Где должны обработчики сигналов жить в проекте Django? - PullRequest
130 голосов
/ 27 апреля 2010

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

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

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

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

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

Ответы [ 7 ]

219 голосов
/ 08 апреля 2014

Это было добавлено к документации , когда была выпущена Django 1.7 :

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

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

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

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

YourApp / сигналы / 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 приложения, которое его определяет, используя метод ready () . Это будет выглядеть так:

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, указав его либо непосредственно в INSTALLED_APPS вашего settings.py, либо в __init__ вашего приложения. См. см. Документацию ready () для получения дополнительной информации.

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

* * YourApp тысячи сорок один / сигналы / __ __ INIT. Р * ** 1043 тысяча сорок-дв *

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 / signal / handlers.py), но вместо использования AppConfig вы загрузите обработчики через __init__ .py вашего приложения, например что-то вроде:

YourApp / __ __ INIT. Ру

import signals

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

39 голосов
/ 14 июля 2012

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

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

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

# /project/__init__.py
import signals

и в signal.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), поэтому я открыт для всех, кто скажет мне, что это ужасная идея!

39 голосов
/ 27 апреля 2010

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

13 голосов
/ 27 апреля 2010

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

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

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

7 голосов
/ 05 мая 2013

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

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

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

так что мы имеем:

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

в 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

Здесь все сделано.

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

Надеюсь, это даст другое решение.

3 голосов
/ 13 августа 2018

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

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'
2 голосов
/ 25 августа 2016

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

signal.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 , но так легче управлять.

Надеюсь, это поможет !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...