django 프로젝트에서 시그널 핸들러는 어디에 있어야합니까?


143

장고 프로젝트에서 신호 리스너를 구현하기 시작했습니다. 나는 그들이 무엇이며 어떻게 사용하는지 이해합니다. 어디에 두어야하는지 알아내는 데 어려움을 겪고 있습니다. django 사이트의 문서에는 다음과 같은 내용이 있습니다.

이 코드는 어디에 살아야합니까?

신호 처리 및 등록 코드를 원하는 곳에 배치 할 수 있습니다. 그러나 신호를 전송하기 전에 신호 처리를 등록 할 수 있도록 모듈이있는 모듈을 조기에 가져와야합니다. 이로 인해 앱의 models.py가 신호 처리기 등록에 적합한 장소입니다.

그것의 좋은 제안이지만, models.py에 비 모델 클래스 또는 메소드를 갖는 것은 나에게 잘못된 길을 문지릅니다.

그렇다면 신호 처리기를 저장하고 등록하는 가장 좋은 방법 / 규칙은 무엇입니까?

답변:


41

실제로 모델 자체의 클래스 메소드를 만들고 싶습니다. 모든 클래스를 하나의 클래스로 유지하므로 가져 오기에 대해 걱정할 필요가 없습니다.


2
그리고 일반적으로 핸들러를 신호에 어디에 연결합니까?
DataGreed

1
@DataGreed : 관련 models.py의 맨 아래에 있습니다.
Daniel Roseman

102
해당 모델에서 방출되는 신호를 듣고 모든 청취자를 배치하면 전체 운동이 의미가 없습니다. 그렇지 않습니까? 신호의 지점은 분리됩니다. 리스너가이 원격 이벤트에 관심이있는 코드와 함께 살아서는 안됩니까? 문제는 이미 터 앞에 리스너가로드되도록하는 방법입니다.
John Mee

제 경우에는의 Foo일부인 모델의 신호를 듣고 싶습니다 fooapp. 그러나 신호 수신기는 확장 기능이며 다른 앱 (예 otherapp:)에 있습니다.
guettli

2
John Mee의 요점은 save () 등을 재정의하는 것과 크게 다르지 않습니다.
Matt

246

이것은 Django 1.7 이 릴리스 되었을 때 문서 에 추가 되었습니다.

엄밀히 말하면 신호 처리 및 등록 코드는 원하는 곳 어디에서나 살 수 있지만 코드 가져 오기의 부작용을 최소화하기 위해 응용 프로그램의 루트 모듈과 모델 모듈을 피하는 것이 좋습니다.

실제로, 신호 처리기는 일반적으로 관련 응용 프로그램의 신호 하위 모듈에 정의됩니다. 신호 수신기는 애플리케이션 구성 클래스의 ready () 메소드로 연결됩니다. receiver () 데코레이터를 사용한다면, ready () 안에 신호 서브 모듈을 가져 오기만하면됩니다.

Django 1.7에서 변경 : ready ()가 이전 버전의 Django에 존재하지 않았기 때문에 신호 등록은 일반적으로 models 모듈에서 발생했습니다.

모범 사례는 handlers.py에서 신호 하위 모듈의 핸들러를 정의하는 것입니다 (예 : 다음과 같은 파일).

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

신호 처리기를 등록하는 가장 좋은 장소는 ready () 메소드를 사용하여이를 정의하는 앱의 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

settings.py의 INSTALLED_APPS 또는 __init__앱 에서 직접 지정하여 AppConfig를로드하고 있는지 확인하십시오 . 자세한 내용은 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. 핸들러에서 신호를 분리하면 상태가 깨끗해집니다.

장고 1.6에 대한 지침 :

여전히 Django 1.6 또는 그 이하 버전에 머물러 있다면 AppConfig를 사용하는 대신 동일한 작업을 수행하지만 (app / signals / handlers.py에서 핸들러 정의) __init__.py of 앱과 같은 것 :

yourapp / __ init__.py

import signals

ready () 메소드를 사용하는 것만 큼 좋지는 않습니다. 종종 순환 가져 오기 문제가 발생하기 때문입니다.


3
documentaiton가 준비 무시 말하는 것처럼, 당신이 장고 어느 경우에 () .ready 슈퍼 같은 (ReportsConfig, 자기를) 수행 할 수 있습니다합니다 (1.7.0의가 현재 비어로) 뭔가 () 준비 채울하기로 결정
W- -

3
수입의 부작용을 해결할 수있는 유일한 방법이기 때문에이 답변이 최선이라고 생각합니다. 나는 이런 종류의 부작용으로 인해 정확히 깨지는 응용 프로그램을 정리하고 있기 때문에 모범 사례를 찾기 위해 여기에 왔습니다. 아아아 응용 프로그램이 django 1.6에서 실행되고 있으며 모범 사례는 django 1.7에서만 작동합니다. __init__가져 오기 신호 를 허용하는 임시 해결 방법은 저에게 효과적이지 않으므로 나중에 장고 버전으로 업그레이드 할 준비가 될 때까지 신호를 가져올 수있는 다른 곳이 있는지 궁금합니다.
kasperd

