Changes between Version 25 and Version 26 of Signals


Ignore:
Timestamp:
Aug 8, 2008, 8:22:33 AM (16 years ago)
Author:
Henrik Vendelbo
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Signals

    v25 v26  
    88 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.
    99
    10 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`.
     10The 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`. To improve performance the API and implementation has been refactored, as described at the end of this document.
    1111
    1212== How signals work ==
     
    1515
    1616{{{
    17 post_save = object()
     17post_save = django.dispatch.Signal()
    1818}}}
    1919
     
    2121
    2222 1. Import the signal from wherever it's been defined.
    23  2. Import the dispatcher.
    24  3. Use the dispatcher's `send` function to send the signal.
     23 2. Use the signal's `send` function to send the signal.
    2524
    2625An 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:
     
    3029}}}
    3130
    32 It also imports the dispatcher:
    33 
    34 {{{
    35 from django.dispatch import dispatcher
    36 }}}
    37 
    3831And in the very last line of the `save` method, it sends the `post_save` signal:
    3932
    4033{{{
    41 dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self)
    42 }}}
    43 
    44 The first two arguments are fairly clear, and are common for all uses of the dispatcher:
    45 
    46  1. `signal` is the signal to be sent.
    47  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.
    48 
    49 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.
     34signals.post_save.send(sender=self.__class__, instance=self)
     35}}}
     36
     37The first argument is fairly clear, and is common for all uses of the dispatcher; `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.
     38
     39The second 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 the first; 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`.
    5040
    5141To 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:
    5242
    5343 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.
    54  2. Import the signal object you'll be listening for.
    55  3. Import the dispatcher.
    56  4. Use the dispatcher's `connect` signal to tell the dispatcher you want to listen for something.
     44 2. Make sure that the signal handler has **kwargs as the last parameter.
     45 3. Import the signal object you'll be listening for.
     46 4. Use the signal's `connect` method to tell the dispatcher you want to listen for something.
    5747
    5848A 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.
     
    6353
    6454{{{
    65 dispatcher.connect(update_contenttypes, signal=signals.post_syncdb)
    66 }}}
    67 
    68 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.
     55signals.post_syncdb.connect(update_contenttypes)
     56}}}
     57
     58The method is called on an instance of django.dispatch.Signal, identifying the signal to listen for. The first argument, `update_contenttypes`, is a reference to the function to execute when the signal is sent out. 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.
    6959
    7060An 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:
     
    7464}}}
    7565
    76 And then uses the `sender` argument to `dispatcher.connect`:
    77 
    78 {{{
    79 dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb)
     66And then uses the `sender` argument to `Signal.connect`:
     67
     68{{{
     69signals.post_syncdb.connect(create_superuser, sender=auth_app)
    8070}}}
    8171
Back to Top