die*_*us9 22 django django-signals django-orm django-admin
我遇到了ManytoMany关系的问题,当我保存它时(通过管理员)并没有在模型中更新,并尝试在附加到post_save
信号的函数中或在save_model
关联的函数内使用新值AdminModel
.我试图通过使用带有id的get函数重新加载这些函数中的对象但它仍然具有旧值.
这是交易问题吗?交易结束时是否抛出信号?
谢谢,
Pet*_*ell 28
当您通过管理表单保存模型时,它不是原子事务.首先保存主对象(以确保它具有PK),然后清除 M2M 并将新值设置为表单中出现的任何值.因此,如果您在主对象的save()中,那么您将处于尚未更新M2M的机会窗口中.实际上,如果您尝试对M2M执行某些操作,则clear()将会消除此更改.我大约一年前遇到过这个问题.
代码在ORM之前的重构日有所改变,但归结为代码django.db.models.fields.ManyRelatedObjectsDescriptor
和ReverseManyRelatedObjectsDescriptor
.查看它们的__set __()方法,您将看到manager.clear(); manager.add(*value)
clear()完成清除该表中当前主对象的任何M2M引用.然后add()设置新值.
所以回答你的问题:是的,这是一个交易问题.
交易结束时是否抛出信号?没有官方的,但请继续阅读:
几个月前有一个相关的线程,MonkeyPatching是一种提出的方法.Grégoire为此发布了一个MonkeyPatch.我没试过,但它看起来应该有用.
当您尝试访问模型的post_save信号中的ManyToMany字段时,相关对象已被删除,并且在信号完成之前不会再次添加.
要访问此数据,您必须绑定到ModelAdmin中的save_related方法.不幸的是,您还必须在post_save信号中包含需要自定义的非管理员请求的代码.
请参阅: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)
Run Code Online (Sandbox Code Playgroud)
然后在您的信号中,您可以进行与保存时要执行的相同更改:
# 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: []
Run Code Online (Sandbox Code Playgroud)
小智 5
我有一个通用的解决方案似乎比猴子修补核心甚至使用芹菜更清洁(虽然我确信有人可以找到它失败的区域).基本上我在admin中为具有m2m关系的表单添加了一个clean()方法,并将实例关系设置为cleaning_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])
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10853 次 |
最近记录: |