在这种情况下我应该使用 django Signals 吗?

Should I use django Signals in this case?

我是初学者,我发现了很多东西,但有时我对要学习的所有信息和技巧感到不知所措。

我尝试为一家比萨店做一个 django 项目。人们可以在线订购比萨饼,订单很简单:您可以选择一个或多个比萨饼,并可选择为您订购的每个比萨饼添加一些额外的东西(添加奶酪、火腿或其他……)并将其添加到购物车。

我的问题是自动计算每个披萨的价格。

基本上这是我的模型文件:

class Pizza(models.Model):

    nom = models.CharField(max_length=30)
    ingrédients = models.CharField(max_length=500)
    prix = models.DecimalField(max_digits=4, decimal_places=2)

nom 表示名称

class Extra(models.Model):

    sup = models.CharField(max_length=30)
    prix = models.DecimalField(max_digits=3, decimal_places=2)

sup 是额外的名称。

class IndividualChoice(models.Model):

    pizzaChosen = models.ForeignKey(‘Pizza’, default="", null=True, on_delete=models.CASCADE)
    extraChosen = models.ManyToManyField(‘Extra’, blank=True)
    panier = models.ForeignKey(‘Cart’, default="", on_delete=models.CASCADE)
    calzone = models.BooleanField(default=False)
    prix = models.DecimalField(max_digits=5, decimal_places=2, default=0)

IndividualChoice 有点奇怪。它是一个存储每个选择的模型,这里的“panier”是指有一个模型的购物车,但我认为让它出现在这里没有用。

我了解了一些关于 django 信号的知识,所以我尝试创建一个:

def prix_extra_calcul(sender, instance, action, *args, **kwargs):
    instance.prix = 0
    if action == “post_add” or action == “post_remove” or action == “post_clear”:
        for extra in instance.extraChosen.all():
            instance.prix += extra.prix
        instance.prix += instance.pizzaChosen.prix
        instance.save()

m2m_changed.connect(prix_extra_calcul, sender=IndividualChoice.extraChosen.through)

当我用额外的东西制作比萨饼时效果很好,但如果只改变比萨饼,则不会触发 m2m 信号。 所以我试图找到另一个解决方案,但它很愚蠢:

def prix_pizza_calcul(sender, instance, *args, **kwargs):
    instance.prix = 0
    for extra in instance.extraChosen.all():
        instance.prix += extra.prix
    instance.prix += instance.pizzaChosen.prix

def prix_extra_calcul(sender, instance, action, *args, **kwargs):
    if action == “post_add” or action == “post_remove” or action == “post_clear”:
    # no need to write code because prix_pizza_calcul will be fired by instance.save()
        instance.save()

pre_save.connect(prix_pizza_calcul, sender=IndividualChoice)
m2m_changed.connect(prix_extra_calcul, sender=IndividualChoice.extraChosen.through)

第二个解决方案"works well"当我想修改一个选择但是当我创建一个新的披萨时我有这个错误消息“调用Python对象时超出了最大递归深度”。我认为这是因为我正在循环播放未保存的内容。

我完全被这个问题困住了,我试了好几天才解决。我应该创建一个信号吗?信号是否适合解决此类问题?

(成为一名 Web 开发人员真是太无聊了……)

感谢阅读!

也许你可以尝试使用@receiver 装饰器。 每个 post_save.

都会发出一个信号
from django.dispatch import receiver

@receiver(post_save, sender=IndividualChoice)
def prix_extra_calcul(sender, instance, created, **kwargs):
    ...

我不知道你对数据库规范化的了解,但这里的 IndividualChoice 价格,你是在复制数据:价格只是对已存储数据的计算。如果避免重复数据,就可以避免数据异常。

如果你有名字和姓氏,你会存储 "full name" 吗?如果您的回答是肯定的,请在此处阅读有关@属性 的文档:https://docs.djangoproject.com/en/3.0/topics/db/models/#model-methods

一个解决方案可能是删除 IndividualChoice 模型上的 DecimalField prix 并添加如下内容:

    @property
    def prix(self):
        "Returns the price of the item"
        price = self.pizzaChosen.prix
        for extra in self.extraChosen.all():
            price += extra.prix
        return price