mirror of
				https://github.com/django/django.git
				synced 2025-11-03 21:25:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			277 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
=======
 | 
						|
Signals
 | 
						|
=======
 | 
						|
 | 
						|
.. module:: django.dispatch
 | 
						|
   :synopsis: Signal dispatch
 | 
						|
 | 
						|
Django includes a "signal dispatcher" which helps allow decoupled applications
 | 
						|
get notified when actions occur elsewhere in the framework. In a nutshell,
 | 
						|
signals allow certain *senders* to notify a set of *receivers* that some action
 | 
						|
has taken place. They're especially useful when many pieces of code may be
 | 
						|
interested in the same events.
 | 
						|
 | 
						|
Django provides a :doc:`set of built-in signals </ref/signals>` that let user
 | 
						|
code get notified by Django itself of certain actions. These include some useful
 | 
						|
notifications:
 | 
						|
 | 
						|
* :data:`django.db.models.signals.pre_save` &
 | 
						|
  :data:`django.db.models.signals.post_save`
 | 
						|
 | 
						|
  Sent before or after a model's :meth:`~django.db.models.Model.save` method
 | 
						|
  is called.
 | 
						|
 | 
						|
* :data:`django.db.models.signals.pre_delete` &
 | 
						|
  :data:`django.db.models.signals.post_delete`
 | 
						|
 | 
						|
  Sent before or after a model's :meth:`~django.db.models.Model.delete`
 | 
						|
  method or queryset's :meth:`~django.db.models.query.QuerySet.delete`
 | 
						|
  method is called.
 | 
						|
 | 
						|
* :data:`django.db.models.signals.m2m_changed`
 | 
						|
 | 
						|
  Sent when a :class:`~django.db.models.ManyToManyField` on a model is changed.
 | 
						|
 | 
						|
* :data:`django.core.signals.request_started` &
 | 
						|
  :data:`django.core.signals.request_finished`
 | 
						|
 | 
						|
  Sent when Django starts or finishes an HTTP request.
 | 
						|
 | 
						|
See the :doc:`built-in signal documentation </ref/signals>` for a complete list,
 | 
						|
and a complete explanation of each signal.
 | 
						|
 | 
						|
You can also `define and send your own custom signals`_; see below.
 | 
						|
 | 
						|
.. _define and send your own custom signals: `defining and sending signals`_
 | 
						|
 | 
						|
Listening to signals
 | 
						|
====================
 | 
						|
 | 
						|
To receive a signal, you need to register a *receiver* function that gets
 | 
						|
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
 | 
						|
:data:`~django.core.signals.request_finished` signal.
 | 
						|
 | 
						|
.. _receiver-functions:
 | 
						|
 | 
						|
Receiver functions
 | 
						|
------------------
 | 
						|
 | 
						|
First, we need to define a receiver function. A receiver can be any Python
 | 
						|
function or method::
 | 
						|
 | 
						|
    def my_callback(sender, **kwargs):
 | 
						|
        print("Request finished!")
 | 
						|
 | 
						|
Notice that the function takes a ``sender`` argument, along with wildcard
 | 
						|
keyword arguments (``**kwargs``); all signal handlers must take these arguments.
 | 
						|
 | 
						|
We'll look at senders `a bit later`_, but right now look at the ``**kwargs``
 | 
						|
argument. All signals send keyword arguments, and may change those keyword
 | 
						|
arguments at any time. In the case of
 | 
						|
:data:`~django.core.signals.request_finished`, it's documented as sending no
 | 
						|
arguments, which means we might be tempted to write our signal handling as
 | 
						|
``my_callback(sender)``.
 | 
						|
 | 
						|
.. _a bit later: `connecting to signals sent by specific senders`_
 | 
						|
 | 
						|
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
 | 
						|
must be able to handle those new arguments.
 | 
						|
 | 
						|
.. _connecting-receiver-functions:
 | 
						|
 | 
						|
Connecting receiver functions
 | 
						|
-----------------------------
 | 
						|
 | 
						|
There are two ways you can connect a receiver to a signal. You can take the
 | 
						|
manual connect route::
 | 
						|
 | 
						|
    from django.core.signals import request_finished
 | 
						|
 | 
						|
    request_finished.connect(my_callback)
 | 
						|
 | 
						|
Alternatively, you can use a :func:`receiver` decorator:
 | 
						|
 | 
						|
.. function:: receiver(signal)
 | 
						|
 | 
						|
    :param signal: A signal or a list of signals to connect a function to.
 | 
						|
 | 
						|
Here's how you connect with the decorator::
 | 
						|
 | 
						|
    from django.core.signals import request_finished
 | 
						|
    from django.dispatch import receiver
 | 
						|
 | 
						|
    @receiver(request_finished)
 | 
						|
    def my_callback(sender, **kwargs):
 | 
						|
        print("Request finished!")
 | 
						|
 | 
						|
