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?
models.py and signals.py in each app have been the recommended places to connect signals, however, they are not the best solution, in my opinion, to keep signals and handlers dispatched. Dispatching should be the reason signals and handlers invented in django.
I was struggling for long time, and finally we figured out the solution.
create a connector module in app folder
so we have:
in app/connectors.py, we defined signal handlers and connect them. An example is provided:
then in models.py, we add the following line in the end of the file:
Everything done here.
In this way, we can put signals in signals.py, and all the handlers in connectors.py. No mess in models and signals.
Hope it provides another solution.
I've only just come across this, and as my signals are not model-related I thought I'd add my solution.
I am logging various data around log in / log out, and needed to hook into
django.contrib.auth.signals
.I have put the signal handlers into a
signals.py
file, and then imported signals from the__init__.py
module file, as I believe this is called as soon as the app starts up (testing with aprint
statement suggests that it's called even before the settings file is read.)and in signals.py
I'm pretty new to Django (/python) so am open to anyone telling me that this is a terrible idea!
I keep them in a separate file
signals.py
, Inmodels.py
after all models are defined. I import them and connect models to signals.signals.py
models.py
This provides me logical separation, of course there is nothing wrong on keeping them in models.py , But it is more manageable this way.
Hope this helps!!
I just recently read this article about best practices when it comes to lay out your projects/applications, and it suggests that all your custom dispatcher signals should go in a file called
signals.py
. However, that doesn't fully solve your problem, since you still need to import these somewhere, and the earlier they get imported the better.The model suggestion is a good one. Since you already defined everything in your
signals.py
file, it shouldn't take more than a line at the top of the the file. This is similar to the way theadmin.py
file is laid out (with class definitions at the top and the code for registering all the custom admin classes at the bottom), if you define your signals then connect them in the same file.Hope that helps! Ultimately it comes down to what you prefer.
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.
Small reminder about
AppConfig
. Don't forget to set: