Fixed #8326: added signals documentation.
Thanks to MercuryTide's signal whitepaper from 2006 (http://www.mercurytide.co.uk/whitepapers/django-signals/) for inspiration and ideas for organization, and to the folks who got the Signals wiki page together for some of the content. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8590 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
378f5ddb5a
commit
6f29ad31b5
|
@ -208,5 +208,6 @@ More information
|
|||
:maxdepth: 1
|
||||
|
||||
settings
|
||||
signals
|
||||
upgrade
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
.. _ref-contrib-comments-signals:
|
||||
|
||||
================================
|
||||
Signals sent by the comments app
|
||||
================================
|
||||
|
||||
.. module:: django.contrib.comments.signals
|
||||
:synopsis: Signals sent by the comment module.
|
||||
|
||||
The comment app sends a series of :ref:`signals <topics-signals>` to allow for
|
||||
comment moderation and similar activities. See :ref:`the introduction to signals
|
||||
<topics-signals>` for information about how to register for and receive these
|
||||
signals.
|
||||
|
||||
comment_will_be_posted
|
||||
======================
|
||||
|
||||
.. data:: django.contrib.comments.signals.comment_will_be_posted
|
||||
|
||||
Sent just before a comment will be saved, after it's been sanity checked and
|
||||
submitted. This can be used to modify the comment (in place) with posting
|
||||
details or other such actions.
|
||||
|
||||
If any receiver returns ``False`` the comment will be discarded and a 403 (not
|
||||
allowed) response will be returned.
|
||||
|
||||
This signal is sent at more or less the same time (just before, actually) as the
|
||||
``Comment`` object's :data:`~django.db.models.signals.pre_save` signal.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The comment model.
|
||||
|
||||
``comment``
|
||||
The comment instance about to be posted. Note that it won't have been
|
||||
saved into the database yet, so it won't have a primary key, and any
|
||||
relations might not work correctly yet.
|
||||
|
||||
``request``
|
||||
The :class:`~django.http.HttpRequest` that posted the comment.
|
||||
|
||||
comment_was_posted
|
||||
==================
|
||||
|
||||
.. data:: django.contrib.comments.signals.comment_was_posted
|
||||
|
||||
Sent just after the comment is saved.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The comment model.
|
||||
|
||||
``comment``
|
||||
The comment instance that was posted. Note that it will have already
|
||||
been saved, so if you modify it you'll need to call
|
||||
:meth:`~django.db.models.Model.save` again.
|
||||
|
||||
``request``
|
||||
The :class:`~django.http.HttpRequest` that posted the comment.
|
||||
|
||||
comment_was_flagged
|
||||
===================
|
||||
|
||||
Sent after a comment was "flagged" in some way. Check the flag to see if this
|
||||
was a user requesting removal of a comment, a moderator approving/removing a
|
||||
comment, or some other custom user flag.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The comment model.
|
||||
|
||||
``comment``
|
||||
The comment instance that was posted. Note that it will have already
|
||||
been saved, so if you modify it you'll need to call
|
||||
:meth:`~django.db.models.Model.save` again.
|
||||
|
||||
``flag``
|
||||
The :class:`~django.contrib.comments.models.CommentFlag` that's been
|
||||
attached to the comment.
|
||||
|
||||
``created``
|
||||
``True`` if this is a new flag; ``False`` if it's a duplicate flag.
|
||||
|
||||
``request``
|
||||
The :class:`~django.http.HttpRequest` that posted the comment.
|
|
@ -9,13 +9,14 @@ API Reference
|
|||
contrib/index
|
||||
databases
|
||||
django-admin
|
||||
files/index
|
||||
forms/index
|
||||
generic-views
|
||||
middleware
|
||||
models/index
|
||||
request-response
|
||||
settings
|
||||
signals
|
||||
templates/index
|
||||
unicode
|
||||
files/index
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
.. _ref-signals:
|
||||
|
||||
=========================
|
||||
Built-in signal reference
|
||||
=========================
|
||||
|
||||
A list of all the signals that Django sends.
|
||||
|
||||
.. seealso::
|
||||
|
||||
The :ref:`comment framework <ref-contrib-comments-index>` sends a :ref:`set
|
||||
of comment-related signals <ref-contrib-comments-signals>`.
|
||||
|
||||
Model signals
|
||||
=============
|
||||
|
||||
.. module:: django.db.models.signals
|
||||
:synopsis: Signals sent by the model system.
|
||||
|
||||
The :mod:`django.db.models.signals` module defines a set of signals sent by the
|
||||
module system.
|
||||
|
||||
.. warning::
|
||||
|
||||
Many of these signals are sent by various model methods like
|
||||
:meth:`~django.db.models.Model.__init__` or
|
||||
:meth:`~django.db.models.Model.save` that you can overwrite in your own
|
||||
code.
|
||||
|
||||
If you override these methods on your model, you must call the parent class'
|
||||
methods for this signals to be sent.
|
||||
|
||||
pre_init
|
||||
--------
|
||||
|
||||
.. data:: django.db.models.signals.pre_init
|
||||
|
||||
Whenever you instantiate a Django model,, this signal is sent at the beginning
|
||||
of the model's :meth:`~django.db.models.Model.__init__` method.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The model class that just had an instance created.
|
||||
|
||||
``args``
|
||||
A list of positional arguments passed to
|
||||
:meth:`~django.db.models.Model.__init__`:
|
||||
|
||||
``kwargs``
|
||||
A dictionary of keyword arguments passed to
|
||||
:meth:`~django.db.models.Model.__init__`:.
|
||||
|
||||
For example, the :ref:`tutorial <intro-tutorial01>` has this line:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
p = Poll(question="What's up?", pub_date=datetime.now())
|
||||
|
||||
The arguments sent to a :data:`pre_init` handler would be:
|
||||
|
||||
========== ===============================================================
|
||||
Argument Value
|
||||
========== ===============================================================
|
||||
``sender`` ``Poll`` (the class itself)
|
||||
|
||||
``args`` ``[]`` (an empty list because there were no positional
|
||||
arguments passed to ``__init__``.)
|
||||
|
||||
``kwargs`` ``{'question': "What's up?", 'pub_date': datetime.now()}``
|
||||
========== ===============================================================
|
||||
|
||||
post_init
|
||||
---------
|
||||
|
||||
.. data:: django.db.models.signals.post_init
|
||||
|
||||
Like pre_init, but this one is sent when the :meth:`~django.db.models.Model.__init__`: method finishes.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
As above: rhe model class that just had an instance created.
|
||||
|
||||
``instance``
|
||||
The actual instance of the model that's just been created.
|
||||
|
||||
pre_save
|
||||
--------
|
||||
|
||||
.. data:: django.db.models.signals.pre_save
|
||||
|
||||
This is sent at the beginning of a model's :meth:`~django.db.models.Model.save`
|
||||
method.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The model class.
|
||||
|
||||
``instance``
|
||||
The actual instance being saved.
|
||||
|
||||
post_save
|
||||
---------
|
||||
|
||||
.. data:: django.db.models.signals.post_save
|
||||
|
||||
Like :data:`pre_save`, but sent at the end of the
|
||||
:meth:`~django.db.models.Model.save` method.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The model class.
|
||||
|
||||
``instance``
|
||||
The actual instance being saved.
|
||||
|
||||
``created``
|
||||
A boolean; ``True`` if a new record was create.
|
||||
|
||||
pre_delete
|
||||
----------
|
||||
|
||||
.. data:: django.db.models.signals.pre_delete
|
||||
|
||||
Sent at the beginning of a model's :meth:`~django.db.models.Model.delete`
|
||||
method.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The model class.
|
||||
|
||||
``instance``
|
||||
The actual instance being saved.
|
||||
|
||||
post_delete
|
||||
-----------
|
||||
|
||||
.. data:: django.db.models.signals.post_delete
|
||||
|
||||
Like :data:`pre_delete`, but sent at the end of the
|
||||
:meth:`~django.db.models.Model.delete` method.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The model class.
|
||||
|
||||
``instance``
|
||||
The actual instance being saved.
|
||||
|
||||
Note that the object will no longer be in the database, so be very
|
||||
careful what you do with this instance
|
||||
|
||||
class_prepared
|
||||
--------------
|
||||
|
||||
.. data:: django.db.models.signals.class_prepared
|
||||
|
||||
Sent whenever a model class has been "prepared" -- that is, once model has
|
||||
been defined and registered with Django's model system. Django uses this
|
||||
signal internally; it's not generally used in third-party applications.
|
||||
|
||||
Arguments that are sent with this signal:
|
||||
|
||||
``sender``
|
||||
The model class which was just prepared.
|
||||
|
||||
Management signals
|
||||
==================
|
||||
|
||||
Signals sent by :ref:`django-admin <ref-django-admin>`.
|
||||
|
||||
post_syncdb
|
||||
-----------
|
||||
|
||||
.. data:: django.db.models.signals.post_syncdb
|
||||
|
||||
Sent by :djadmin:`syncdb` after it installs an application.
|
||||
|
||||
Any handlers that listen to this signal need to be written in a particular
|
||||
place: a ``management`` module in one of your :setting:`INSTALLED_APPS`. If
|
||||
handlers are registered anywhere else they may not be loaded by
|
||||
:djadmin:`syncdb`.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The ``models`` module that was just installed. That is, if
|
||||
:djadmin:`syncdb` just installed an app called ``"foo.bar.myapp"``,
|
||||
``sender`` will be the ``foo.bar.myapp.models`` module.
|
||||
|
||||
``app``
|
||||
Same as ``sender``.
|
||||
|
||||
``created_models``
|
||||
A list of the model classes from any app which :djadmin:`syncdb` has
|
||||
created so far.
|
||||
|
||||
``verbosity``
|
||||
Indicates how much information manage.py is printing on screen. See
|
||||
the :djadminopt:`--verbosity`` flag for details.
|
||||
|
||||
Functions which listen for :data:`post_syncdb` should adjust what they
|
||||
output to the screen based on the value of this argument.
|
||||
|
||||
``interactive``
|
||||
If ``interactive`` is ``True``, it's safe to prompt the user to input
|
||||
things on the command line. If ``interactive`` is ``False``, functions
|
||||
which listen for this signal should not try to prompt for anything.
|
||||
|
||||
For example, the :mod:`django.contrib.auth` app only prompts to create a
|
||||
superuser when ``interactive`` is ``True``.
|
||||
|
||||
Request/response signals
|
||||
========================
|
||||
|
||||
.. module:: django.core.signals
|
||||
:synopsis: Core signals sent by the request/response system.
|
||||
|
||||
Signals sent by the core framework when processing a request.
|
||||
|
||||
request_started
|
||||
---------------
|
||||
|
||||
.. data:: django.core.signals.request_started
|
||||
|
||||
Sent when Django begins processing an HTTP request.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The handler class -- i.e.
|
||||
:class:`django.core.handlers.modpython.ModPythonHandler` or
|
||||
:class:`django.core.handlers.wsgi.WsgiHandler` -- that handled
|
||||
the request.
|
||||
|
||||
request_finished
|
||||
----------------
|
||||
|
||||
.. data:: django.core.signals.request_finished
|
||||
|
||||
Sent when Django finishes processing an HTTP request.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The handler class, as above.
|
||||
|
||||
got_request_exception
|
||||
---------------------
|
||||
|
||||
.. data:: django.core.signals.got_request_exception
|
||||
|
||||
This signal is sent whenever Django encounters an exception while processing an incoming HTTP request.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
``sender``
|
||||
The handler class, as above.
|
||||
|
||||
``request``
|
||||
The :class:`~django.http.HttpRequest` object.
|
||||
|
||||
Test signals
|
||||
============
|
||||
|
||||
.. module:: django.test.signals
|
||||
:synopsis: Signals sent during testing.
|
||||
|
||||
Signals only sent when :ref:`running tests <topics-testing>`.
|
||||
|
||||
template_rendered
|
||||
-----------------
|
||||
|
||||
.. data:: django.test.signals.template_rendered
|
||||
|
||||
Sent when the test system renders a template. This signal is not emitted during
|
||||
normal operation of a Django server -- it is only available during testing.
|
||||
|
||||
Arguments sent with this signal:
|
||||
|
||||
sender
|
||||
The :class:`~django.template.Template` object which was rendered.
|
||||
|
||||
template
|
||||
Same as sender
|
||||
|
||||
context
|
||||
The :class:`~django.template.Context` with which the template was
|
||||
rendered.
|
|
@ -22,4 +22,5 @@ Introductions to all the key parts of Django you'll need to know:
|
|||
i18n
|
||||
pagination
|
||||
serialization
|
||||
settings
|
||||
settings
|
||||
signals
|
|
@ -0,0 +1,176 @@
|
|||
.. _topics-signals:
|
||||
|
||||
=======
|
||||
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 :ref:`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 is called.
|
||||
|
||||
|
||||
* :data:`django.core.signals.request_started` &
|
||||
:data:`django.core.signals.request_finished`
|
||||
|
||||
Sent when Django starts or finishes an HTTP request.
|
||||
|
||||
See the :ref:`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. 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
|
||||
------------------
|
||||
|
||||
First, we need to define a receiver function. A receiver can be any Python function or method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
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
|
||||
-----------------------------
|
||||
|
||||
Next, we'll need to connect our receiver to the signal:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.core.signals import request_finished
|
||||
|
||||
request_finished.connect(my_callback)
|
||||
|
||||
Now, our ``my_callback`` function will be called each time a request finishes.
|
||||
|
||||
.. admonition:: Where should this code live?
|
||||
|
||||
You can put signal handling and registration code anywhere you like.
|
||||
However, you'll need to make sure that the module it's in gets imported
|
||||
early on so that the signal handling gets registered before any signals need
|
||||
to be sent. This makes your app's ``models.py`` a good place to put
|
||||
registration of signal handlers.
|
||||
|
||||
Connecting to signals sent by specific senders
|
||||
----------------------------------------------
|
||||
|
||||
Some signals get sent many times, but you'll only be interested in recieving 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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.db.models.signals import pre_save
|
||||
from myapp.models import MyModel
|
||||
|
||||
def my_handler(sender, **kwargs):
|
||||
...
|
||||
|
||||
pre_save.connect(my_handler, sender=MyModel)
|
||||
|
||||
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 :ref:`built-in signal documentation <ref-signals>` for details of each
|
||||
particular signal.
|
||||
|
||||
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.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
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
|
||||
---------------
|
||||
|
||||
.. method:: Signal.send(sender, **kwargs)
|
||||
|
||||
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.
|
||||
|
||||
For example, here's how sending our ``pizza_done`` signal might look:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class PizzaStore(object):
|
||||
...
|
||||
|
||||
def send_pizza(self, toppings, size):
|
||||
pizza_done.send(sender=self, toppings=toppings, size=size)
|
||||
...
|
||||
|
||||
|
Loading…
Reference in New Issue