在Django中使用ManyToMany插入对象 [英] Inserting object with ManyToMany in Django

查看:142
本文介绍了在Django中使用ManyToMany插入对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似博客的应用程序,包含故事和类别:

 类类别(models.Model):
...
class Story(models.Model):
categories = models.ManyToManyField(Category)
...

现在我知道当您保存一个具有多对多字段的模型的新实例时,会出现问题,因为该对象尚未在数据库中。这个问题通常表现在表单提交上,可以使用 story_form.save(commit = False)来整理。一个没有形式说话的情况呢?在我的情况下,我想构建一个API来接受远程提交。因为我喜欢JSON,而且我们公司的很多其他消息都是JSON(包括来自这个服务器的传出消息),我希望能够收到以下内容:

  {operation:INSERT,
values:[
{datatype:story,
:[4,6,8],
id:50,
...
}
]
}

并实现将值转换为实例的工厂。但是我希望工厂尽可能地不了解操作的类型。所以:

  {operation:UPDATE,
values:[
{数据类型:故事,
类别:[4,6,8],
id:50,
...
}
]
}

也应该以相同的方式进行转换,除了INSERT忽略id和UPDATE获取已存在的实例并覆盖它。 (远程提交者监听一个给定它的源,其中包括要缓存的类别对象,因此它可以并且必须通过id引用它们,但它不与数据库进行任何直接的通信。) / p>

我真正的问题是:最简单的一致方法是充实一个涉及到ManyToManyManager的Django模型对象的实例。据我所知,任何插入多对多字段的对象将需要两个数据库命中,因为必须先获取一个新的id。但是我目前的尴尬的解决方案是立即保存对象,并将其标记为隐藏,以便下线功能可以与其一起玩,并将其保存为更有意义的东西。似乎一个步骤将覆盖保存,以便没有ids的对象保存一次,将一些代理字段复制到类别 ,然后再保存。最重要的是一些强大的经理对象,可以帮助我解决问题。你推荐什么?

解决方案

我评论S.Lott的帖子,认为他的答案是最好的。他是对的:如果目标只是为了避免两个数据库命中,那么你只是一个不必要的痛苦的世界。



阅读你对ModelForm的引用,如果您正在寻找解决方案,您可以以某种方式推迟官方保存,您可能希望看看<$ c中的 save_instance()函数$ C> forms.models 。内部函数 save_m2m 是如何为表单完成延迟的多对多保存。对于没有表单的模型,实现一些基本上遵循相同的原则。



说完了,再回到S.Lott的帖子,一个ModelForm和一个实际的模型有些不同。因为表单只能在浏览器中显示一组安全的数据(安全,因为它以某种方式被过滤,或排除了用户不应该编辑的关键字段),这是合理的设计期望有人可能需要在保存前向表单派生模型添加重要信息。这就是为什么django有 commit = False



对于直接实例化模型的情况,这个期望会下降。在这里,您可以对模型API进行编程访问,因此您可能会发现直接使用该API更容易维护,而不是通过广义间接更容易出错。我可以理解你为什么要画出工厂的概念,但是在这种情况下,您可能会发现为各种模式创建一个防弹型泛化的努力是一件并不重要的事情。


I have a blog-like application with stories and categories:

class Category(models.Model):
    ...
class Story(models.Model):
    categories = models.ManyToManyField(Category)
    ...

Now I know that when you save a new instance of a model with a many-to-many field, problems come up because the object is not yet in the database. This problem usually manifests itself on form submission, which can be neatly worked around with story_form.save(commit=False). What about a situation where there are no forms to speak of? In my case, I want to build an API to accept remote submissions. Since I like JSON, and a whole lot of other messaging in our company is in JSON (including outgoing messages from this server), I'd like to be able to receive the following:

{ "operation": "INSERT",
  "values": [
            { "datatype": "story",
              "categories": [4,6,8],
              "id":50,
              ...
            }
            ]
}

and implement a factory that converts the values to instances. But I'd like the factory to be as agnostic as possible to the type of operation. So:

{ "operation": "UPDATE",
  "values": [
            { "datatype": "story",
              "categories": [4,6,8],
              "id":50,
              ...
            }
            ]
}

should also be converted in the same way, except that INSERT ignores id and UPDATE gets the already existing instance and overrides it. (The remote submitter listens to a feed that gives it, among other things, the category objects to cache, so it can, and must, refer to them by id, but it doesn't have any direct communication with the database.)

My real question is: what's the most easiest consistent to inflate an instance of a Django model object that has a ManyToManyManager involved. As far as I can fathom, any insert of an object with a many-to-many field will require two database hits, just because it is necessary to obtain a new id first. But my current awkward solution is to save the object right away and mark it hidden, so that functions down the line can play with it and save it as something a little more meaningful. It seems like one step up would be overriding save so that objects without ids save once, copy some proxy field to categories, then save again. Best of all would be some robust manager object that saves me the trouble. What do you recommend?

解决方案

I commented on S.Lott's post that I feel his answer is the best. He's right: if the goal is just to avoid two database hits, then you're just in for a world of unnecessary pain.

Reading your reference to ModelForm, however, if you are looking instead for a solution to that allows you to defer official saving in some way, you may wish to have a look at the save_instance() function in forms.models. The inner function save_m2m is how the delayed many-to-many save is accomplished for forms. Implementing something for models without forms would basically follow the same principle.

Having said that, and coming back to S.Lott's post, the case of a ModelForm and an actual Model are somewhat different. Because forms expose only a "safe" set of data to be edited in a browser ("safe" because it is filtered in some way, or excludes critical fields that a user shouldn't be editing), it is a reasonable design expectation that someone might need to add important information to the form-derived model before saving. This is why django has the commit=False.

This expectation falls down for cases where you are directly instantiating models. Here you have programmatic access to the model API, so you will probably find that using that API directly is easier to maintain and less error prone than through generalized indirection. I can understand why you are picturing the factory concept, but in this case you may find the effort to create a bullet-proof generalization for all manner of models is a complication that's just not worth it.

这篇关于在Django中使用ManyToMany插入对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