23:django 信號(signal)


django包含了一個“信號分配器”使得當一些動作在框架的其他地方發生的時候,解耦的應用可以得到提醒。通俗來講,就是一些動作發生的時候,信號允許特定的發送者去提醒一些接受者,這是特別有用的設計因為有些代碼對某些事件是特別感興趣的,比如刪除動作。

為此,django提供了很多內置的信號,比如一些常用的功能(以幾個在django.db.models.signal目錄下的信號為例):

  • save:pre_save和post_save
  • delete:pre_delete和post_delete
  • change:m2m_changed

如果你想了解更多,可以查閱django的內置信號文檔,本節的最后也會有一個所有內置信號的簡略介紹。

監聽信號

要想接受信號,你首先要注冊一個接收器函數,當信號被Signal.connect()方法發射的時候,這個函數會被調用

Signal.connect(receiver[,sender=None,weak=True,dispatch_uid=None])

參數解釋:

  • receiver:連接到這個信號的回調函數
  • sender:信號的發送者
  • weak:是否是弱引用,默認是真。因此,如果你的接收器是是一個本地函數,會被當做垃圾回收,如果你不想,請在使用connect()方法的時候使用weak=False
  • dispatch_uid:一個唯一的標識符給信號接收器,避免重復的信號被發送

下面讓我們來看一個具體的例子來解釋這些參數吧吧,這個例子以request_finished信號(每個HTTP請求結束的時候會被調用):

回調函數receiver

回調函數可以是一個函數或者方法,比如我們可以這樣定義一個接收器:

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

 

注意的是所有的信號處理器都需要這兩個參數:sender和**kwargs。因為所有的信號都是發送關鍵字參數的,可能你處理的時候沒有任何參數,但不意味着在處理的過程中(在你寫的處理函數之前)有任何的參數生成,如果沒有傳**kwargs參數的話,可能會發生問題;基於這樣的考慮,這兩個參數都是必須的。

連接到你的receiver回調函數

有兩種方法可以把信號和接收器連接到一起:

connect方法

from django.core.signals import request_finished

request_finished.connect(my_callback)

 

裝飾器方法

from django.core.signals import request_finished
from django.dispatch import receiver

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

 

這樣配置之后,每次HTTP接受的時候都會調用這個接收器回調函數了

綁定特定的發送者

記上面之后,你會不會想到這樣的一個問題:每次都調用,會不會很煩啊?如果是我的話,我肯定覺得很煩,畢竟我不是想接受所有人的信號的,所以你需要設置sender關鍵字參數

第二個知識:每一類的信號都對應着特定的發送者,所以要綁定發送者也得綁定對應的發送者類型,例如,request_finished對應的是handler class,而pre_save對應則是model class

下面我們以pre-save為例子綁定特定的發送者(模型):

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):

預防重復的信號

使用dispatch_uid關鍵字參數

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

 

說完了如何監聽一個信號,下面我們繼續講解定義和發送信號吧】

定義信號

class Signal([providing_args=list])

所有的信號都是django.dispatch.Signal的實例,參數providing_args是一個信號提供給監聽器的參數名的列表,比如:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

 

這段代碼定義了一個pizza_done的信號,參數有toppings和size

發送信號

有兩個方法發送信號

Signal.send(sender,**kwargs)

Signal.send_robust(sender,**kwargs)

sender參數是必須的,關鍵字參數可選

class PizzaStore(object):
    ...

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

 

這兩種方法都返回一個元組對[(receiver,respose),...]列表,一個代表被調用的receiver回調函數和他們的response的列表

這兩種方法的區別在於send不會捕捉任何的異常,(放任錯誤的傳播),而send_robust則是捕捉所有的異常,並確保每個接收器都知道這個信號(發生錯誤了)(如果發生錯誤的話,錯誤實體和發生錯誤的接收器作為一個元組對一起返回給那個列表

斷開信號

Signal.disconnect([receiver=None,sender=None,weak=True,dispatch_uid=None)

和監聽信號類似

receiver參數用來指明那個接收器被斷開,如果使用了dispatch_uid的話,receiver可以為None

總結,你可以使用django自帶的信號,也可以自定義自己的信號,信號可以connect,可以send也可以disconnect等等

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM