Python 编辑多个字段时避免Django中的重复信号

Python 编辑多个字段时避免Django中的重复信号,python,django,django-models,django-signals,Python,Django,Django Models,Django Signals,我希望自动更新外部应用程序有关模型中的更改。问题在于,数据在事件和用户之间存在许多关系。我试着用这个 问题是,如果我只做了一次更改,删除一个用户并添加另一个用户,那么该代码将被调用两次这不好,我不能忽略一种类型的操作,以防只调用该操作。我曾想过将实例推到堆栈中并忽略DUP,但这看起来很混乱。有没有办法让我自己发出一次信号 这个问题似乎没有一个好的答案,所以这里有一些有用的解决方法,比我在第一步中想象的要好 解决方案1: 不要组合信号,而是将实例的主键添加到集合中以忽略重复信号: updated

我希望自动更新外部应用程序有关模型中的更改。问题在于,数据在事件和用户之间存在许多关系。我试着用这个


问题是,如果我只做了一次更改,删除一个用户并添加另一个用户,那么该代码将被调用两次这不好,我不能忽略一种类型的操作,以防只调用该操作。我曾想过将实例推到堆栈中并忽略DUP,但这看起来很混乱。有没有办法让我自己发出一次信号

这个问题似乎没有一个好的答案,所以这里有一些有用的解决方法,比我在第一步中想象的要好

解决方案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()之间的所有事件。将上次调用的内容存储到磁盘/数据库的某个位置,以避免在重新启动时重新发送所有内容。

Django
m2m\u changed
表示许多型号的更改。如果有4个动作

  • 预加
  • 后加
  • 预移除
  • 后置移除
  • 因此,如果您只是添加一个用户,此m2m_更改方法将被触发2次,分别用于
    pre_add
    post_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 Docs:

    难道你不能让你的代码幂等,这样调用两次就不会有什么坏处吗?@LorenzoPeña那么确保有变化的唯一方法就是询问前面提到的api。使用api作为内部函数肯定会增加一些代码负担。如果你有一个聪明的方法,我可以让它在不发送2个帖子的情况下被调用两次,我洗耳恭听:)试试@LorenzoPeña中描述的
    dispatch_uid
    方法,我试过了,但这似乎只解决了信号连接器运行多次的问题。你能负担得起Django 1.9吗,那里有一个相关的方法
    set()
    这是一个完整的解决方案吗?
        @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