Django signal 使用總結

本文最先發表於我的博客 Pylixm'wiki-django signal使用總結html

最近在已經開發好的項目上加功能,想到了django的signal,整理記錄以下備查。python

什麼是django的signal

官方文檔描述以下:shell

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

Django內部包含了一位「信號調度員」:當某事件在框架內發生時,它能夠通知到咱們的應用程序。 簡而言之,當event(事件)發生時,signals(信號)容許若干 senders(寄件人)通知一組 receivers(接收者)。這在咱們多個獨立的應用代碼對同一事件的發生都感興趣時,特別有用。app

我的理解,django的signal可理解爲django內部的鉤子,當一個事件發生時,其餘程序可對其做出相關反應,可經過signal來回調定義好的處理函數(receivers),從而更大程度的解耦咱們的系統。框架

最佳使用場景

通知類 

通知是signal最經常使用的場景之一。例如,在論壇中,在帖子獲得回覆時,通知樓主。從技術上來說,咱們能夠將通知邏輯放在回覆保存時,可是這並非一個好的處理方式,這樣會時程序耦合度增大,不利於系統的後期擴展維護。若是咱們在回覆保存時,只發一個簡單的信號,外部的通知邏輯拿到信號後,再發送通知,這樣回覆的邏輯和通知的邏輯作到了分開,後期維護擴展都比較容易。函數

初始化類

信號的另外一個列子即是事件完成後,作一系列的初始化工做。post

其餘一些使用場景總結

如下狀況不要使用signal:ui

  • signal與一個model緊密相關, 並能移到該model的save()時spa

  • signal能使用model manager代替時

  • signal與一個view緊密相關, 並能移到該view中時

如下狀況可使用signal:

  • signal的receiver須要同時修改對多個model時

  • 將多個app的相同signal引到同一receiver中處理時

  • 在某一model保存以後將cache清除時

  • 沒法使用其餘方法, 但須要一個被調函數來處理某些問題時

如何使用

django 的 signal 使用可分爲2個模塊:

  • signal :signal定義及觸發事件

  • receiver : signal 接受函數

內建signal的使用

django 內部有些定義好的signal供咱們使用:

模型相關:

  • pre_save 對象save前觸發

  • post_save 對象save後觸發

  • pre_delete 對象delete前觸發

  • post_delete 對象delete後觸發

  • m2m_changed ManyToManyField 字段更新後觸發

請求相關:

  • request_started 一個request請求前觸發

  • request_finished request請求後觸發

針對django自帶的signal,咱們只須要編寫receiver 便可,使用以下。

第一步,編寫receiver並綁定到signal

myapp/signals/handlers.py

from django.dispatch import receiver
from django.core.signals import request_finished
 
## decorators 方式綁定
@receiver(request_finished, dispatch_uid="request_finished")
def my_signal_handler(sender, **kwargs):
    print("Request finished!================================")

# 普通綁定方式
def my_signal_handler(sender, **kwargs):
    print("Request finished!================================")

request_finished.connect(my_signal_handler)

#####################################################
# 針對model 的signal 
from django.dispatch import receiver
from django.db.models.signals import post_save
 
from polls.models import MyModel
 
 
@receiver(post_save, sender=MyModel, dispatch_uid="mymodel_post_save")
def my_model_handler(sender, **kwargs):
 print('Saved: {}'.format(kwargs['instance'].__dict__))
  • dispatch_uid 確保此receiver 只調用一次

第二步,加載signal

myapp/__init__py

default_app_config = 'myapp.apps.MySendingAppConfig'

myapp/apps.py

from django.apps import AppConfig
 
 
class MyAppConfig(AppConfig):
    name = 'myapp'
 
    def ready(self):
        # signals are imported, so that they are defined and can be used
        import myapp.signals.handlers

到此,當系統受到request 請求完成後,便會執行receiver。

其餘內建的signal,參考官方文檔:
https://docs.djangoproject.com/en/1.9/topics/signals/

自定義signal的使用

自定義signal,須要咱們編寫 signal和 receiver 。

第一步, 編寫signal

myapp.signals.signals.py

import django.dispatch
 
my_signal = django.dispatch.Signal(providing_args=["my_signal_arg1", "my_signal_arg_2"])

第二步,加載signal

myapp/__init__py

default_app_config = 'myapp.apps.MySendingAppConfig'

myapp/apps.py

from django.apps import AppConfig
 
 
class MyAppConfig(AppConfig):
    name = 'myapp'
 
    def ready(self):
        # signals are imported, so that they are defined and can be used
        import myapp.signals.handlers

第三步,事件觸發時,發送signal

myapp/views.py

from .signals.signals import my_signal
 
my_signal.send(sender="some function or class",
               my_signal_arg1="something", my_signal_arg_2="something else"])

自定義的signal,django已經爲咱們編寫了此處的事件監聽。

第四步,收到signal,執行receiver

myapp/signals/handlers.py

from django.dispatch import receiver
from myapp.signals.signals import my_signal
 
 
@receiver(my_signal, dispatch_uid="my_signal_receiver")
def my_signal_handler(sender, **kwargs):
    print('my_signal received')

此時,咱們自定義的signal 便開發完成了。

總結

  • django signal 的處理是同步的,勿用於處理大批量任務。

  • django signal 對程序的解耦、代碼的複用及維護性有很大的幫助。

以上爲我的觀點,若有疑問歡迎交流。

參考

http://sabinemaennel.ch/django/signals-in-django/
https://docs.djangoproject.com/en/1.10/topics/signals/
http://www.weiguda.com/blog/38/
http://www.python88.com/topic/151

相關文章
相關標籤/搜索