Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
481 views
in Technique[技术] by (71.8m points)

Where should signal handlers live in a django project?

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:

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.

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?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...