Django: How to trigger a function whenever certain objects are modified from the wagtail interface

I have a long list of "Quotation" objects.

The price of a quotation depends on dozens of children (and grand children) objects. The lowest one being the rate/hour.

When I change the children objects of a quotation like the rate/hour, the quotation price changes.

I would like to recalculate the price of each quotation that is impacted by any change I make on their consistuant objects automatically. I am using Wagtail for the object admin.

I am not sure about the way to do that, should I use signals? Wagtail hooks?

Wagtail models and pages are just Django models.

Are all children (and grand children) of the same model? In that case you could just register a post_save signal on the child model, but in general, I'd recommend using post_save only for things like sending an email when an object changes, unless you take the following things into consideration:

  • This kind of processing can become very slow very quickly. If you have multiple quotations, you'll need to use an atomic transaction, otherwise you'll make a new db connection when saving every quotation.
  • You'll also need to prefetch children and grandchildren, to prevent multiple database calls.
  • When saving other models inside a post_save, you run the risk of creating an endless loop of post_save signals.

I think a better way would be to add a @property called price on Quotation instead of storing the price in the database:

class Quotation(models.Model):
    # Model fields here
    ...

    @property
    def price(self):
        return sum([child.price for child in self.children])

This will only calculate a price when you call quotation.price. You could speed up this calculation by prefetching children when receiving Quotations.

Back to Top