【问题标题】:Django model form saves m2m after instanceDjango模型表单在实例后保存m2m
【发布时间】:2017-01-13 11:11:35
【问题描述】:

我对 Django 基于类的表单保存表单的方式有疑问。我正在为我的一个模型使用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()方法保存表单,属于BaseModelForm类。然后这个方法返回save_instanceforms\models.py中的一个函数。该函数定义了一个本地函数save_m2m(),它将多对多关系保存在一个表单中。

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

instance.save()
save_m2m()

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

我能做些什么呢?我不能只更改 save_instance 函数中的顺序,因为它是 Django 的一部分,我可能会破坏其他内容。

【问题讨论】:

    标签: python django python-2.7 django-1.4


    【解决方案1】:

    丹尼尔的回答给出了这种行为的原因,你将无法修复它。

    但是,只要 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 说该实例“可以是发送者的实例,或者是与 ManyToManyField 相关的类的实例”。

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

    【讨论】:

    • 那么文档所说的基本上是,如果MyModel 和它相关的模型实例在现有关联中进行更改时都会触发信号?
    • 是的,两者之间有一个不可见的表,即 MyModel.m2m_relationship.through,如果发生变化,则无论发生什么情况,都会发送信号。我不知道发送的是哪个实例,您需要尝试一下。
    • 好吧,这真的没关系,因为只有 MyModel 会改变它。如果是另一个,我想我仍然会应用 m2m 更改操作。
    • 应该是接收者,但是 .through 应该可以工作。
    • 好吧,这是我的 IDE 遇到的一个荒谬的错误。它坚持应该是though 而不是through...
    【解决方案2】:

    但其他任何方式都无法做到。

    多对多关系不是实例上的字段,而是链接表中的条目。在实例本身存在之前无法保存该关系,因为它没有 ID 可以输入到该链接表中。

    【讨论】:

    • 那我该怎么办?一些保存后的操作来根据 m2m 修改我想要的内容?
    猜你喜欢
    • 1970-01-01
    • 2014-09-21
    • 2011-03-05
    • 1970-01-01
    • 2022-01-24
    • 2020-03-30
    • 2011-05-09
    • 2018-11-25
    • 2014-01-13
    相关资源
    最近更新 更多