Dan Ward Follow me on Twitter View my LinkedIn profile Subscribe to my news feed   

A self-confessed geek and web developer

 

Blog: Database transactions in Django

From time-to-time, I'll have a brainwave while trying to figure out something tech-oriented; well, either that or I just want to get something off my chest. Anyhow, if I get round to typing it up, it'll wind up here in the blog.

Created by dan on Thursday 29th October, 2009 at 3:11 PM
Tags: Django, MySQL, Python, Web development

I've come to the point where I really need to go down the route of using database transactions for a few operations carried out on my Django project. As always, a simple search for 'django database transactions' in Google returns a, somewhat relieving official Django page with the documentation for their database transaction middleware.

My only reservation about Django's documentation is, that in some cases, it can be a little vague as to how exactly the syntax should be structured, resulting in more Googling. As I write this, I've not tried the syntax, which I'm about to detail, however if there are any critically-incorrect statements, they will be corrected in due course. I'm mainly writing this for myself, so that I can get a grasp of things when I need to, and while I'm not actually working on it. I also suggest that if you're going to try things out, don't be stupid: do it in a dev environment.

So, let me try to word database transactions in a way that most developers will understand. On occasions, you may find that instead of updating a single model or object, you need to update multiple models or objects. From the perspective of a developer who likes to think that everything will go wrong, updating 10 models or objects (for example) would take a lot of error-handling to go back on operations prior to one where an error has occurred. This is where database transactions enter the picture.

With a database transaction, it is possible to churn out every single model or object change in one blob of code and still be safe in the knowledge that if something bad were to go wrong (always best to think negatively, in my opinion), all changes would be rolled back to their prior state, as if they never happened.

Anyway, less of the talkie and more workie... To get started, we need to add Django's database transaction middleware to the project. The namespace for the middleware is as below:

 

django.middleware.transaction.TransactionMiddleware

 

Now, the transaction is designed to be utilised inside your views, so at the top of the views.py where your transactional view resides, you need to import the database transaction library using the below line:

 

from django.db import transaction

 

For your view, which utilises the database transaction library, you need to add a decorator, as below:

 

@transaction.commit_manually
def viewfunc(request):

# Your view code
...

 

Other than 'commit_manually', there are other decorators, but they appear to attempt to speed up development time, however at the cost of control. Anyhow, we're ready to do stuff with database transactions now.

There are two options with manual committing: either you can simply spit out your model or object updates, then commit if all is successful, or you can go a step further and use Django's save points. Save points allow you to set milestones in the transaction process, so instead of rolling back everything, you can roll back as far as the specified save point.

Below is an example of the standard manual commit (to my understanding):

 

@transaction.commit_manually
def viewfunc(request):

# Try updating each model or object
try:

# Update object a
...
a.save()

# Update object b
...
a.save()

# Update object c
...
a.save()

# If an exception occurred in the 'try' statement
except:

# Roll-back all changes made inside the 'try' statement
transaction.rollback()

# If successful
else:

# Commit all changes in the 'try' statement
transaction.commit()

 

With the above view code, if object c's update failed for example, the changes made to a and b prior to the exception would be undone. Otherwise, if all changes were successful and no exceptions occurred, then all model or object changes would be saved.

For more information on the database transaction framework implemented in Django, or to look in to using save points (only a little more work than what's above; the wording is very clear), view the latest documentation:

http://docs.djangoproject.com/en/dev/topics/db/transactions/

Sorry if this didn't help in the slightest, although it's really more for my own recollection.