Browse Source

Updated advice on connecting signals at startup.

Aymeric Augustin 11 years ago
parent
commit
c31d7c4813
2 changed files with 33 additions and 15 deletions
  1. 6 0
      docs/ref/signals.txt
  2. 27 15
      docs/topics/signals.txt

+ 6 - 0
docs/ref/signals.txt

@@ -354,6 +354,12 @@ 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.
 
+Since this signal is sent during the app registry population process, and
+:meth:`AppConfig.setup() <django.apps.AppConfig.setup>` runs after the app
+registry is fully populated, receivers cannot be connected in that method.
+One possibility is to connect them ``AppConfig.__init__()`` instead, taking
+care not to import models or trigger calls to the app registry.
+
 Arguments that are sent with this signal:
 
 ``sender``

+ 27 - 15
docs/topics/signals.txt

@@ -48,8 +48,7 @@ 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:
+called when the signal is sent by using the :meth:`Signal.connect` method:
 
 .. method:: Signal.connect(receiver, [sender=None, weak=True, dispatch_uid=None])
 
@@ -115,8 +114,13 @@ manual connect route:
 
     request_finished.connect(my_callback)
 
-Alternatively, you can use a ``receiver`` decorator when you define your
-receiver:
+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:
 
 .. code-block:: python
 
@@ -129,16 +133,25 @@ receiver:
 
 Now, our ``my_callback`` function will be called each time a request finishes.
 
-Note that ``receiver`` can also take a list of signals to connect a function
-to.
 
 .. 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.
+    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.setup` method of your
+    application configuration class. If you're using the :func:`receiver`
+    decorator, simply import the ``signals`` submodule inside
+    :meth:`~django.apps.AppConfig.setup`.
+
+    .. versionchanged:: 1.7
+
+        Since :meth:`~django.apps.AppConfig.setup` didn't exist in previous
+        versions of Django, signal registration usually happened in the
+        ``models`` module.
 
 .. _connecting-to-specific-signals:
 
@@ -178,10 +191,9 @@ particular signal.
 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.
+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