41
I actually like to make them classmethods of the model itself. That keeps everything within one class, and means you don’t have to worry about importing anything.
270
This was added to the documentation when Django 1.7 was released:
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 ready() method of your application configuration class. If you’re using the receiver() decorator, simply import the signals submodule inside ready().
Changed in Django 1.7: Since ready() didn’t exist in previous versions of Django, signal registration usually happened in the models module.
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:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
pass
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:
from django.apps import AppConfig
class TasksConfig(AppConfig):
name = 'tasks'
verbose_name = "Tasks"
def ready(self):
import yourproject.yourapp.signals.handlers #noqa
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
import django.dispatch
task_generate_pre_save = django.dispatch.Signal(providing_args=["task"])
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
import signals
This isn’t as nice as using the ready() method because it often causes circular import issues.
- [Django]-Django, Turbo Gears, Web2Py, which is better for what?
- [Django]-Celery missed heartbeat (on_node_lost)
- [Django]-Django: guidelines for speeding up template rendering performance
40
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 a print
statement suggests that it’s called even before the settings file is read.)
# /project/__init__.py
import signals
and in signals.py
# /project/signals.py
from django.contrib.auth.signals import user_logged_in
def on_logged_in(sender, user, request, **kwargs):
print 'User logged in as: \'{0}\''.format(user)
user_logged_in.connect(on_logged_in)
I’m pretty new to Django (/python) so am open to anyone telling me that this is a terrible idea!
- [Django]-Difference between User.objects.create_user() vs User.objects.create() vs User().save() in django
- [Django]-Django model blank=False does not work?
- [Django]-Django: Reverse for 'detail' with arguments '('',)' and keyword arguments '{}' not found
14
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 the admin.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.
- [Django]-Django Background Task
- [Django]-How can I build multiple submit buttons django form?
- [Django]-How to force application version on AWS Elastic Beanstalk
10
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:
app/
__init__.py
signals.py
models.py
connectors.py
in app/connectors.py, we defined signal handlers and connect them. An example is provided:
from signals import example_signal
from models import ExampleModel
from django.db.models.signals import post_save, post_delete
def hanndler(sender, *args, **kwargs):
pass
post_save.connect(hander, sender=ExampleModel)
then in models.py, we add the following line in the end of the file:
from app import connector
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.
- [Django]-How to tell if a task has already been queued in django-celery?
- [Django]-PyCharm: DJANGO_SETTINGS_MODULE is undefined
- [Django]-Duplicate column name
6
Small reminder about AppConfig
. Don’t forget to set:
# yourapp/__init__.py
default_app_config = 'yourapp.apps.RockNRollConfig'
- [Django]-Choose test database?
- [Django]-How do I make many-to-many field optional in Django?
- [Django]-Django models avoid duplicates
3
I keep them in a separate file signals.py
, In models.py
after all models are defined. I import them and connect models to signals.
signals.py
# necessary imports
def send_mail_on_save(<args>):
# code here
models.py
# imports
class mymodel(models.Model):
# model here
# import signals
from signals import send_mail_on_save
# connect them
post_save.connect(send_mail_on_save,sender=mymodel)
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!!
- [Django]-Constructing Django filter queries dynamically with args and kwargs
- [Django]-TransactionManagementError "You can't execute queries until the end of the 'atomic' block" while using signals, but only during Unit Testing
- [Django]-Python Asyncio in Django View