1.0.0 Other/Proprietary License
  not rated
Adds post_commit and post_rollback signal handlers to Django




While working on the ASU Digital Repository, I found I needed the ability to trigger callbacks when a transaction was committed. Django's signals seemed to be the perfect mechanism, but transaction commit and rollback signals are not (as of this writing) supported in the core framework. (See these tickets in the Django issue tracker for background: Ticket #14050, Ticket #14051)

However, a gist written by Grégoire Cachet seems to do the trick. It adds a custom signal implementation and monkey-patches Django's transaction handling functions to dispatch post_commit and post_rollback signals.

django_transaction_signals is a Django app that extends that gist in the following ways:

- Adds a defer() function that can be used inside a transaction to defer the execution of a function until the transaction has committed (I found this quite useful for triggering Celery tasks that depend on the objects committed).
- Guards against badly behaved signal handlers (i.e. ones that leave the current transaction in a dirty state) and raises a BadlyBehavedTransactionSignalHandlerError when it detects a misbehaving handler.
- Clears handlers on transaction exit regardless of whether a commit, rollback, or neither occurred. This fixes an issue where handlers could accumulate and be triggered on a subsequent transaction.

Usage (from the original gist):

You have to make sure to load this before you use signals.

For example, add the the following line to your project's file:

import django_transaction_signals

Then, to use the signals, create a function and bind it to the post_commit signal:

from django.db import transaction

def my_function(**kwargs):
 # do your stuff here

If you're using non-local variables in your callback function, make sure to use non-weak reference or your variables could be garbage collected before the function gets called. For example, in a model's save() method:

def save(self, *args, **kwargs):
 def my_function(**kwargs):
 # do your stuff here
 # access self variable
 transaction.signals.post_commit.connect(my_function, weak=False)

Usage of defer() function:

defer() registers a function to be run upon successful completion of the current transaction (if one exists). Calling defer(func, *args, **kwargs) translates to the following:

- If a transaction is active, register a post-commit listener to execute func(*args, **kwargs)
- If no transaction is active, execute func(*args, **kwargs) immediately

This example demonstrates a transactional update of a model object which registers a Celery task to be executed when the transaction commits successfully.

from celery.task import task
from django.db import transaction
from django_transaction_signals import defer
import pysolr

def update_object(obj):
 # ...modify and save object...
 defer(index_object.delay, obj)
 # some additional work in the transaction...

def index_object(obj):
 index_obj = {'id':}
 # index object...
 solr = pysolr.Solr('http://localhost:8080/solr')
Last updated on August 23rd, 2012

0 User reviews so far.