Xof / xact

Transaction decorator for Django and PostgreSQL
http://thebuild.com/blog/2012/03/19/a-recipe-for-django-transactions-on-postgresql/
73 stars 7 forks source link

xact is a recipe for handling transactions sensibly in Django applications on PostgreSQL.

Note: As of Django 1.6, the functionality of xact will be merged into the Django core as the atomic decorator. Code that uses xact should be able to be migrated to atomic with just a search-and-replace. atomic works on databases other than PostgreSQL, is thread-safe, and has other nice features; switch to it when you can!

The goals are:

The bits of the recipe are:

The quick reasons behind each step:

This recipe a few other nice features:

xact() also supports the using parameter for multiple databases.

Rollback is a supplied exception class designed for situations in which you want to trigger an exception to cause a rollback, but do not want that exception to propagate beyond the scope of the xact block. xact will perform the rollback, then swallow the exception.

Of course, a few caveats:

To use, just drop the source (one class definition, one function) into a file somewhere in your Django project (such as the omni-present utils application every Django project seems to have), and include it.

Examples:

from utils.transaction import xact

@xact
def my_view_function1(request):
   # Everything here will be in a transaction.
   # It'll roll back if an exception escapes, commits otherwise.

def my_view_function2(request):
   # This stuff won't be in a transaction, so don't modify the database here.
   with xact():
      # This stuff will be, and will commit on normal completion, roll back on a exception

def my_view_function3(request):
   with xact():
      # Modify the database here (let's call it "part 1").
      try:
         with xact():
            # Let's call this "part 2."
            # This stuff will be in its own savepoint, and can commit or
            # roll back without losing the whole transaction.
      except:
         # Part 2 will be rolled back, but part 1 will still be available to
         # be committed or rolled back.  Of course, if an exception
         # inside the "part 2" block is not caught, both part 2 and
         # part 1 will be rolled back.