views:

95

answers:

2

I need to perform a range of simple calculations on an Invoice model object, which has a number of Order children associated with it that hold the order quantity and order value etc. This is all managed through the admin form for Invoice (with order as inlines)

The code I'm working with now performs these calcs like this:

Invoice (models.py)

def save():
    #get the total of all associated orders
    for order in self.invoice_orders.all():
    self.invoice_net_total += order.order_value
    super(Invoice, self).save()

Which causes a few problems when changing a child order quantity and then saving the form - I get the previous total instead of the new total, only when I save again does the total correct itself. Perhaps due to the way Django saves parent and child objects?

Other option I toyed with was moving this calculation to the child order object (prepare for horrible code):

Order (models.py)

def save():
  if not self.id:
    self.invoice.invoice_net_total += self.order_value
  elif self.id:
    #grab old instance
    old = Order.objects.get(pk=self.id)
    #remove that old total
    self.invoice.invoice_net_total -= old.order_value
    self.invoice.save()
    #add new total
    self.invoice.invoice_net_value += self.order_value
    self.invoice.save()

Though that's not very effective either.

Wondering if anyone could guide me to a straightforward way of ensuring these calcs perform as they should? Thought of signals (relatively new to me) but wondered if that was overkill. I'm probably overthinking this!

Thank you

A: 

Me thinks you need to explicitly save the child objects before doing the calculation, since your query references the objects as in the database, while any changed object from the form may not have been saved you.

Ber
+3  A: 

On a different thought, consider not even explicitly saving the invoice total. Instead, it may be dynamically recalculated each time you qurey for an invoice.

I think this is better modeling as it avoid redundant and possibly inconsistent data. SQL and Django are smart enough to compute you invoice total without much overhead each time you need it. Esp. you don't do the summation in you program if you use an aggregation function

Ber
Aggregation is probably the best option, but be aware that aggregation is not available in Django 1.0, but 1.1 (with aggregration) shoud be out "any day now(tm)" – and SVN trunk is stable enough to use right now :)
mikl
Thanks aggregation would be fantastic alas I'm stuck with Django 1.0.2 at the moment but you gave me an idea - I solved this with a property declaration method in the model, I realised I don't need to explicitly commit the total to a field - works perfectly. Cheers.