Now, our ``my_callback`` function will be called each time a request finishes.
 | 
						|
 | 
						|
.. admonition:: Where should this code live?
 | 
						|
 | 
						|
    Strictly speaking, signal handling and registration code can live anywhere
 | 
						|
    you like, although it's recommended to avoid the application's root module
 | 
						|
    and its ``models`` module to minimize side-effects of importing code.
 | 
						|
 | 
						|
    In practice, signal handlers are usually defined in a ``signals``
 | 
						|
    submodule of the application they relate to. Signal receivers are
 | 
						|
    connected in the :meth:`~django.apps.AppConfig.ready` method of your
 | 
						|
    application configuration class. If you're using the :func:`receiver`
 | 
						|
    decorator, simply import the ``signals`` submodule inside
 | 
						|
    :meth:`~django.apps.AppConfig.ready`.
 | 
						|
 | 
						|
    .. versionchanged:: 1.7
 | 
						|
 | 
						|
        Since :meth:`~django.apps.AppConfig.ready` didn't exist in previous
 | 
						|
        versions of Django, signal registration usually happened in the
 | 
						|
        ``models`` module.
 | 
						|
 | 
						|
.. _connecting-to-specific-signals:
 | 
						|
 | 
						|
Connecting to signals sent by specific senders
 | 
						|
----------------------------------------------
 | 
						|
 | 
						|
Some signals get sent many times, but you'll only be interested in receiving a
 | 
						|
certain subset of those signals. For example, consider the
 | 
						|
:data:`django.db.models.signals.pre_save` signal sent before a model gets saved.
 | 
						|
Most of the time, you don't need to know when *any* model gets saved -- just
 | 
						|
when one *specific* model is saved.
 | 
						|
 | 
						|
In these cases, you can register to receive signals sent only by particular
 | 
						|
senders. In the case of :data:`django.db.models.signals.pre_save`, the sender
 | 
						|
will be the model class being saved, so you can indicate that you only want
 | 
						|
signals sent by some model::
 | 
						|
 | 
						|
    from django.db.models.signals import pre_save
 | 
						|
    from django.dispatch import receiver
 | 
						|
    from myapp.models import MyModel
 | 
						|
 | 
						|
 | 
						|
    @receiver(pre_save, sender=MyModel)
 | 
						|
    def my_handler(sender, **kwargs):
 | 
						|
        ...
 | 
						|
 | 
						|
The ``my_handler`` function will only be called when an instance of ``MyModel``
 | 
						|
is saved.
 | 
						|
 | 
						|
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
 | 
						|
particular signal.
 | 
						|
 | 
						|
.. _preventing-duplicate-signals:
 | 
						|
 | 
						|
Preventing duplicate signals
 | 
						|
----------------------------
 | 
						|
 | 
						|
In some circumstances, the code connecting receivers to signals may run
 | 
						|
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 email 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::
 | 
						|
 | 
						|
    from django.core.signals import request_finished
 | 
						|
 | 
						|
    request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
 | 
						|
 | 
						|
Defining and sending signals
 | 
						|
============================
 | 
						|
 | 
						|
Your applications can take advantage of the signal infrastructure and provide
 | 
						|
its own signals.
 | 
						|
 | 
						|
Defining signals
 | 
						|
----------------
 | 
						|
 | 
						|
.. class:: Signal([providing_args=list])
 | 
						|
 | 
						|
All signals are :class:`django.dispatch.Signal` instances. The
 | 
						|
``providing_args`` is a list of the names of arguments the signal will provide
 | 
						|
to listeners. This is purely documentational, however, as there is nothing that
 | 
						|
checks that the signal actually provides these arguments to its listeners.
 | 
						|
 | 
						|
For example::
 | 
						|
 | 
						|
    import django.dispatch
 | 
						|
 | 
						|
    pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
 | 
						|
 | 
						|
This declares a ``pizza_done`` signal that will provide receivers with
 | 
						|
``toppings`` and ``size`` arguments.
 | 
						|
 | 
						|
Remember 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.
 | 
						|
 | 
						|
Sending signals
 | 
						|
---------------
 | 
						|
 | 
						|
There are two ways to send signals in Django.
 | 
						|
 | 
						|
.. 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 (which is a class most of the time),
 | 
						|
and may provide as many other keyword arguments as you like.
 | 
						|
 | 
						|
For example, here's how sending our ``pizza_done`` signal might look::
 | 
						|
 | 
						|
    class PizzaStore(object):
 | 
						|
        ...
 | 
						|
 | 
						|
        def send_pizza(self, toppings, size):
 | 
						|
            pizza_done.send(sender=self.__class__, 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.
 | 
						|
 | 
						|
.. versionadded:: 1.8
 | 
						|
 | 
						|
    The tracebacks are present on the ``__traceback__`` attribute
 | 
						|
    of the errors returned when calling ``send_robust()``.
 | 
						|
 | 
						|
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.
 |