1

it seems to me as if the post_save signal is triggered not when the entire save process has been finalized in the database, but at the end of the model.save() call.

I made this observation when executing the following code:

models.py

class PurchaseOrder(models.Model):
    total_value = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)

def purchase_order_post_save_handler(sender, instance, **kwargs):
    project_po_value_update_thread = accounting.threads.ProjectPoValueUpdateThread(instance)
    project_po_value_update_thread.start() 

post_save.connect(purchase_order_post_save_handler, sender=PurchaseOrder) 

threads.py

class ProjectPoValueUpdateThread(threading.Thread):
    """
    thread to update the po.project with the latest po values
    called via the save method of the purchase order
    """

    def __init__(self, purchase_order):
        self.purchase_order = purchase_order
        threading.Thread.__init__(self)

    def run(self):
        "starts the thread to update project po values"
        try:
            project = self.purchase_order.project
            #update active po budget
            active_po_sum = PurchaseOrder.objects.filter(project=project, is_active=True).aggregate(total_value_sum=Sum('total_value'))
            active_total_value_sum = active_po_sum['total_value_sum']
            project.total_value = active_total_value_sum
            project.save()

In some cases, this code did not update the project total_value correctly, as the instance (which I just saved) queried with PurchaseOrder.objects.filter(project=project, is_active=True) was obviously not updated. Thus it seems to me as the thread has overtaken the instance save method and queried an old version of the model.

I know how to overcome this specific problem (just take the latest value from the instance provided by the post_save signal), but I'm wondering how one could create a post_save signal that is triggered when the save action in the database finalized.

Thomas Kremmel
  • 14,575
  • 26
  • 108
  • 177
  • This question is similar: http://stackoverflow.com/questions/950214/run-code-after-transaction-commit-in-django – Davide R. Mar 13 '13 at 12:20

1 Answers1

1

You are correct, the post_save signal is executed at the end of the save() method. That fact is in the Django docs:

django.db.models.signals.post_save

Like pre_save, but sent at the end of the save() method.

If your intent is to use a signal in several areas, you may be better suited to write your own.

edit: better link to signal definitions

Andrew Sledge
  • 10,163
  • 2
  • 29
  • 30
  • Ok, I think I will follow the recommendation of this answer: http://stackoverflow.com/a/951193/237690 and post a feature request to the django mailing list. Would be great to see this feature in the core of django. – Thomas Kremmel Mar 13 '13 at 14:04