Django模型形式在实例后保存m2m

Django model form saves m2m after instance

我对基于 Django class 的表单保存表单的方式有疑问。我正在为我的一个模型使用 form.ModelForm,它具有一些多对多关系。

在模型的保存方法中,我检查了其中一些关系的值以修改其他属性:

class MyModel(models.Model):
  def save(self, *args, **kwargs):
    if self.m2m_relationship.exists():
      self.some_attribute = False
    super(MyModel, self).save(*args, **kwargs)

即使我在表单的 m2m 关系中填充了一些数据,我 self.m2m_relationship 在保存模型时令人惊讶的是它是空的 QuerySet。我最终发现了以下内容:

调用form.save()方法保存表格,属于BaseModelFormclass。那么这个方法returnssave_instanceforms\models.py中的一个函数。该函数定义了一个局部函数save_m2m(),它以一种形式保存多对多关系。

事情是这样的,检查 save_instance 在保存和实例以及 m2m 时选择的顺序:

instance.save()
save_m2m()

显然问题就在这里。实例的 save 方法首先被调用,这就是为什么 self.m2m_relationship 是一个空的 QuerySet。它只是还不存在。

我该怎么办?我不能只更改 save_instance 函数中的顺序,因为它是 Django 的一部分,我可能会破坏其他东西。

但用其他方式是不可能的。

many-to-many 关系不是实例上的字段,它是链接 table 中的条目。在实例本身存在之前无法保存该关系,因为它没有进入该链接的 ID table.

Daniel 的回答给出了这种行为的原因,您将无法修复它。

但是只要 m2m 关系发生变化,就会发送 m2m_changed 信号,也许您可​​以使用它:

from django.db.models import signals

@signals.receiver(signals.m2m_changed, sender=MyModel.m2m_relationship.through)
def handle_m2m_changed(sender, instance, action, **kwargs):
    if action == 'post_add':
        # Do your check here

但请注意 docs 表示实例 "can be an instance of the sender, or of the class the ManyToManyField is related to"。

我不知道它到底是如何工作的,但你可以尝试一下你得到的,然后调整代码。