Should I use django Signals in this case?

Hi everyone

First of all, I would like to say English is not my first language so if it feels confusing please ask me to rephrase. I’m a beginner, I discover many things and sometimes I feel overwhelmed about all the informations and tricks to learn.

I try to do a django project for a pizzeria. People can order pizza online, the order is simple : you can choose one or more pizza and optionally add some Extras (adding cheese, ham or whatever…) for each pizza you ordered and it’s added to the cart.
My problem is to calculate automatically the price for each pizza.

Basically here’s my Model file:

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 means name

class Extra(models.Model):

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

sup is the name of the extra.

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 is a bit weird. It’s a model which stores each choice, here “panier” means Cart which has a model but I don’t think it’s useful to make it appear here.

I learned a bit about django signals, so I tried to create one:

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)

It works well when I create a pizza with extra but if only change the pizza the m2m signal won’t be fired.
So I tried to find another solution but it’s stupid:

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):
print(action)
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)

The second solution works well when I want to modify a choice but when I create a new pizza I have this error message “maximum recursion depth exceeded while calling a Python object”. And I think it’s because i’m looping over something not saved.

I’m completely stuck with this problem, I tried to solve it for several days. Should I create a Signal, is a signal is appropriate for this kind of problem ?
(What a loooong way to be a web developer…)

Thanks for reading !

Signals were not so adequate. I asked for help on Stackoverflow and someone advise me to use @property.

Here the solution

Thanks for your attention.