mirror of
				https://github.com/django/django.git
				synced 2025-10-28 16:16:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			284 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| =======
 | |
| 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, register a *receiver* function using the
 | |
| :meth:`Signal.connect` method. The receiver function is called when the signal
 | |
| is sent. All of the signal's receiver functions are called one at a time, in
 | |
| the order they were registered.
 | |
| 
 | |
| .. 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, import the ``signals`` submodule inside
 | |
|     :meth:`~django.apps.AppConfig.ready`.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     The :meth:`~django.apps.AppConfig.ready` method may be executed more than
 | |
|     once during testing, so you may want to :ref:`guard your signals from
 | |
|     duplication <preventing-duplicate-signals>`, especially if you're planning
 | |
|     to send them within tests.
 | |
| 
 | |
| .. _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 as many times for a signal event. For example, the
 | |
| :meth:`~django.apps.AppConfig.ready` method may be executed more than once
 | |
| during testing. More generally, this occurs everywhere your project imports the
 | |
| module where you define the signals, because signal registration runs as many
 | |
| times as it is imported.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| .. admonition:: When to use custom signals
 | |
| 
 | |
|     Signals are implicit function calls which make debugging harder. If the
 | |
|     sender and receiver of your custom signal are both within your project,
 | |
|     you're better off using an explicit function call.
 | |
| 
 | |
| Defining signals
 | |
| ----------------
 | |
| 
 | |
| .. class:: Signal()
 | |
| 
 | |
| All signals are :class:`django.dispatch.Signal` instances.
 | |
| 
 | |
| For example::
 | |
| 
 | |
|     import django.dispatch
 | |
| 
 | |
|     pizza_done = django.dispatch.Signal()
 | |
| 
 | |
| This declares a ``pizza_done`` signal.
 | |
| 
 | |
| 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` (all built-in signals use
 | |
| this) 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:
 | |
|         ...
 | |
| 
 | |
|         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.
 | |
| 
 | |
| 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, dispatch_uid=None)
 | |
| 
 | |
| To disconnect a receiver from a signal, call :meth:`Signal.disconnect`. The
 | |
| arguments are as described in :meth:`.Signal.connect`. The method returns
 | |
| ``True`` if a receiver was disconnected and ``False`` if not.
 | |
| 
 | |
| The ``receiver`` argument indicates the registered receiver to disconnect. It
 | |
| may be ``None`` if ``dispatch_uid`` is used to identify the receiver.
 |