django의 신호 메커니즘인 Signals에 대해 간단히 이야기하다

27774 단어
개술
Django includes a “signal dispatcher” which helps allow decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events.
Django 내부에는 '신호 스케줄러' 가 포함되어 있습니다. 어떤 사건이 프레임워크에서 발생하면 프로그램에 알릴 수 있습니다.간단하게 말하면 이벤트 (이벤트) 가 발생할 때,signals (신호) 는 몇몇 senders (보내는 사람) 가receivers (수신자) 에게 알릴 수 있도록 허용한다.이것은 우리의 여러 개의 독립된 응용 코드가 같은 사건의 발생에 대해 모두 흥미를 느낄 때 특히 유용하다.
2. signal,receiver,sender
2.1 signal
모든 시그널은django입니다.dispatch.Signal 클래스의 인스턴스입니다.Django는 사용자 코드가 이 신호에 미리 연결되어 있으면 프레임 안의 일부 이벤트가 발생할 때 사용자 코드가 알림을 받아서 사용자 코드를 실행할 수 있는 내장된 신호 집합을 제공합니다.다음은 미리 정의된 Django signals 중 일부입니다.
django.db.models.signals.pre_save & django.db.models.signals.post_save
Sent before or after a model’s save() method is called.
django.db.models.signals.pre_delete & django.db.models.signals.post_delete
Sent before or after a model’s delete() method or queryset’s delete() method is called.
django.db.models.signals.m2m_changed
Sent when a ManyToManyField on a model is changed.
django.core.signals.request_started & django.core.signals.request_finished
Sent when Django starts or finishes an HTTP request.
물론 사용자도 signal을 사용자 정의할 수 있다.
For example:
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

This declares a pizza_done signal that will provide receivers with toppings and size arguments.
피자라 정의done의Signal 실례, toppings와size 사전 인자를receivers에 제공합니다.(의문:Signal류의 원본을 보면 개인적으로는 이providing args가'꽃병'이라고 생각하는데 전체 클래스가providing args 속성에 이용된 적이 없는 것 같다. 구두약정처럼receivers가 어떤 파라미터를 얻을 수 있는지,send()가 어떻게 전달되었는지 봐야 한다~, 아시는 소협이 지적해 주세요)
2.2 receiver 및 Signal에 연결하는 방법
receiver는 리셋 함수에 해당하며, 관련 이벤트가 발생하면 실행을 촉발합니다.
def my_callback(sender, **kwargs):
    print "Request finished!"

Notice that the function takes a sender argument, along with wildcard keyword arguments (**kwargs); all signal handlers must take these arguments.
We'll look at senders a bit later, but right now look at the **kwargs argument. All signals send keyword arguments, and may change those keyword arguments at any time. In the case of request_finished, it's documented as sending no arguments, which means we might be tempted to write our signal handling as my_callback (sender).
This would be wrong -- in fact, Django will throw an error if you do so. That's because at any point arguments could get added to the signal and your receiver must be able to handle those new arguments.
위에서 말한 바와 같이 나는 이렇게 이해한다. 우리의 리셋 함수가 천변만화된 매개 변수를 지원할 수 있도록sender+kwargs 사전으로 참조할 수 있다.
그러나 매번 값을 받을 때마다 Kwargs에서 꺼내야 하기 때문에 가독성도 떨어지는 것 같다.개인용법은 함수에서 자주 사용하는 매개 변수를 직접 열거하는 것이다. 예를 들어defmycallback(sender,app,**kwargs):pass.
signal에 Receivers 바인딩
이 점을 실현할 수 있는 두 가지 방법이 있다.수동:
from django.core.signals import request_finished
request_finished.connect(my_callback)

또는 Receiver 장식기를 사용하여 Receiver를 정의할 수 있습니다.
from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print "Request finished!"

지금, 매번 Requestfinished 신호가 알림이 있으면 my 한번 실행합니다callback.
이렇게 설정하면 각종signals에서 보내는 알림을 받을 수 있습니다.그런데 만약에 제 하수가 특정 센더에게만 관심이 있다면 어떡하죠?connect 함수의 sender 매개 변수를 지정하여 필터링할 수 있으며, 장식기 방식으로 필터링하면 다음과 같습니다.
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):
    ...

