Django,通过具有多个 ManyToManyField 的模型处理 m2m 更改信号

问题描述 投票:0回答:3

我有一个模型 M 包含三个manytomanyfields(a,b,c)到 django 中的三个不同模型。

    class M (models.Model):
           name = models.CharField()
           a = models.ManyToManyField(A)
           b = models.ManyToManyField(B)
           c = models.ManyToManyField(C)

现在,我想处理模型 M 上的任何更改,并相应地向 url 发送 HttpRequest。 正如你所知,在模型 M 的保存后信号中,a、b 和 c 的属性值尚未设置,因为它们将在保存模型 M 完成时设置。(ManyToManyField 的规则)

我为我的模型编写了一个处理程序来处理任何更改(创建新实例或更新一个或多个字段)

    @receiver(post_save, sender=M)
    @receiver(m2m_changed, sender=M.a.through)
    @receiver(m2m_changed, sender=M.b.through)
    @receiver(m2m_changed, sender=M.c.through)
    def M_changes_handler(sender, **kwargs):
          is_instance_set_compeletly(kwargs['instance']):
              #send_and_HttpRequest(url, data = instance)


    def is_instance_set_compeletly(kwargs['instance']):
          if M.a.all() is not None and M.b.all() is not None and 
              M.c.all()is not None
             flag = True
          else:
             flag = False
          return flag

现在考虑模型 M 上的更新请求(更改所有字段)将为所有字段 a、b 和 c 发送信号;因此,三个 httpRequest 将使用三个不同版本的实例发送给我的发件人!另一方面,当用户仅更改模型 M 的字段(例如 b)时,此函数将仅发送一个 httpRequest。

我想动态处理这个问题,并且只需在我的模型 M 上针对任何类型的更改发送一个请求。 我想知道是否有人可以帮助我:)

*请注意,上面的代码只是一个草稿,可能包含语法错误,因此请忽略它们;)

更新:我的问题解决了! 保存包含 m2mfields 的模型的过程很有趣! 首先,M 的字段不是 m2m 字段类型,例如是否在调用 post_save 之前设置了字符字段、外键等。所以在 post_save 中它们的值被更新 尽管在模型保存完成之前不会设置 m2mfields。然后调用 m2mchange 信号来设置 m2mfields 拥有模型更新版本的唯一方法是覆盖 admin.py 中的表单保存,因为在完成所有 m2mfields 设置后将调用“表单保存”

django-models django-signals m2m
3个回答
1
投票

解决方案: 对于所有 stack-overflow 用户和亲爱的 Blake Gibbs 如果一个模型包含很多字段,并且您想要访问已保存记录的所有数据,则无法访问这些 m2m 字段,因为它们将在完成保存模型的过程后保存(在我的示例中考虑 M),然后将该 Id 分配给其他自行创建的 m2m 表将该 Id 绑定到 m2m 字段(例如我的示例中的 A)。因此,在这种情况下,重写 admin.py 中模型的保存方法不起作用。 我只是在 Forms.py 中重写表单的保存功能

类 MForm(forms.ModelForm):

class Meta:
        model = M          
        exclude = []
def save(self, commit=True):
    query = ""
    old_instance = super(MForm, self).save(commit=False)# if you need the old instance

#否则返回 super(MForm, self).save(commit=True)

    instance = super(MForm,self).save(commit=True)

在这种情况下,“实例”确实被完全保存,您可以使用“.all()”访问 m2m 字段

希望有帮助!


0
投票

您可以保存 M 的先前实例,并在 post_save 中使用新的 M 检查字段已根据您可以发送请求而更改。


0
投票

一般来说:在 m2m 字段或 backwords forignKey 的情况下,不建议在 django 中使用信号处理更改,这是因为:
通过多对多 - 无论是表更改,数据库中发生更改的表都是保存连接两个表的 pk 的表。
通过backwords forignKey - 外键只能与创建的实例相关,而不是尚未在数据库中的实例,并且仅在保存发生时才会进入数据库。
如果您仍然想使用信号,为了防止调用两次更改函数,您可以使用

dispatch_uid
,并在 apps.py 的 for 循环中将信号连接到模型,这可能是一个更简单的解决方案,然后覆盖“表单”保存”在
admin.py

© www.soinside.com 2019 - 2024. All rights reserved.