Где должны жить обработчики сигналов в проекте django?

Я только начал реализовывать прослушиватели сигналов в проекте django. Пока я понимаю, что это такое и как ими пользоваться. Мне трудно понять, куда их положить. Документация с сайта django имеет это, чтобы сказать:

где должен жить этот код?

вы можете положить обработку сигнала и регистрационный код где угодно. Тем не менее, вы должны убедиться, что модуль это импортируется ранний так что обработка сигнала получает зарегистрирован перед любыми сигналами отправляемый. Это делает ваше приложение models.py хорошее место, чтобы положить Регистрация обработчиков сигналов.

в то время как его хорошее предложение, имея не модельные классы или методы в моем models.py просто раздражает меня не так.

Итак, какова наилучшая практика / правило для хранения и регистрации обработчиков сигналов?

7 ответов


Мне действительно нравится делать их classmethods самой модели. Это держит все в пределах одного класса и означает, что вам не нужно беспокоиться об импорте чего-либо.


это было добавлено к документация, когда Джанго 1.7 был освобожден:

строго говоря, обработка сигналов и регистрационный код могут жить где угодно, хотя рекомендуется избегать корневого модуля приложения и его модуля моделей для минимизации побочных эффектов импорта кода.

на практике обработчики сигналов обычно определяются в подмодуле сигналов приложения, к которому они относятся. Сигнал приемники подключаются в методе ready () класса конфигурации приложения. Если вы используете декоратор receiver (), просто импортируйте подмодуль сигналов внутри ready ().

изменено в Django 1.7: поскольку ready () не существовал в предыдущих версиях Django, Регистрация сигнала обычно происходила в модуле models.

Лучшая практика заключается в определении ваших обработчиков в handlers.py в подмодуле signals, например, файл, который выглядит например:

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

лучшее место для регистрации обработчика сигнала находится в AppConfig приложения, которое его определяет, используя готово() метод. Это будет выглядеть так:

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

убедитесь, что вы загружаете AppConfig, указав его либо непосредственно в вашем settings.py ' S INSTALLED_APPS, или в __init__ приложения. Видеть см. документацию ready () для получения дополнительной информации.

Примечание: если вы предоставляете сигналы для других приложений, чтобы слушать тоже, поместите их в __init__ в вашем модуле сигналов, например, файл, который выглядит как:

yourapp/signals/__init__.py

import django.dispatch

task_generate_pre_save = django.dispatch.Signal(providing_args=["task"])

другое приложение может прослушивать ваш сигнал, импортируя и регистрируя его, например from yourapp.signals import task_generate_pre_save. Отделяя ваши сигналы от ваших обработчиков сохраняет вещи чистый.

инструкции для Django 1.6:

если вы все еще застряли на Django 1.6 или ниже, то вы сделаете то же самое (определите свои обработчики в yourapp/signals/handlers.py) но вместо того, чтобы использовать AppConfig, вы бы загрузили обработчики через __init__.py вашего приложения, например, что-то вроде:

yourapp/__init__.py

import signals

это не так приятно, как использование метода ready (), потому что он часто вызывает круговой вопросы импорта.


Я только что столкнулся с этим, и поскольку мои сигналы не связаны с моделью, я подумал, что добавлю свое решение.

я регистрирую различные данные вокруг входа / выхода из системы и должен подключиться к django.contrib.auth.signals.

Я поместил обработчики сигналов в signals.py файл, а затем импортированные сигналы из __init__.py файл модуля, как я считаю, это называется, как только приложение запускается (тестирование с print оператор предполагает, что он вызывается еще до того, как файл настроек читать.)

# /project/__init__.py
import signals

и в 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)

Я довольно новичок в Django (/python), поэтому открыт для всех, кто говорит мне, что это ужасная идея!


Я только недавно прочитала этой статья о лучших практиках, когда дело доходит до выкладывать ваши проекты/приложения, и это предполагает, что все ваши пользовательские сигналы диспетчера должны идти в файл под названием signals.py. Однако это не полностью решает вашу проблему, так как вам все равно нужно импортировать их где-то, и чем раньше они будут импортированы, тем лучше.

модельное предложение хорошее. Поскольку вы уже определили все в своем signals.py файл, он не должен возьмите больше, чем строку в верхней части файла. Это похоже на то, как admin.py файл выложен (с определениями классов вверху и кодом для регистрации всех пользовательских классов администратора внизу), если вы определяете свои сигналы, то подключите их в том же файле.

надеюсь, что это поможет! В конечном счете все сводится к тому, что вы предпочитаете.


models.py и signals.py в каждом приложении были рекомендованы места для подключения сигналов, однако, они не являются лучшим решением, на мой взгляд, чтобы держать сигналы и обработчики отправлены. Диспетчеризация должна быть причиной сигналов и обработчиков, изобретенных в django.

Я долго боролся, и, наконец, мы нашли решение.

создайте модуль соединителя в папке приложения

Итак, мы имеем:

app/
    __init__.py
    signals.py
    models.py
    connectors.py

in app/connectors.py, мы определили обработчики сигналов и подключаем их. Приведен пример:

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)

затем в models.py, мы добавляем следующую строку в конце файла:

from app import connector

все, что сделано здесь.

таким образом, мы можем поместить сигналы в signals.py, и все обработчики в connectors.py - ... Никакого беспорядка в моделях и сигналах.

надеюсь, что это дает еще одно решение.


Я храню их в отдельном файле signals.py , в models.py после того как все модели были определены. Я импортирую их и подключаю модели к сигналам.

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)

Это обеспечивает мне логическое разделение, конечно, нет ничего плохого в том, чтобы держать их в models.py, но это более управляемо таким образом.

надеюсь, что это помогает!!


небольшое напоминание о AppConfig. Не забудьте установить:

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'