위의 콜백 함수 myhandler는 MyModel 인스턴스가 저장된 경우에만 호출됩니다.
이외에도 connect 함수에는 dispatch 매개 변수가 있습니다uid (보통 문자열) 는 유일하게 당신의 리셋 함수를 표시하는 데 사용됩니다. 반복적으로 귀속되거나 같은 signal에 리셋 함수를 등록하는 것을 피하기 위해서입니다. 그러면 이벤트가 여러 번 리셋될 수 있습니다.
2.3 sender
사실sender는 매개 변수일 뿐입니다. 위에서 말한 connect 함수 중 선택할 수 있는 매개 변수가 아니라, 신호를 보낼 때sender 매개 변수를 지정해야 합니다. 이것은receiver 함수인 이signal이 도대체 어디에서 왔는지 알려줍니다.예를 들면 다음과 같습니다.
class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self, toppings=toppings, size=size)
        ...

여기, 피자done 신호가 전송되었습니다. sender 파라미터는 PizzaStore의 실례입니다.
Signal 말고는sender(sender,kwargs)로 신호를 보내고,Signal도 사용할 수 있습니다.send_robust(sender,kwargs).차이점은 후자는receiver 리셋 함수의 이상을 포착하고 오류 정보를 함수 리셋 값에 추가합니다.
2.4 기타
메서드Signal.disconnect([receiver=None,sender=None,weak=True,dispatch uid=None])는 signal과 모receiver의 귀속 관계를 해제하는 데 사용됩니다.
셋째, Django에 이미 만들어진 예를 들어보자.
너의 settings에 있다.INSTALLED_APPS에'django'추가contrib.'manage.py syncdb'를 실행하면 데이터베이스에'django content type'이 한 장 더 있고 그 안에 기록이 있을 거예요. 물론 이상한 건 없어요. 표djangocontent_type의 기록은 프로젝트 전체에 설치된 응용 프로그램을 대표합니다.이어서, 너는 다시 settings로 가라.INSTALLED_APPS에서 사용자 정의, news 응용 프로그램을 추가하면 이 news 기록을 표django 에 어떻게 추가합니까content_type 중은요?역시 "manage.py syncdb"!이 실현에는 Django의 signal 메커니즘이 활용되었다.
먼저 signal 정의:
#file:django\db\models\signals.py

from django.dispatch import Signal
post_syncdb = Signal(providing_args=["class", "app", "created_models", 
"verbosity", "interactive"])

post_syncdb는 아래에서 여러 번 사용한 신호입니다.
다음으로 receiver가 Signal에 바인딩됩니다.
#file:django\contrib\contenttypes\management.py(       signal connect     
    management.py    management   __init__.py

from django.db.models import signals
signals.post_syncdb.connect(update_contenttypes)

update_콘텐츠 types 함수는 추가된 응용에 따라djangocontent_type표에 해당하는 기록을 생성합니다.
마지막으로 신호의 촉발:
#file:django\core\management\sql.py

def emit_post_sync_signal(created_models, verbosity, interactive, db):
    # Emit the post_sync signal for every application.
    for app in models.get_apps():
        app_name = app.__name__.split('.')[-2]
        if verbosity >= 2:
            print("Running post-sync handlers for application %s" % app_name)
        models.signals.post_syncdb.send(sender=app, app=app,
            created_models=created_models, verbosity=verbosity,
            interactive=interactive, db=db)

이 함수 emitpost_sync_signal은 바로 관리자입니다.py의 두 가지 명령인syncdb와flush가 호출하여 매번manage.py syncdb는 항상 이렇게 효과가 있다.
이상과 같은 결론은 저의 생각입니다. 잘못된 점이 있으면 과감하게 벽돌을 치십시오~
어이, 여기까지, 여기까지!

좋은 웹페이지 즐겨찾기