I have just started implementing signal listeners in a django project. While I understand what they are and how to use them. I am having a hard time figuring out where I should put them. The documentation from the django site has this to say:
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.
While its a good suggestion, having non model classes or methods in my models.py just rubs me the wrong way.
So then, what is the best practice/rule for storing and registering signal handlers?
Best Answer
This was added to the documentation when Django 1.7 was released:
Best practice is to define your handlers in handlers.py in a signals submodule, e.g. a file that looks like:
yourapp/signals/handlers.py:
The best place to register your signal handler is then in the AppConfig of the app that defines it, using the ready() method. This will look like this:
yourapp/apps.py:
Make sure you're loading your AppConfig by specifying it either directly in your settings.py's INSTALLED_APPS, or in the
__init__
of your app. See see the ready() documentation for more information.Note: If you're providing signals for other apps to listen too as well, put them in the
__init__
in your signals module, e.g. a file that looks like:yourapp/signals/__init__.py
Another app can then listen to your signal by importing and registering it, e.g.
from yourapp.signals import task_generate_pre_save
. Separating your signals from your handlers keeps things clean.Instructions for Django 1.6:
If you're still stuck on Django 1.6 or lower, then you'd do the same thing (define your handlers in yourapp/signals/handlers.py) but rather than using AppConfig, you would load the handlers via the __init__.py of your app, e.g. something like:
yourapp/__init__.py
This isn't as nice as using the ready() method because it often causes circular import issues.