我的项目中有以下模型:
class Topping(models.Model):
name = models.CharField(max_length=255)
class Pizza(models.Model):
name = models.CharField(max_length=255)
toppings = models.ManyToManyField(Topping, blank=True)
def save(self, *args, **kwargs):
print('Saving...')
if self.pk:
for topping in self.toppings.all():
print(topping.name)
super(Pizza, self).save(*args, **kwargs)
def toppings_changed(sender, instance, **kwargs):
instance.save()
m2m_changed.connect(toppings_changed, sender=Pizza.toppings.through)
基本上,只要更改toppings
,就会触发信号。信号的全部作用就是调用Pizza
对象的save方法。无论如何,可以说我有三个对象:
pizza = Pizza.objects.get(pk=1) # Number of toppings is 0
topping1 = Topping.objects.get(pk=1)
topping2 = Topping.objects.get(pk=2)
现在,我要为披萨设置两个浇头。我使用以下代码执行此操作:
pizza = Pizza.objects.get(pk=1)
pizza.toppings.set([1, 2])
浇头的设置正确,但是,由于发生了两次更改,因此两次调用了披萨的save方法,因为两次调用了m2m_changed信号。在所有更改都已提交之后,我怎么只能调用一次?为了明确起见,我希望同时添加两个浇头,但是在所有更改结束时,我只希望触发一次信号。感谢您的帮助。
答案 0 :(得分:1)
java.util.Date
信号有点奇怪,它被调用了两次:一次是用toString()
的动作,一次是用m2m_changed
的动作(请参阅docs )。由于您要为任何操作调用pre_add
,它将最终被调用两次,因此post_add
将被调用两次。
您似乎对toppings_changed()
感兴趣,所以我会做类似的事情:
save()
在这里,无论您要传递给post_add
的参数多少,@receiver(m2m_changed, sender=Pizza.toppings.through)
def toppings_changed(sender, instance, action, **kwargs):
if action == "post_add":
instance.save()
都只能被调用一次。请注意,如果您使用接收器装饰器,则无需执行instance.save()
。
以上内容也适用于set()
和m2m_changed.connect(...)
,因此,如果要在删除后打印列表,则需要添加更多逻辑以检查pre/post_remove
是否有效。
最后,以防万一,如果您不知道,pre/post_clear
将用您提供的两个{action == "post_remove"
和set([1, 2])
替换所有浇头。如果您只是想将浇头添加到现有组合中,则可以使用pk=1
。
希望这会有所帮助!