from . import handlers(또는 비슷한) 없어야 yourapp/signals/__init__.py합니까?
dhobbs

또한 handlers.py 모듈을 어딘가에 가져 와서는 안됩니까? 나는 이것을 시도하고 있으며 신호 처리기를 정의하지 않는 것 같습니다.
안드레스

1
fwiw 나는 yourproject.TaskConfig 클래스 코드 블록의 마지막 줄에 필요하지 않았습니다 . 그래서이 품질 보증 : 고려, 정확히이 구조로이 작업을 가지고
그렉 Kaleka

40

나는 단지 이것을 만났고 신호가 모델과 관련이 없으므로 솔루션을 추가 할 것이라고 생각했습니다.

로그인 / 로그 아웃 주위에 다양한 데이터를 기록하고 있으며 연결해야했습니다 django.contrib.auth.signals.

신호 처리기를 signals.py파일에 넣고 __init__.py모듈 파일 에서 신호를 가져 왔습니다 . 앱이 시작 되 자마자 호출된다고 생각 print하기 때문에 (설정 파일을 읽기 전에도 호출되었음을 암시합니다.)

# /project/__init__.py
import 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)에 익숙하지 않으므로 이것이 끔찍한 아이디어라고 말하는 사람에게 열려 있습니다!


3
논리적으로 느껴지지만 앱 수준에서 제안하는 것이 좋습니다.
Nils

2
주의해서이 논리는 중복 신호가 발생 될 가능성이 높습니다. user_logged_in.connect(on_logged_in)아마도 dispatch_uid논쟁에 빠져있을 것 입니다. docs.djangoproject.com/en/dev/topics/signals/… 에서 자세히 알아보십시오 .
Scott Coates

알고 주셔서 감사합니다. 이 방법 (IP / 사용자 에이전트 기록)을 사용하여 모든 로그인을 기록하고 있으며 지금까지 복제본이 없었습니다.
Hugo Rodger-Brown

13

최근에 프로젝트 / 응용 프로그램을 배치 할 때 모범 사례에 대한 기사를 읽었 으며 모든 사용자 정의 디스패처 신호가라는 파일로 이동해야한다고 제안합니다 signals.py. 그러나 여전히 어딘가에 가져와야하고 더 일찍 가져올수록 문제가 완전히 해결되지는 않습니다.

모델 제안은 좋은 것입니다. signals.py파일의 모든 것을 이미 정의 했으므로 파일 맨 위에 줄을 넘지 않아야합니다. admin.py신호를 정의한 다음 동일한 파일에 연결 하면 파일이 배치 되는 방식과 비슷합니다 (맨 위의 클래스 정의와 맨 아래의 모든 사용자 지정 관리 클래스를 등록하는 코드 포함).

희망이 도움이됩니다! 궁극적으로 그것은 당신이 선호하는 것에 달려 있습니다.


1
또한 신호 처리기를 signals.py파일 에 넣고 싶었지만 나중에 어떻게 호출해야하는지 몰랐습니다. 내 models.py파일 로 가져 와서 models.py 파일을 "오염"시키지 않고 매우 깨끗한 솔루션을 얻었습니다. 감사합니다! :)
Danilo Bargen

10
이 크로스 수입이 : models.py에서 수입 모델에 signals.py 시도는
이반 Virabyan

8

각 앱의 models.py 및 signals.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에 넣을 수 있습니다. 모델과 신호에 혼란이 없습니다.

그것이 또 다른 해결책을 제공하기를 바랍니다.


1
그래서 신호는 무엇입니까? py? 귀하의 예에서 보이는 것은 사용자 정의 신호 일뿐입니다. 일반적으로 맞춤형 신호가 없으므로 신호와 커넥터를 결합합니다.
dalore

@dalore 네, 모든 커스텀 시그널은 signal.py에 들어갑니다. 우리는 많은 맞춤형 신호를 가지고 있습니다. 그러나 많은 것이 없다면이 파일은 생략 될 수 있습니다.
사무엘

@dal과 같은 질문
olleh

1
이 모든 것이 이제는 오래된 조언이므로, django 방법은 appconfig를 사용하여 신호 핸들러가있는 핸들러를 가져 오는 것입니다. 그리고
signs.py에서

3

모든 모델이 정의 된 후에 signals.pyIn 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 에 유지하는 데 아무런 문제가 없습니다 . 그러나이 방법으로 더 관리하기 쉽습니다.

도움이 되었기를 바랍니다!!


신호 핸들러를 "signals.py"에 넣습니다. 이름을 "handlers.py"로 지정하면
Abdul Fatah

1
파일 이름을 signals.py 또는 handler.py로 지정하는지는 중요하지 않습니다. 그것은 단지 규칙이 아닌 관습입니다.
18:05에 allsyed

3

에 대한 작은 알림 AppConfig. 설정하는 것을 잊지 마십시오 :

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.