我遇到了一个奇怪的问题,我希望这里的某些人能够对此有所了解。
我正在覆盖模型的save()方法,以便在运行super()之后向ManyToMany字段添加一些值。我的问题是,当我在Django admin中保存时,值似乎会被添加到关系中,但之后会再次为空。
但是,如果我从manage.py shell
这样做,它可以毫无问题地工作。
我在那里放了两个打印语句,无论我是通过Django admin还是通过shell运行它们,它们都会产生完全相同的输出。
class Store(models.Model):
holidays = models.ManyToManyField(StoreHoliday, blank=True)
copy_holidays_from = models.ForeignKey('Store', blank=True, null=True)
def save(self):
print '==== BEFORE SAVE:', self.holidays.all()
super(Store, self).save()
self.copy_holidays()
print '==== AFTER SAVE:', self.holidays.all()
def copy_holidays(self):
if self.pk and self.copy_holidays_from:
self.holidays.clear()
for h in self.copy_holidays_from.holidays.all():
self.holidays.add( h )
这是print
语句的输出:
==== BEFORE SAVE: []
==== AFTER SAVE: [<StoreHoliday: 10 Mar 2010, Chuck Norris birthday (Closed)>]
有没有人对可能导致这种情况的原因有任何建议?
编辑:当通过管理界面保存时,Django似乎会丢弃save()中对m2m关系的所有手动更改。这与处理表单的方式有关吗?
答案 0 :(得分:12)
事实证明,上述不是实现它的正确方法。该代码属于StoreAdmin,通过覆盖model_save()。
这就是我解决它的方法:
class StoreAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if obj.copy_holidays_from:
form.cleaned_data['holidays'] = obj.copy_holidays_from.holidays.all()
super(StoreAdmin, self).save_model(request, obj, form, change)
答案 1 :(得分:3)
我今天可能遇到了同样的行为,是的,你认为它与django处理数据的方式有关是正确的。
django admin对ManyToMany字段的更改与更改实际对象分开。 (请记住,m2m保存在不同的数据库表中。)
在我的情况下,如果我没有在管理站点的ManyToMany字段中选择任何内容,这将转换为对ManyToMany关系的clear()操作。您在save()方法中执行的所有操作都会立即被删除。我在post_save信号处理程序中做的事情也一样。
解决方案(对我来说)是将ManyToMany字段分隔为内联,因此在修改对象时它不会自动保存为空。
答案 2 :(得分:1)
在django 2,1,4中,我的解决方案是使用save_related()
def save_related(self, request, form, formsets, change):
super().save_related(request, form, formsets, change)
form.instance.permissions.add(request.user)
答案 3 :(得分:0)
对我来说,管理员只保存了许多字段的最后一个选定实例(选择了最后一个'假日')的问题。所以我必须覆盖save_model方法,例如:
@admin.register(Store)
class StoreAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
form.cleaned_data['holidays'] = StoreHoliday.objects.filter(pk__in=dict(request.POST).get('holidays'))
super(StoreAdmin, self).save_model(request, obj, form, change)
我花了很多时间在上面,其他解决方案都没有用,所以我希望它会有所帮助。
答案 4 :(得分:0)
一种更新m2m的解决方案,以及更新您的一个模型。
Django 1.11 and higher
在更新过程中可以观察到的行为,即使没有使用模型或信号之一的保存方法保存对m2m记录所做的更改,也仅由于m2m格式重写了所有记录,所以即使未保存这些更改在更新主要对象之后。
这就是为什么要逐步进行:
主要对象已更新。
您的代码(在保存方法或信号中)进行了更改(您可以 看看它们,只需在ModelAdmin中放置一个断点):
def save_related(self, request, form, formsets, change): breakpoint() form.save_m2m() for formset in formsets: self.save_formset(request, form, formset, change=change)
有一个解决方案:通过m2m进行更改 transaction.on_commit。 transaction.on_commit将进行您的更改 提交事务后,在form.save_m2m()之后。
不幸的是,此解决方案的缺点-您使用m2m进行的更改将在单独的事务中执行。