m2m_changed信号通过——保存与多对多



我有这两个基本模型,

class Product(models.Model):
title = models.CharField(max_length=40)
description = models.TextField(blank=True)
price = models.DecimalField(decimal_places=2, max_digits=7, default=0)
...

class Cart(models.Model):
user = models.ForeignKey(
User, null=True, blank=True, on_delete=models.CASCADE)
products = models.ManyToManyField(
Product, blank=True, through='CartItem')
total = models.DecimalField(default=0.00, max_digits=7, decimal_places=2)
def recalculate_and_save(self):
print("recalculate_and_save running")
total = 0
for ci in self.cartitem_set.all():
total += ci.product.price*ci.quantity
self.total = total
self.save()

,以及上面的多对多关系的助手模型,以说明数量:

class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.SmallIntegerField(default=1)

我想实现的是每次添加或删除商品时自动计算购物车的总数。

@receiver(m2m_changed, sender=CartItem)
def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
print(f"m2m_changed received; action={action}, instance={instance}")
instance.recalculate_and_save()

然后我意识到,在日志中看到pre_save和postrongave动作,我可能做了一些错误的事情-在从父母的保存调用(两次)的函数中调用save,按照文档。第一个问题是,为什么它没有把我送入一个无限循环?第二个(可能更重要)—为什么我只看到接收函数在从购物车中删除商品时执行,而不是在添加商品时执行?删除是通过

cart.products.remove (product_obj)

,但通过

添加

cart_obj.cartitem_set。添加(cart_item_obj散装= False)

,这可能与为什么删除会触发接收者,而添加不会有关。但这使问题更加复杂——将发送方设置为CartItem,我希望在产品上执行的删除会错过接收方,而不是直接对CartItem起作用的添加(尽管通过on_delete=CASCADE删除产品也会删除CartItem)。

修改ManyToManyField(本例中为products)时触发m2m_changed信号

来自docs:

Sent when a ManyToManyField is changed on a model instance

对于你的问题:


为什么它不让我进入无限循环?

这是因为recalculate_and_save没有对m2m字段products做任何事情,所以它不会再次触发m2m_changed信号,避免了无限循环。


为什么我只看到接收函数在从购物车中删除商品时执行,而不是在添加商品时执行?

由于信号只来自于修改products时,所以对cartitem_set进行操作不会触发它。

所以你需要在修改cartitem_set后手动调用recalculate_and_save:

cart_obj.cartitem_set.add(cart_item_obj, bulk=False)
cart_obj.recalculate_and_save()

相关内容

  • 没有找到相关文章

最新更新