위 포스팅은 다음 링크의 글을 번역한 것입니다. 

How to Create Django Signals





Django Signals은 특정 이벤트가 발생할 때 응용 프로그램에 알릴 수있는 전략입니다. 특정 모델 인스턴스가 업데이트 될 때마다 캐시 페이지를 무효화하려는 경우 코드 기반에서, 이 모델을 업데이트 할 수있는 위치가 여러곳 있다고 가정해 보겠습니다. 이 특정 모델의 save메소드가 실행이 될 때마다 실행될 코드 일부를 연결하여 Signals를 사용하여 이를 수행 할 수 있습니다.


 또 다른 일반적인 사용 사례는 일대일 관계를 통해 프로필 전략을 사용하여 사용자 Custom Django 사용자를 확장 한 경우입니다. 우리가 일반적으로하는 일은 "Signal dispatcher"를 사용하여 사용자의 post_save 이벤트를 수신하여 프로필 인스턴스도 업데이트하는 것입니다. 다른 게시물에서이 사례를 다뤘습니다. 여기에서 읽을 수 있습니다 : 장고 사용자 모델을 확장하는 방법.


이 튜토리얼에서는 기본 제공 신호를 소개하고 모범 사례에 대한 일반적인 조언을 제공합니다.




언제 사용해야 하는가 ?


우리가 더 나아가기 전에, 우리가 언제 사용하는지 알아야 합니다. 


- 많은 코드의 조각들이 같은 이벤트에 연결되어 있을때 (interested 를 연결로 의역) 

- 분리된 어플리케이션들의 상호작용이 필요할때

      - A Django Core model

- A model Defined by a third-part app 





어떻게 작동하는가 ?


Observer Design Pattern에 익숙하다면, 장고가 그것을 어떻게 구현하는지 알 수 있습니다. 동일한 목적으로 사용됩니다.


Signals 시스템에는 '송신자(senders)'와 '수신자(receivers)'라는 두 가지 핵심 요소가 있습니다. 이름에서 알 수 있듯이 Senders는 신호를 전달하는 책임자이고 Receivers 는이 신호를 수신 한 다음 무언가를 수행하는 객체입니다.


- Receivers는 신호를 수신하는 함수 또는 인스턴스 메소드이여야 합니다.

- Senders는 Sender로 부터 이벤트를 받으려면 Python 개체이거나 None이어야합니다.


Sender와 Receiver 사이의 연결은 connect 메소드를 통해 Signal의 인스턴스 인 "signal dispatcher"를 통해 수행됩니다.


Django Core는 또한 ModelSignal을 정의합니다.이 ModelSignal은 Sender가 app_label.ModelName 형식의 문자열로 지연 지정되도록 허용하는 Signal의 하위 클래스입니다. 하지만 일반적으로 Signal 클래스를 사용하여 사용자 정의 신호를 생성하려고합니다.


따라서 신호를 수신하려면 Signal.connect () 메서드를 사용하여 신호를 보낼 때 호출되는 수신기 함수를 등록해야합니다.





사용법


post_save 의 built-in Signal 에 대해 살펴 보겠습니다. 그 코드는 django.db.models.signals 모듈에 있습니다. 이 특별한 Signal은 save 메소드를 실행한 모델이 끝난 직후에 발생합니다.

from django.contrib.auth.models import User
from django.db.models.signals import post_save

def save_profile(sender, instance, **kwargs):
    instance.profile.save()

post_save.connect(save_profile, sender=User)

위 예제에서 save_profile은 리시버 함수이고, User는 보낸 사람이고 post_save는 신호입니다. 사용자 인스턴스가 save 메소드의 실행을 완료 할 때마다 save_profile 함수가 실행됩니다.


post_save.connect (save_profile)와 같이 송신자 인자를 입력하지 않는다면, save_profile 함수는 Django 모델이 save 메소드를 실행한 후에 실행될 것입니다.


신호를 등록하는 또 다른 방법은 @receiver 데코레이터를 사용하는 것입니다.

def receiver(signal, **kwargs)

signal 매개 변수는 Signal 인스턴스 또는 Signal 인스턴스의 List/Tuple 일 수 있습니다.


아래 예를 참조하십시오.

from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
    instance.profile.save()


수신기 기능을 여러 신호에 등록하려면 다음과 같이하십시오.

@receiver([post_save, post_delete], sender=User)



코드는 어디에 있어야합니까?


응용 프로그램의 signal를 등록하는 위치에 따라 코드를 가져 오기 때문에 몇 가지 부작용이 발생할 수 있습니다. 따라서 모델 모듈 또는 응용 프로그램 루트 모듈에 두는 것을 피하는 것이 좋습니다.


Django 문서는 앱 구성 파일에 신호를 넣도록 조언합니다. profile이라는 Django 앱을 고려할 때 평소에하는 작업입니다


profiles/signals.py :


from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

from cmdbox.profiles.models import Profile

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

profiles/app.py :

from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _

class ProfilesConfig(AppConfig):
    name = 'cmdbox.profiles'
    verbose_name = _('profiles')

    def ready(self):
        import cmdbox.profiles.signals  # noqa

profiles/__init__.py :

default_app_config = 'cmdbox.profiles.apps.ProfilesConfig'

위 예제에서 @receiver () 데코레이터를 사용하기 때문에 ready () 메서드 내에서 signals 모듈을 가져 오는 것만으로 작동합니다. connect () 메서드를 사용하여 리시버 함수를 연결하는 경우 아래 예제를 참조하십시오.

from cmdbox.profiles.models import Profile

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

profiles/signals.py:

from django.apps import AppConfig
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _

from cmdbox.profiles.signals import create_user_profile, save_user_profile

class ProfilesConfig(AppConfig):
    name = 'cmdbox.profiles'
    verbose_name = _('profiles')

    def ready(self):
        post_save.connect(create_user_profile, sender=User)
        post_save.connect(save_user_profile, sender=User)

Note : INSTALLED_APPS 설정에서 이미 AppConfig를 참조하고 있다면 profiles / __ init__.py 세팅은 필요하지 않습니다.

default_app_config = 'cmdbox.profiles.apps.ProfilesConfig'


그 외 내장 Signal 함수를 찾고 싶다면 장고 문서를 참조해 주세요.