我想自动更新一个关于模型更改的外部应用程序。问题是数据在事件之间存在许多关系<->用户。我试着使用"m2m_changed"信号。
@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
这个问题是,如果我做了一个单一的更改,删除了一个用户并添加了另一个用户,那么这个代码会被调用两次这不好,我不能只忽略一种类型的操作,以防只调用该操作。我曾想过将实例推到堆栈中并忽略dup,但这似乎很混乱。有没有一种方法可以让我自己发出只响一次的信号?
m2m_changed
表示ManyToMany模型的变化。如果有4个动作
- pre_add
- post_add
- 预移动
- 移动后
因此,如果您只是添加一个用户,这个m2m_changed方法将被触发两次,分别针对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文档:https://docs.djangoproject.com/en/2.2/ref/signals/#m2m-已更改
这个问题似乎没有一个好的答案,所以这里有一些有用的解决方案,比我最初想象的要好。
解决方案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()之间的所有事件。将上次调用的内容存储到磁盘/数据库的某个位置,以避免在重新启动时重新发送所有内容。