编辑 many_to_many 字段时避免 Django 中的重复信号

Avoiding duplicate signals in Django when editing many_to_many fields

我想自动更新有关模型更改的外部应用程序。问题是数据在事件 <-> 用户之间处于多对多关系。我尝试使用"m2m_changed" signal

@receiver(m2m_changed, sender=models.Event.organisers.through)
def event_changed(sender, instance, action, *args, **kwargs):
    if "post" in action:
      # hey api here is the new list of organisers of this

这个问题是,如果我在删除一个用户并添加另一个用户的地方进行一次更改,那么这段代码将被调用两次!那不好,我不能如果仅调用该操作,则忽略一种类型的操作。我曾想过将实例推入堆栈并忽略重复项,但这看起来很乱。有没有办法让我自己的信号只触发一次?

中继似乎无法很好地回答这个问题,所以这里有一些有用的解决方法,比我最初想象的要好。

解决方案 1:

不是组合信号,而是将实例的主键添加到集合中以忽略重复信号:

updated = set()

@receiver(m2m_changed, sender=models.Event.organisers.through) 
def event_changed(sender, instance, action, *args, **kwargs):
        if "post" in action:
          updated.add(instance.pk)

def send_updates():
    for Event in updated:              # Iteration AKA for each element
       #update code here

虽然这需要对 运行 send_updates() 进行某种计划任务,但如果事件有许多连续更改,它可以避免发送垃圾邮件的机会。

解决方案 2

完全忽略信号将上次修改添加到模型中。然后 运行 查询以获取从现在到上次调用 send_updates() 之间的所有事件。将最后一次调用存储到 disk/database 以避免在重新启动时重新发送所有内容。

Django m2m_changed 表示对 ManyToMany 模型的更改。如果有 4 个动作

  1. pre_add
  2. post_add
  3. pre_remove
  4. post_remove

因此,如果您只是添加用户,此 m2m_changed 方法将被触发 2 次,分别为 pre_addpost_add

您可以指定要调用的操作 API。可以这样做:

    @receiver(m2m_changed, sender=models.Event.organisers.through)
    def event_changed(sender, instance, action, *args, **kwargs):
    if kwargs.get('action') == 'pre_add': # Or whatever action you want
       # Call your API here

参考 Django 文档:https://docs.djangoproject.com/en/2.2/ref/signals/#m2m-changed