PageRenderTime 146ms CodeModel.GetById 142ms app.highlight 1ms RepoModel.GetById 1ms app.codeStats 0ms

/docs/topics/signals.txt

https://code.google.com/p/mango-py/
Plain Text | 272 lines | 184 code | 88 blank | 0 comment | 0 complexity | dddc5a34179c56e935c12cf5d59c1986 MD5 | raw file
  1=======
  2Signals
  3=======
  4
  5.. module:: django.dispatch
  6   :synopsis: Signal dispatch
  7
  8Django includes a "signal dispatcher" which helps allow decoupled applications
  9get notified when actions occur elsewhere in the framework. In a nutshell,
 10signals allow certain *senders* to notify a set of *receivers* that some action
 11has taken place. They're especially useful when many pieces of code may be
 12interested in the same events.
 13
 14Django provides a :doc:`set of built-in signals </ref/signals>` that let user
 15code get notified by Django itself of certain actions. These include some useful
 16notifications:
 17
 18    * :data:`django.db.models.signals.pre_save` &
 19      :data:`django.db.models.signals.post_save`
 20
 21      Sent before or after a model's :meth:`~django.db.models.Model.save` method
 22      is called.
 23
 24    * :data:`django.db.models.signals.pre_delete` &
 25      :data:`django.db.models.signals.post_delete`
 26
 27      Sent before or after a model's :meth:`~django.db.models.Model.delete`
 28      method is called.
 29
 30    * :data:`django.db.models.signals.m2m_changed`
 31
 32      Sent when a :class:`ManyToManyField` on a model is changed.
 33
 34    * :data:`django.core.signals.request_started` &
 35      :data:`django.core.signals.request_finished`
 36
 37      Sent when Django starts or finishes an HTTP request.
 38
 39See the :doc:`built-in signal documentation </ref/signals>` for a complete list,
 40and a complete explanation of each signal.
 41
 42You can also `define and send your own custom signals`_; see below.
 43
 44.. _define and send your own custom signals: `defining and sending signals`_
 45
 46Listening to signals
 47====================
 48
 49To receive a signal, you need to register a *receiver* function that gets
 50called when the signal is sent by using the
 51:meth:`.Signal.connect` method:
 52
 53.. method:: Signal.connect(receiver, [sender=None, weak=True, dispatch_uid=None])
 54    
 55    :param receiver: The callback function which will be connected to this
 56        signal. See :ref:`receiver-functions` for more information.
 57    
 58    :param sender: Specifies a particular sender to receive signals from. See
 59        :ref:`connecting-to-specific-signals` for more information.
 60
 61    :param weak: Django stores signal handlers as weak references by
 62        default. Thus, if your receiver is a local function, it may be
 63        garbage collected. To prevent this, pass ``weak=False`` when you call
 64        the signal's ``connect()`` method.
 65
 66    :param dispatch_uid: A unique identifier for a signal receiver in cases
 67        where duplicate signals may be sent. See
 68        :ref:`preventing-duplicate-signals` for more information.
 69
 70Let's see how this works by registering a signal that
 71gets called after each HTTP request is finished. We'll be connecting to the
 72:data:`~django.core.signals.request_finished` signal.
 73
 74.. _receiver-functions:
 75
 76Receiver functions
 77------------------
 78
 79First, we need to define a receiver function. A receiver can be any Python
 80function or method:
 81
 82.. code-block:: python
 83
 84    def my_callback(sender, **kwargs):
 85        print "Request finished!"
 86
 87Notice that the function takes a ``sender`` argument, along with wildcard
 88keyword arguments (``**kwargs``); all signal handlers must take these arguments.
 89
 90We'll look at senders `a bit later`_, but right now look at the ``**kwargs``
 91argument. All signals send keyword arguments, and may change those keyword
 92arguments at any time. In the case of
 93:data:`~django.core.signals.request_finished`, it's documented as sending no
 94arguments, which means we might be tempted to write our signal handling as
 95``my_callback(sender)``.
 96
 97.. _a bit later: `connecting to signals sent by specific senders`_
 98
 99This would be wrong -- in fact, Django will throw an error if you do so. That's
