diff --git a/docs/ref/contrib/comments/index.txt b/docs/ref/contrib/comments/index.txt index 1e9418b55a..443c89d3c1 100644 --- a/docs/ref/contrib/comments/index.txt +++ b/docs/ref/contrib/comments/index.txt @@ -208,5 +208,6 @@ More information :maxdepth: 1 settings + signals upgrade diff --git a/docs/ref/contrib/comments/signals.txt b/docs/ref/contrib/comments/signals.txt new file mode 100644 index 0000000000..d3fd85cad5 --- /dev/null +++ b/docs/ref/contrib/comments/signals.txt @@ -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 ` to allow for +comment moderation and similar activities. See :ref:`the introduction to 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. diff --git a/docs/ref/index.txt b/docs/ref/index.txt index ac71175abf..c54cd20954 100644 --- a/docs/ref/index.txt +++ b/docs/ref/index.txt @@ -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 \ No newline at end of file diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt new file mode 100644 index 0000000000..df6097fb82 --- /dev/null +++ b/docs/ref/signals.txt @@ -0,0 +1,294 @@ +.. _ref-signals: + +========================= +Built-in signal reference +========================= + +A list of all the signals that Django sends. + +.. seealso:: + + The :ref:`comment framework ` sends a :ref:`set + of comment-related 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 ` 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 `. + +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 `. + +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. diff --git a/docs/topics/index.txt b/docs/topics/index.txt index 702c02f676..5d83980837 100644 --- a/docs/topics/index.txt +++ b/docs/topics/index.txt @@ -22,4 +22,5 @@ Introductions to all the key parts of Django you'll need to know: i18n pagination serialization - settings \ No newline at end of file + settings + signals \ No newline at end of file diff --git a/docs/topics/signals.txt b/docs/topics/signals.txt new file mode 100644 index 0000000000..6f66b036c7 --- /dev/null +++ b/docs/topics/signals.txt @@ -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 ` 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 ` 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 ` 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) + ... + +