ManyToMany关系问题在保存后不会更新

我遇到了ManytoMany Relationships问题,当我保存模型(通过pipe理员)时,在模型中没有更新,尝试在附加到post_save信号的函数内或关联的AdminModelsave_model内使用新值。 我试图重新加载这些函数中的对象,通过使用与ID ..的function,但它仍然有旧值。

这是交易问题吗? 交易结束时是否有信号出现?

谢谢,

当您通过pipe理员表单保存模型时,它不是一个primefaces事务。 主对象首先被保存(以确保它具有PK),然后清除 M2M并将新值设置为从表格中出来的任何值。 所以,如果你在主要对象的save()中,那么你就处于M2M尚未更新的机会窗口中。 事实上,如果你试图对M2M做些什么,这个改变将被clear()消灭。 大约一年前我遇到过这个问题。

代码已经从前ORM重构date有所改变,但它归结为django.db.models.fields.ManyRelatedObjectsDescriptorReverseManyRelatedObjectsDescriptor代码。 看看他们的__set __()方法,你会看到manager.clear(); manager.add(*value) manager.clear(); manager.add(*value) clear()完成清除表中当前主对象的任何M2M引用。 add()然后设置新的值。

所以要回答你的问题:是的,这是一个交易问题。

交易结束时是否有信号出现? 没有官方的,但阅读:

几个月前有一个相关的线程 ,MonkeyPatching是一种方法提出。 Grégoire为此发布了一个MonkeyPatch 。 我没有尝试过,但它看起来应该工作。

我有一个通用的解决scheme,看起来比猴子修补核心,甚至使用芹菜(虽然我敢肯定有人可以find失败的地方)一点点。 基本上我添加一个干净的()方法在具有m2m关系的表单的pipe理,并将实例关系设置为cleared_data版本。 这使得实例的保存方法可以使用正确的数据,即使它不是“书本”。 尝试一下,看看它是如何发展的:

 def clean(self, *args, **kwargs): # ... actual cleaning here # then find the m2m fields and copy from cleaned_data to the instance for f in self.instance._meta.get_all_field_names(): if f in self.cleaned_data: field = self.instance._meta.get_field_by_name(f)[0] if isinstance(field, ManyToManyField): setattr(self.instance,f,self.cleaned_data[f]) 

http://gterzian.github.io/Django-Cookbook/signals/2013/09/07/manipulating-m2m-with-signals.html

问题:在post或pre_save信号接收器中操作模型的m2m时,在Django随后的“清除”m2m中,您的更改将被消除。

解决scheme:在post或pre_save信号处理程序中,将另一个处理程序注册到要更新其m2m的模型的m2m中介模型上的m2m_changed信号。

请注意,这第二个处理程序将收到几个m2m_changed信号,这是testing与它们一起传递的“action”参数的值的关键。

在第二个处理程序中,检查“post_clear”操作。 当你用post_clear动作收到一个信号时,这个m2m已经被Django清除了,你有机会成功的操作它。

一个例子:

 def save_handler(sender, instance, *args, **kwargs): m2m_changed.connect(m2m_handler, sender=sender.m2mfield.through, weak=False) def m2m_handler(sender, instance, action, *args, **kwargs): if action =='post_clear': succesfully_manipulate_m2m(instance) pre_save.connect(save_handler, sender=YouModel, weak=False) 

请参阅https://docs.djangoproject.com/en/1.5/ref/signals/#m2m-changed

当您尝试访问模型的post_save信号中的ManyToMany字段时,相关对象已被删除,直到信号完成后才会再次添加。

要访问这些数据,你必须绑定到你的ModelAdmin的save_related方法。 不幸的是,您还必须在post_save信号中包含需要定制的非pipe理请求中的代码。

请参阅: https : //docs.djangoproject.com/en/1.7/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_related

例:

 # admin.py Class GroupAdmin(admin.ModelAdmin): ... def save_related(self, request, form, formsets, change): super(GroupAdmin, self).save_related(request, form, formsets, change) # do something with the manytomany data from the admin form.instance.users.add(some_user) 

然后在您的信号中,您可以进行与保存时执行相同的更改:

 # signals.py @receiver(post_save, sender=Group) def group_post_save(sender, instance, created, **kwargs): # do somethign with the manytomany data from non-admin instance.users.add(some_user) # note that instance.users.all() will be empty from the admin: [] 

没有猴子补丁的另一种方法是使用芹菜 ,你可以使一个任务,将访问M2M关系正确的数据,这是因为任务运行asynchronous,如果你延迟30秒,aproxim,你一定会交易已经结束。

您必须在post_savepre_save信号中调用Task.apply_async(args=[...], countdown=30)

你可以在这个线程中find更多的信息: Django manytomany信号?