0

I have this code in my views.py:

from django.shortcuts import render
from .helpers import *
from .forms import OrderForm

def create_order(request):
    if request.method == 'POST':
        form = OrderForm(request.POST)
        if not request.POST._mutable:
            request.POST._mutable = True
        
        if form.is_valid():
            obj = form.save(commit=False)
            obj.total_price = calculate_total_price_obj(obj)
            obj.save()
    else:
        form = OrderForm()
    return render(request, 'create_order.html', {'form': form})

I have this in my helpers.py:

def calculate_total_price_obj(obj) -> float:
        """
        Calculate the total_price of the order.
        This function has to be called after the Order has been created and saved.
        """
        prices_of_ordered_foods = obj.ordered_foods
        print(prices_of_ordered_foods)
        return sum(prices_of_ordered_foods)

What I'm trying to achieve is:

  1. Get the form the user sent.
  2. Calculate field total_price based on the prices of chosen meals/foods by the user when he was filling up the forms (this is a ManyToManyField in my models.py). After calculation is performed, save the form. (Calculation is a simple sum() method.)

However, this does not work. I am getting this error: <MyOrderObject> needs to have a value for field "id" before this many-to-many relationship can be used.

Any ideas how to fix it?

Thank you

neisor
  • 384
  • 4
  • 15
  • You object doesn't have id yet. Instead of that you may do it in post_save or override create method – Bartosz Karwacki Aug 31 '21 at 09:39
  • Could you please elaborate a bit more on this? I'm not sure what to do based on your answer. Thank you – neisor Aug 31 '21 at 09:42
  • https://docs.djangoproject.com/en/3.2/ref/signals/#post-save https://stackoverflow.com/questions/2307943/django-overriding-the-model-create-method – Bartosz Karwacki Aug 31 '21 at 09:44
  • You need to save `obj` first before using m2m fields – Brian Destura Aug 31 '21 at 10:55
  • @BartoszKarwacki I have tried what you suggested but it seems that in the `post_save` signal the ManyToManyField is not yet populated (meaning, the foreign model is not yet assigned to the model where I have created the `post_save` method.) – neisor Aug 31 '21 at 11:53

1 Answers1

0

You can' t use a post_save signal sent by Order.save to calculate total_price, because only after save method is called many-to-many relationships are set. So you need to save the Order instance, assign meals/food and only then call calculate_total_price_obj.

def create_order(request):
    if request.method == 'POST':
        form = OrderForm(request.POST)
        if not request.POST._mutable:
            request.POST._mutable = True
        
        if form.is_valid():
            obj = form.save(commit=True)
            # Note that you must set many-to-many relationships before calling calculate_total_price_obj
            obj.total_price = calculate_total_price_obj(obj)
            obj.save()
    else:
        form = OrderForm()
    return render(request, 'create_order.html', {'form': form})
Alain Bianchini
  • 3,883
  • 1
  • 7
  • 27