Fixed #11441 -- Improved signal topic guide, particularly regarding the weak and dispatch_uid parameters to the Signal.connect method. Thanks to Mike_A and sayane for the report, and gremmie for the draft patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14337 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
6737570aeb
commit
e4c0c377dd
|
@ -46,15 +46,38 @@ You can also `define and send your own custom signals`_; see below.
|
||||||
Listening to signals
|
Listening to signals
|
||||||
====================
|
====================
|
||||||
|
|
||||||
To receive a signal, you need to register a *receiver* function that gets called
|
To receive a signal, you need to register a *receiver* function that gets
|
||||||
when the signal is sent. Let's see how this works by registering a signal that
|
called when the signal is sent by using the
|
||||||
|
:meth:`.Signal.connect` method:
|
||||||
|
|
||||||
|
.. method:: Signal.connect(receiver, [sender=None, weak=True, dispatch_uid=None])
|
||||||
|
|
||||||
|
:param receiver: The callback function which will be connected to this
|
||||||
|
signal. See :ref:`receiver-functions` for more information.
|
||||||
|
|
||||||
|
:param sender: Specifies a particular sender to receive signals from. See
|
||||||
|
:ref:`connecting-to-specific-signals` for more information.
|
||||||
|
|
||||||
|
:param weak: Django stores signal handlers as weak references by
|
||||||
|
default. Thus, if your receiver is a local function, it may be
|
||||||
|
garbage collected. To prevent this, pass ``weak=False`` when you call
|
||||||
|
the signal's ``connect()`` method.
|
||||||
|
|
||||||
|
:param dispatch_uid: A unique identifier for a signal receiver in cases
|
||||||
|
where duplicate signals may be sent. See
|
||||||
|
:ref:`preventing-duplicate-signals` for more information.
|
||||||
|
|
||||||
|
Let's see how this works by registering a signal that
|
||||||
gets called after each HTTP request is finished. We'll be connecting to the
|
gets called after each HTTP request is finished. We'll be connecting to the
|
||||||
:data:`~django.core.signals.request_finished` signal.
|
:data:`~django.core.signals.request_finished` signal.
|
||||||
|
|
||||||
|
.. _receiver-functions:
|
||||||
|
|
||||||
Receiver functions
|
Receiver functions
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
First, we need to define a receiver function. A receiver can be any Python function or method:
|
First, we need to define a receiver function. A receiver can be any Python
|
||||||
|
function or method:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -77,6 +100,8 @@ This would be wrong -- in fact, Django will throw an error if you do so. That's
|
||||||
because at any point arguments could get added to the signal and your receiver
|
because at any point arguments could get added to the signal and your receiver
|
||||||
must be able to handle those new arguments.
|
must be able to handle those new arguments.
|
||||||
|
|
||||||
|
.. _connecting-receiver-functions:
|
||||||
|
|
||||||
Connecting receiver functions
|
Connecting receiver functions
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
@ -115,6 +140,8 @@ The ``receiver`` decorator was added in Django 1.3.
|
||||||
to be sent. This makes your app's ``models.py`` a good place to put
|
to be sent. This makes your app's ``models.py`` a good place to put
|
||||||
registration of signal handlers.
|
registration of signal handlers.
|
||||||
|
|
||||||
|
.. _connecting-to-specific-signals:
|
||||||
|
|
||||||
Connecting to signals sent by specific senders
|
Connecting to signals sent by specific senders
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
@ -146,10 +173,34 @@ Different signals use different objects as their senders; you'll need to consult
|
||||||
the :doc:`built-in signal documentation </ref/signals>` for details of each
|
the :doc:`built-in signal documentation </ref/signals>` for details of each
|
||||||
particular signal.
|
particular signal.
|
||||||
|
|
||||||
|
.. _preventing-duplicate-signals:
|
||||||
|
|
||||||
|
Preventing duplicate signals
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
In some circumstances, the module in which you are connecting signals may be
|
||||||
|
imported multiple times. This can cause your receiver function to be
|
||||||
|
registered more than once, and thus called multiples times for a single signal
|
||||||
|
event.
|
||||||
|
|
||||||
|
If this behavior is problematic (such as when using signals to
|
||||||
|
send an e-mail whenever a model is saved), pass a unique identifier as
|
||||||
|
the ``dispatch_uid`` argument to identify your receiver function. This
|
||||||
|
identifier will usually be a string, although any hashable object will
|
||||||
|
suffice. The end result is that your receiver function will only be
|
||||||
|
bound to the signal once for each unique ``dispatch_uid`` value.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.core.signals import request_finished
|
||||||
|
|
||||||
|
request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
|
||||||
|
|
||||||
Defining and sending signals
|
Defining and sending signals
|
||||||
============================
|
============================
|
||||||
|
|
||||||
Your applications can take advantage of the signal infrastructure and provide its own signals.
|
Your applications can take advantage of the signal infrastructure and provide
|
||||||
|
its own signals.
|
||||||
|
|
||||||
Defining signals
|
Defining signals
|
||||||
----------------
|
----------------
|
||||||
|
@ -176,9 +227,14 @@ Remember that you're allowed to change this list of arguments at any time, so ge
|
||||||
Sending signals
|
Sending signals
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
.. method:: Signal.send(sender, **kwargs)
|
There are two ways to send send signals in Django.
|
||||||
|
|
||||||
To send a signal, call :meth:`Signal.send`. You must provide the ``sender`` argument, and may provide as many other keyword arguments as you like.
|
.. method:: Signal.send(sender, **kwargs)
|
||||||
|
.. method:: Signal.send_robust(sender, **kwargs)
|
||||||
|
|
||||||
|
To send a signal, call either :meth:`Signal.send` or :meth:`Signal.send_robust`.
|
||||||
|
You must provide the ``sender`` argument, and may provide as many other keyword
|
||||||
|
arguments as you like.
|
||||||
|
|
||||||
For example, here's how sending our ``pizza_done`` signal might look:
|
For example, here's how sending our ``pizza_done`` signal might look:
|
||||||
|
|
||||||
|
@ -191,4 +247,26 @@ For example, here's how sending our ``pizza_done`` signal might look:
|
||||||
pizza_done.send(sender=self, toppings=toppings, size=size)
|
pizza_done.send(sender=self, toppings=toppings, size=size)
|
||||||
...
|
...
|
||||||
|
|
||||||
|
Both ``send()`` and ``send_robust()`` return a list of tuple pairs
|
||||||
|
``[(receiver, response), ... ]``, representing the list of called receiver
|
||||||
|
functions and their response values.
|
||||||
|
|
||||||
|
``send()`` differs from ``send_robust()`` in how exceptions raised by receiver
|
||||||
|
functions are handled. ``send()`` does *not* catch any exceptions raised by
|
||||||
|
receivers; it simply allows errors to propagate. Thus not all receivers may
|
||||||
|
be notified of a signal in the face of an error.
|
||||||
|
|
||||||
|
``send_robust()`` catches all errors derived from Python's ``Exception`` class,
|
||||||
|
and ensures all receivers are notified of the signal. If an error occurs, the
|
||||||
|
error instance is returned in the tuple pair for the receiver that raised the error.
|
||||||
|
|
||||||
|
Disconnecting signals
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. method:: Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])
|
||||||
|
|
||||||
|
To disconnect a receiver from a signal, call :meth:`Signal.disconnect`. The
|
||||||
|
arguments are as described in :meth:`.Signal.connect`.
|
||||||
|
|
||||||
|
The *receiver* argument indicates the registered receiver to disconnect. It may
|
||||||
|
be ``None`` if ``dispatch_uid`` is used to identify the receiver.
|
||||||
|
|
Loading…
Reference in New Issue