Django and syncdb’s signal processing
January 1st, 2008
One feature of django is worth to note is that it supports signals. In fact, under its skin it implements PyDispatcher, a python library that allows to emit signals and to dispatch them.
If at first glance this couldn’t look so useful to you, well, this hasn’t been true for me since it was exactly that kind of stuff I was looking for. What I was trying to do was to implement some kind of auto-installer for an application that I’m writing, and in order to do so I had to run the set up after that the syncdb command is issued. So the main problem was: how do I know when a user does the syncdb in a non-intrusive way?
After some googling, I found that in django exists the semi-hidden feature of signals, so I began exploring them. The only thing you can look at on the official site is a page on their wiki, and additionally there are some cool articles over the net. Anyway, if you want to know a fast way to catch the syncdb command just follow up the reading.
First of all, let say that django looks for a file named management.py in every installed application’s directory whenever the syncdb command is ran. In this file we’ll write our management functions and we’ll link those functions to django through its signal system.
To do so we need to import some basic django’s modules:
from django.dispatch import dispatcher
from django.db.models import signals
With these modules we have everything to handle the django’s signals, and so here we go:
dispatcher.connect(do_something_with_the_signal, signal=signals.post_syncdb, sender=model)
With that function we connect our function do_something_with_the_signal to the django’s signal handler. A word apart has to be given to the sender attribute. In that way we say that our function must be called only when the appropriate model gets called in the syncdb phase.
The signal handling’s function must be defined as following:
def do_something_with_the_signal(app, created_models, verbosity, **kwargs):
So let describe the parameter list:
- app: the dispatcher sender’s attribute
- created_models: a list of models that have been created with this syncdb
- verbosity: django’s verbosity level
- kwargs: a variable-length’s list of optional arguments
Let suppose we want to create a function that inserts the settings.LANGUAGES list into a model (as I had to do for a little work). Here is how the code looks like:
from django.conf import settings
from django.dispatch import dispatcher
from django.db.models import signals
from project.translatable import models as transmodel
def create_language_list(app, created_models, verbosity, **kwargs):
for lang in settings.LANGUAGES:
lcode, literal = lang
if transmodel.Language in created_models:
print "Adding %s (%s)..." % (literal, lcode)
new_lang = transmodel.Language(code=lcode, name=literal)
new_lang.save()
dispatcher.connect(create_language_list, signal=signals.post_syncdb, sender=transmodel)
It’s worth noting here that using the print statement is perfectly OK (this is done by django’s auth system for example). Another thing to note is that we check that our model has been created in that syncdb’s phase. I do so because in this way the model is filled just the first time the model is created.
Another use of this stuff is to insert initial raw data into the model by using django’s ORM and not by using raw SQL. In this way we’ll be database-backend indipendent and we’ll have a transparent way to have initial data in our models.