'''NOTE''': Signals have been refactored in a backwards-incompatible way. Until this page gets updated, see the item on BackwardsIncompatibleChanges. == What Are Signals? == Django includes an internal "dispatcher" which provides two pieces of functionality: 1. Pieces of code which want to advertise what they're doing can use the dispatcher to send "signals" which contain information about what's happening. 2. Pieces of code which want to do something whenever a certain event happens can use the dispatcher to "listen" for particular signals, then execute the functions they want when those signals are sent out. The actual mechanism comes from a third-party library called [http://pydispatcher.sourceforge.net/ PyDispatcher], which is bundled with Django and which lives at `django.dispatch.dispatcher`. == How signals work == A signal is just a simple Python object, and requires nothing special to set up. For example, the `post_save` signal, found in `django.db.models.signals`, is defined like so: {{{ post_save = object() }}} When a piece of code wants to send a signal, it needs to do three things: 1. Import the signal from wherever it's been defined. 2. Import the dispatcher. 3. Use the dispatcher's `send` function to send the signal. An example of this can be found in the `save` method of the base model class, `django.db.models.Model`; the file in which that class is defined imports the signals defined in the `django.db.models` module: {{{ from django.db.models import signals }}} It also imports the dispatcher: {{{ from django.dispatch import dispatcher }}} And in the very last line of the `save` method, it sends the `post_save` signal: {{{ dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self) }}} The first two arguments are fairly clear, and are common for all uses of the dispatcher: 1. `signal` is the signal to be sent. 2. `sender` is the object which is sending the signal; in this case, `self.__class__`; this will be whatever model class the object which was just saved belongs to. The third argument, `instance`, is one of the more interesting features of the dispatcher: when sending a signal, you are free to include ''any'' extra arguments beyond these two; if a function which is listening for the signal is expecting certain information to be passed in as arguments, the dispatcher will ensure that the extra arguments to `send` are used. In this case the extra argument `instance` is `self`, which means it will be the object which was just saved. This means that functions which are listening for the `post_save` signal can, if they want to do something with the object that was just saved, specify that they take an argument named `instance`, and the dispatcher will pass it to them. To listen for a signal, first define a function that you want to execute when the signal is sent; if you know that the signal will be sent with extra arguments and you want to use those arguments, make sure your function accepts them. Then you need to do three things: 1. Make sure there is a reference to your signal handler somewhere. If it is defined as a local function, chances are it will be garbage collected and won't receive any signals. 2. Import the signal object you'll be listening for. 3. Import the dispatcher. 4. Use the dispatcher's `connect` signal to tell the dispatcher you want to listen for something. A good example of this is found in Django's bundled "contenttypes" application, which creates and maintains a registry of all the installed models in your database. In order to do this, the contenttypes app defines a `ContentType` model, and it needs to know any time a new model is installed so it can create the appropriate `ContentType` object for that model. To do this, it includes a file called `management.py`; whenever `manage.py syncdb` is run, it loops through ''every'' application in the `INSTALLED_APPS` setting, and looks to see if any apps contain a module called `management`; if they do, `manage.py` imports them before installing any models, which means that any dispatcher connections listed in an app's `management` module will be set up before model installation happens. In its `management.py` file, the contenttypes app defines a function called `update_contenttypes`, which takes three arguments: `app`, `created_models` and `verbosity`. These correspond to the extra arguments `manage.py` will use with `dispatcher.send` when it sends the `post_syncdb` signal after installing each new application, and provide enough information to determine which models need to have new `ContentType` objects created (actually, just `app` and `created_models` would be enough; the extra argument, `verbosity`, is used by `manage.py` to indicate whether any listening functions should be "verbose" and echo output to the console, or be quiet and not echo any output. The `management.py` file also imports `django.db.models.signals` and `django.dispatch.dispatcher`; after the `update_contenttypes` function is defined, it sets up that function to listen for the `post_syncdb` signal: {{{ dispatcher.connect(update_contenttypes, signal=signals.post_syncdb) }}} The first argument, `update_contenttypes`, is the name of the function to execute when the signal is sent out. The second argument, `signal`, is the signal to listen for. There is another optional argument, `sender`, which is not used in this example; `sender` can be used to narrow down exactly what will be listened for; when you specify `sender`, your function will only be executed when the object which sent the signal is the same as the object you specify as the `sender` argument. An example of this can be found in Django's authentication application: `django.contrib.auth.management` defines a function called `create_superuser`, and uses the dispatcher to connect to the `post_syncdb` signal -- but ''only'' when `post_syncdb` is being sent as a result of installing the auth application. To do this, the auth app's `management.py` file imports its own models: {{{ from django.contrib.auth import models as auth_app }}} And then uses the `sender` argument to `dispatcher.connect`: {{{ dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb) }}} Here's a breakdown of exactly why that works: 1. Whenever `manage.py syncdb` finishes installing the models for a particular application, it sends the `post_syncdb` signal. You'll remember that `dispatcher.send` takes an optional argument, `sender`, which is the object that's "sending" the signal. In this case, `manage.py syncdb` sets `sender` to be the `models` module of the app it just installed. 2. `django.contrib.auth.management` import the auth app's models as `auth_app`, which means that, within that file, the variable `auth_app` ''is'' the module `django.contrib.auth.models`. 3. So when `manage.py syncdb` send the `post_syncdb` signal with `django.contrib.auth.models` as the `sender` argument, the dispatcher notices that this is the same as the `sender` specified in the `dispatcher.connect` call in `django.contrib.auth.management`, and so the `create_superuser` function is executed. In case you've ever wondered, that's how Django knows to prompt you to create a superuser whenever you install the auth app for the first time. The auth app also sets up another function -- `create_permissions` -- which doesn't specify `sender` in its call to `dispatcher.connect`, so it runs any time `post_syncdb` is sent. That's how the auth app creates the add, change and delete `Permission` objects for each application you install. == List of signals built in to Django == Django defines several sets of signals which are used internally, and which you can listen for in order to run your own custom code at specific moments. `django.db.models.signals` defines the following signals: '''class_prepared''' This is sent whenever a model class has been "prepared"; in other words, once most of the metaprogramming which makes models work has been completed. Django uses this signal internally to know when to generate and add the automatic `AddManipulator` and `ChangeManipulator` to a model class (see the DevModelCreation page for details). Arguments that are sent with this signal: * `sender` -- the model class which was just prepared. '''pre_init''' Whenever you create a new instance of a Django model (for example, in [http://www.djangoproject.com/documentation/tutorial1/ the first part of the Django tutorial] when you do `p = Poll(question="What's up?", pub_date=datetime.now())`) , this signal is sent at the beginning of the execution of the model's `__init__` method. '''Note:''' if you override `__init__` on your model, you must call the parent class' `__init__` method for this signal to be sent, and it will be sent at the beginning of the parent class' `__init__` method. Arguments sent with this signal: * `sender` -- the model class you're creating an instance of. * `args` -- a list of positional arguments passed to the model's `__init__` method. * `kwargs` -- a dictionary of keyword arguments passed to the model's `__init__` method. For example, in the tutorial when you do `p = Poll(question="What's up?", pub_date=datetime.now())`, the `kwargs` argument to the `pre_init` signal would be the dictionary `{'question': "What's up?", 'pub_date': datetime.now()}`. '''post_init''' Like `pre_init`, but this one is sent when the model's `__init__` method is done executing. '''Note:''' if you override `__init__` on your model, you must call the parent class' `__init__` method for this signal to be sent, and it will be sent at the end of the parent class' `__init__` method. Arguments sent with this signal: * `sender` -- the model class you've just created an instance of. * `instance` -- the instance of the model you just created. For example, in the tutorial when you do `p = Poll(question="What's up?", pub_date=datetime.now())`, the `instance` argument to the `post_init` signal would be the `Poll` object you just created. '''pre_save''' This is sent at the beginning of a model's `save` method. '''Note:''' if you override `save` on your model, you must call the parent class' `save` method for this signal to be sent, and it will be sent at the beginning of the parent class' `save` method. Arguments sent with this signal: * `sender` -- the model class of the object being saved. * `instance` -- the actual object being saved. * `raw` -- raw save, save the object exactly as presented. '''post_save''' This is sent at the end of a model's `save` method. '''Note:''' if you override `save` on your model, you must call the parent class' `save` method for this signal to be sent, and it will be sent at the end of the parent class' `save` method. Arguments sent with this signal: * `sender` -- the model class of the object which was just saved. * `instance` -- the actual object which was just saved. * `created` -- a boolean. True if a new record was create. * `raw` -- raw save, save the object exactly as presented. '''pre_delete''' This is sent at the beginning of a model's `delete` method. '''Note:''' if you override `delete` on your model, you must call the parent class' `delete` method for this signal to be sent, and it will be sent at the beginning of the parent class' `delete` method. Arguments sent with this signal: * `sender` -- the model class of the object which is about to be deleted. * `instance` -- the actual object which is about to be deleted. '''post_delete''' This is sent at the end of a model's `delete` method. '''Note:''' if you override `delete` on your model, you must call the parent class' `delete` method for this signal to be sent, and it will be sent at the beginning of the parent class' `delete` method. Arguments sent with this signal: * `sender` -- the model class of the object which was just deleted. * `instance` -- the actual object which was just deleted (the object will no longer be in the database, but will stick around in memory for a little while after that). '''post_syncdb'' Sent by `manage.py syncdb` after it installs an application. Arguments sent with this signal: * `sender` -- the `models` module of the application which was just installed. * `app` -- same as `sender`. * `created_models` -- a list of the model classes which `manage.py` has created so far, regardless of app. * `verbosity` -- indicates how much information `manage.py` is printing on screen. There are three possible values: 0 means no information, 1 means some information and 2 means all possible information. Functions which listen for this signal should adjust what they output to the screen based on the value of this argument. * `interactive` -- whether `manage.py` is running in "interactive" mode; this is a boolean and so is either `True` or `False`. If `interactive` is `True`, it's safe to prompt the user to input things on the command line (for example, the auth app only prompts to create a superuser when `interactive` is `True`); if `interactive` is `False`, functions which listen for this signal should not try to prompt for anything. ---- `django.core.signals` defines the following signals: '''request_started''' This signal is sent whenever Django begins processing an incoming HTTP request. This signal doesn't provide any arguments. '''request_finished''' This signal is sent whenever Django finishes processing an incoming HTTP request. This signal doesn't provide any arguments. '''got_request_exception''' This signal is sent whenever Django encounters an exception while processing an incoming HTTP request. This signal doesn't provide any arguments. ---- `django.test.signals` defines the following signals: '''template_rendered''' This signal is sent by Django's testing framework whenever the test system renders a template; it's used by the test system to verify that the template rendered as expected. This signal is not emitted during normal operation of a Django server -- it is only available during testing. Arguments sent with this signal: * `sender` -- the `Template` object which was rendered. * `template` -- same as `sender`. * `context` -- the `Context` with which the template was rendered. == Refactoring differences == [8223] refactored signals and {{{django.dispatch}}} with an eye towards speed. The net result was up to a 90% improvement in the speed of signal handling, but along the way some backwards-incompatible changes were made: * All handlers now must be declared as accepting {{{**kwargs}}}. * Signals are now instances of {{{django.dispatch.Signal}}} instead of anonymous objects. * Connecting, disconnecting, and sending signals are done via methods on the {{{Signal}}} object instead of through module methods in {{{django.dispatch.dispatcher}}}. The module-level methods are deprecated. * The {{{Anonymous}}} and {{{Any}}} sender options no longer exist. You can still receive signals sent by any sender by using {{{sender=None}}} So, a quick summary of the code changes you'd need to make: || '''Before''' || '''After''' || || {{{def my_handler(sender)}}} || {{{def my_handler(sender, **kwargs)}}} || || {{{my_signal = object()}}} || {{{my_signal = django.dispatch.Signal()}}} || || {{{dispatcher.connect(my_handler, my_signal)}}} || {{{my_signal.connect(my_handler)}}} || || {{{dispatcher.send(my_signal, sender)}}} || {{{my_signal.send(sender)}}} || || {{{dispatcher.connect(my_handler, my_signal, sender=Any)}}} || {{{my_signal.connect(my_handler, sender=None)}}} || == Other documentation == * [http://feh.holsman.net/articles/2006/06/13/django-signals Django signals] -- blog entry by Ian Holsman which discusses signals in general. * [http://www.bright-green.com/blog/2006_07_12/initialising_application_data_.html Initializing application data in Django] -- blog entry by Alan Green which discusses use of the `post_syncdb` signal to provide initial application data. * [http://www.b-list.org/weblog/2006/09/10/django-tips-laying-out-application Django tips: laying out an application] -- blog entry by James Bennett which mentions the use of the `post_syncdb` signal to execute custom functions when an application is installed. * [http://www.mercurytide.com/whitepapers/django-signals/ Django signals] -- Mercurytide whitepaper explaining Django's dispatcher. == Applications not bundled with Django which use signals == * [http://zyons.com/ Zyons] * http://django-utils.googlecode.com/svn/branches/0.1/thumbnail/field.py * [http://satchmoproject.com/ Satchmo] * [http://getbanjo.com/ Banjo] * [http://code.google.com/p/django-announcements/ Django Announcements] * [http://code.google.com/p/django-evolution/ Django Evolution]