100because at any point arguments could get added to the signal and your receiver
101must be able to handle those new arguments.
102
103.. _connecting-receiver-functions:
104
105Connecting receiver functions
106-----------------------------
107
108There are two ways you can connect a receiver to a signal. You can take the
109manual connect route:
110
111.. code-block:: python
112
113    from django.core.signals import request_finished
114
115    request_finished.connect(my_callback)
116
117Alternatively, you can use a ``receiver`` decorator when you define your
118receiver:
119
120.. code-block:: python
121
122    from django.core.signals import request_finished
123    from django.dispatch import receiver
124
125    @receiver(request_finished)
126    def my_callback(sender, **kwargs):
127        print "Request finished!"
128
129Now, our ``my_callback`` function will be called each time a request finishes.
130
131.. versionadded:: 1.3
132
133The ``receiver`` decorator was added in Django 1.3.
134
135.. admonition:: Where should this code live?
136
137    You can put signal handling and registration code anywhere you like.
138    However, you'll need to make sure that the module it's in gets imported
139    early on so that the signal handling gets registered before any signals need
140    to be sent. This makes your app's ``models.py`` a good place to put
141    registration of signal handlers.
142
143.. _connecting-to-specific-signals:
144
145Connecting to signals sent by specific senders
146----------------------------------------------
147
148Some signals get sent many times, but you'll only be interested in receiving a
149certain subset of those signals. For example, consider the
150:data:`django.db.models.signals.pre_save` signal sent before a model gets saved.
151Most of the time, you don't need to know when *any* model gets saved -- just
152when one *specific* model is saved.
153
154In these cases, you can register to receive signals sent only by particular
155senders. In the case of :data:`django.db.models.signals.pre_save`, the sender
156will be the model class being saved, so you can indicate that you only want
157signals sent by some model:
158
159.. code-block:: python
160
161    from django.db.models.signals import pre_save
162    from django.dispatch import receiver
163    from myapp.models import MyModel
164
165    @receiver(pre_save, sender=MyModel)
166    def my_handler(sender, **kwargs):
167        ...
168
169The ``my_handler`` function will only be called when an instance of ``MyModel``
170is saved.
171
172Different signals use different objects as their senders; you'll need to consult
173the :doc:`built-in signal documentation </ref/signals>` for details of each
174particular signal.
175
176.. _preventing-duplicate-signals:
177
178Preventing duplicate signals
179----------------------------
180
181In some circumstances, the module in which you are connecting signals may be
182imported multiple times. This can cause your receiver function to be
183registered more than once, and thus called multiples times for a single signal
184event. 
185
186If this behavior is problematic (such as when using signals to
187send an e-mail whenever a model is saved), pass a unique identifier as
188the ``dispatch_uid`` argument to identify your receiver function. This
189identifier will usually be a string, although any hashable object will
190suffice. The end result is that your receiver function will only be
191bound to the signal once for each unique ``dispatch_uid`` value.
192
193.. code-block:: python
194
195    from django.core.signals import request_finished
196
197    request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
198
199Defining and sending signals
200============================
201
202Your applications can take advantage of the signal infrastructure and provide
203its own signals.
204
205Defining signals
206----------------
207
208.. class:: Signal([providing_args=list])
209
210All signals are :class:`django.dispatch.Signal` instances. The
211``providing_args`` is a list of the names of arguments the signal will provide
212to listeners.
213
214For example:
215
216.. code-block:: python
217
218    import django.dispatch
219
220    pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
221
222This declares a ``pizza_done`` signal that will provide receivers with
223``toppings`` and ``size`` arguments.
224
225Remember that you're allowed to change this list of arguments at any time, so getting the API right on the first try isn't necessary.
226
227Sending signals
228---------------
229
230There are two ways to send send signals in Django.
231
232.. method:: Signal.send(sender, **kwargs)
233.. method:: Signal.send_robust(sender, **kwargs)
234
235To send a signal, call either :meth:`Signal.send` or :meth:`Signal.send_robust`.
236You must provide the ``sender`` argument, and may provide as many other keyword
237arguments as you like.
238
239For example, here's how sending our ``pizza_done`` signal might look:
240
241.. code-block:: python
242
243    class PizzaStore(object):
244        ...
245
246        def send_pizza(self, toppings, size):
247            pizza_done.send(sender=self, toppings=toppings, size=size)
248            ...
249
250Both ``send()`` and ``send_robust()`` return a list of tuple pairs
251``[(receiver, response), ... ]``, representing the list of called receiver
252functions and their response values.
253
254``send()`` differs from ``send_robust()`` in how exceptions raised by receiver
255functions are handled. ``send()`` does *not* catch any exceptions raised by
256receivers; it simply allows errors to propagate. Thus not all receivers may
257be notified of a signal in the face of an error.
258
259``send_robust()`` catches all errors derived from Python's ``Exception`` class,
260and ensures all receivers are notified of the signal. If an error occurs, the
261error instance is returned in the tuple pair for the receiver that raised the error.
262
263Disconnecting signals
264=====================
265
266.. method:: Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])
267
268To disconnect a receiver from a signal, call :meth:`Signal.disconnect`. The
269arguments are as described in :meth:`.Signal.connect`.
270
271The *receiver* argument indicates the registered receiver to disconnect. It may
272be ``None`` if ``dispatch_uid`` is used to identify the receiver.