dar*_*rse 1 django many-to-many django-models django-orm
我的项目中有以下模型:
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)
Run Code Online (Sandbox Code Playgroud)
基本上,每当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)
Run Code Online (Sandbox Code Playgroud)
现在,我想将这两种配料添加到我的披萨中。我使用以下代码执行此操作:
pizza = Pizza.objects.get(pk=1)
pizza.toppings.set([1, 2])
Run Code Online (Sandbox Code Playgroud)
配料设置正确,但是,披萨的 save 方法被调用两次,因为 m2m_changed 信号被调用两次,因为发生了两次更改。在提交所有更改后,如何才能仅调用一次?为了澄清,我希望添加两种配料,但我只想在所有更改结束时触发一次信号。谢谢你的帮助。
该m2m_changed信号有点奇怪,因为它被调用了两次:一次使用 的操作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()
Run Code Online (Sandbox Code Playgroud)
在这里,instance.save()无论您传递给 的参数有多少,都应该只调用一次set()。m2m_changed.connect(...)请注意,如果您使用接收器装饰器,则不需要执行此操作。
上述内容也适用于pre/post_remove和pre/post_clear,因此如果您想在删除后打印列表,则需要添加更多逻辑来检查 if action == "post_remove"。
最后,以防万一您不知道,set([1, 2])将用您提供的两种配料(和)替换所有配料。如果您只是想在现有的套餐中添加配料,我会使用.pk=1pk=2add(1, 2)
希望这可以帮助!