Trigering post_save signal only after transaction has completed Trigering post_save signal only after transaction has completed django django

Trigering post_save signal only after transaction has completed


I think the simplest way is to use transaction.on_commit(). Here's an example using the models.Model subclass Photo that will only talk to Elasticsearch once the current transaction is over:

from django.db import transactionfrom django.db.models.signals import post_save@receiver(post_save, sender=Photo)def save_photo(**kwargs):    transaction.on_commit(lambda: talk_to_elasticsearch(kwargs['instance']))

Note that if the transaction.on_commit() gets executed while not in an active transaction, it will run right away.


Not really. The signals have nothing to do with the db transaction success or failure, but with the save method itself - before the call you have the pre_save signal fired and after the call you have the post_save signal fired.

There are 2 approaches here:

  • you are going to inspect the instance in the post_save method and decide that the model was saved successfully or not; simplest way to do that: in the save method, after the transaction executed successfully, annotate your instance with a flag, say instance.saved_successfully = True, which you will test in the post_save handler.
  • you are going to ditch the post_save signal and create a custom signal for yourself, which you will trigger after the transaction ran successfully.

Makes sense?

P.S.

If you strictly need to bind to the transaction commit signal, have a look over this package: https://django-transaction-hooks.readthedocs.org/en/latest/; it looks like the functionality is integrated in Django 1.9a.


I was having serious issues with django's admin not allowing post_save transactions on parent objects when they had inline children being modified.

This was my solution to an error complaining about conducting queries in the middle of an atomic block:

def on_user_post_save_impl(user):     do_something_to_the_user(user)def on_user_post_save(sender, instance, **kwargs):    if not transaction.get_connection().in_atomic_block:        on_user_post_save_impl(instance)    else:        transaction.on_commit(lambda: on_user_post_save_impl(instance))