Trigering post_save signal only after transaction has completed

doto picture doto · Oct 17, 2015 · Viewed 8k times · Source

I have written some APIs, for which the respective functions executive inside a transaction block. I am calling the save() method (after some modifications) on instance/s of a/several Model/s, and also consecutively indexing some JSON related information of the instance/s in Elasticsearch. I want the database to rollback even if for some reason the save() for one of the instances or indexing to the Elasticsearch fails.

Now, the problem is arising that even inside the transaction block, the post_save() signals gets called, and that is an issue because some notifications are being triggered from those signals.

Is there a way to trigger post_save() signals only after the transactions have completed successful?

Answer

Michael Tom picture Michael Tom · Oct 8, 2018

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 transaction
from 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.