django包含乙個「訊號分配器」,當在框架中其他位置發生操作時,該訊號分配器可幫助通知已分離的應用程式。簡而言之,訊號使某些傳送者可以通知一組接收者已經採取了某些措施。當許多**片段可能對同一事件感興趣時,它們特別有用。
django提供了一組內建訊號,這些訊號使django自身可以將某些操作通知給使用者**。 其中包括一些有用的通知:
django.db.models.signals.pre_delete
和 ``django.db.models.signals.post_delete`
django.db.models.signals.m2m_changed
django.core.signals.request_started
和django.core.signals.request_finished
有關完整列表和每個訊號的完整說明,請參見內建訊號文件。
您還可以定義和傳送自己的自定義訊號; 見下文:
要接收訊號,請使用signal.connect()
方法註冊乙個接收器函式,傳送訊號時將呼叫接收器功能。所有訊號的接收器函式都按註冊的順序一次呼叫乙個。
signal.connect(receiver, sender=none, weak=true, dispatch_uid=none)
源**
引數:通過註冊在每個http請求完成後呼叫的訊號,讓我們看看它是如何工作的。我們將連線到request_finished
訊號。
首先,我們需要定義乙個接收器函式。 接收者可以是任何python函式或方法:
def my_callback(sender, **kwargs):
print("request finished!")
請注意,該函式帶有乙個sender
引數以及萬用字元關鍵字引數(**kwargs)
; 所有訊號處理程式都必須採用這些引數。
我們稍後再看傳送者,但現在看一下**kwargs
引數。所有訊號都傳送關鍵字引數,並且可以隨時更改這些關鍵字引數。在request_finished
的情況下,它被記錄為不傳送任何引數,這意味著我們可能會想將訊號處理編寫為my_callback(sender)
。
這將是錯誤的, 實際上,如果您這樣做,django將丟擲錯誤, 這是因為在任何時候都可以將引數新增到訊號中,並且您的接收器必須能夠處理這些新引數。
您可以通過兩種方式將接收器連線到訊號。 您可以採取手動連線路由:
from django.core.signals import request_finished
request_finished.connect(my_callback)
另外,您可以使用receive()
裝飾器:
receiver(signal)
源**
引數:signal: 連線功能的訊號或訊號列表。
這是您與裝飾器的連線方式:
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished)
def my_callback(sender, **kwargs):
print("request finished!")
現在,每次請求完成時都會呼叫我們的my_callback
函式。
我的**該放在哪?嚴格來說,訊號處理和註冊**可以存在於您喜歡的任何位置,儘管建議避免使用應用程式的根模組及其模型模組,以最大程度地減少匯入**的***。
實際上,訊號處理程式通常是在與之相關的應用程式的
signals
子模組中定義的。訊號接收器連線在應用程式配置類的ready()
方法中。如果您使用receiver()
裝飾器,則將訊號子模組匯入ready()
中。
註解:在某些情況下,將接收器連線到訊號的**可能會執行多次。這可能會導致您的接收器功能被多次註冊,因此對於訊號事件將被多次呼叫。例如,在測試過程中,
ready()
方法可能會執行多次,因此,您可能希望防止訊號重複,特別是如果您打算在測試中傳送訊號時。
ready()
方法可以在測試期間執行多次。更一般而言,這會在專案匯入定義訊號的模組的任何地方發生,因為訊號註冊的執行次數與匯入的次數相同。
如果此行為有問題(例如在儲存模型時使用訊號傳送電子郵件),請傳遞唯一識別符號作為dispatch_uid
引數來標識您的接收器功能。這個識別符號通常是乙個字串,儘管任何雜湊物件都足夠了。最終結果是,對於每個唯一的dispatch_uid
值,您的接收器函式將僅與訊號繫結一次:
from django.core.signals import request_finished
request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
您的應用程式可以利用訊號基礎設施並提供自己的訊號。
何時使用自定義訊號?訊號是隱式函式呼叫,使除錯更加困難。如果自定義訊號的傳送者和接收者都在專案中,那麼最好使用顯式函式呼叫。
class signal(providing_args=list)
[源**](
所有訊號都是django.dispatch.signal
例項。provider_args
是訊號將提供給偵聽器的引數名稱的列表。不過,這純粹是文件化的,因為沒有任何東西可以檢查訊號是否確實向其偵聽器提供了這些引數。
例如:
import django.dispatch
pizza_done = django.dispatch.signal(providing_args=["toppings", "size"])
這宣告了pizza_done
訊號,該訊號將為接收者提供toppings
和size
引數。請記住,您可以隨時更改此引數列表,因此無需在第一次嘗試時就正確設定api。
在django中,有兩種傳送訊號的方法。
signal.send(sender, **kwargs)
signal.send_robust(sender, **kwargs)
要傳送訊號,請呼叫signal.send()
(所有內建訊號都使用此訊號)或signal.send_robust()
。您必須提供sender
引數(大多數情況下是乙個類),並且可以根據需要提供盡可能多的其他關鍵字引數。
例如,這是傳送我們的pizza_done
訊號的樣子:
class pizzastore:
...def send_pizza(self, toppings, size):
pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
...
send()
和send_robust()
都返回乙個元組對[[receiver, response),...]
的列表,它們表示被呼叫的接收器函式及其響應值的列表。
send()
與send_robust()
的不同之處在於如何處理接收器函式引發的異常。send()
不會捕獲接收方引發的任何異常,它只是允許錯誤傳播,因此,面對錯誤,可能不會將訊號通知所有接收器。
send_robust()
捕獲從python的exception
類派生的所有錯誤,並確保將訊號通知所有接收器。如果發生錯誤,則在引發錯誤的接收器的元組對中返回錯誤例項。
呼叫send_robust()
時,返回的錯誤的__traceback__
屬性上提供了追溯。
signal.disconnect(receiver=none, sender=none, dispatch_uid=none)
要斷開接收器與訊號的連線,請呼叫signal.disconnect()
。 引數如signal.connect()
中所述。如果接收器已斷開連線,則該方法返回true,否則返回false。receiver
引數指示已註冊的接收方斷開連線。 如果使用dispatch_uid
標識接收者,則可能為none。
驅動 訊號機制
一 實驗平台 開發板fs2410,採用三星s3c2410的cpu,linux作業系統。二 實現功能 主程式讓四個led燈形成流水燈,當按下開關k1時,熄滅所有燈,並推出程序。三 實驗原理 阻塞和poll機制都是應用程式進行查詢,應用程式是主動的,而裝置時是被動的。訊號機制可以讓裝置主動向應用程式發訊...
Linux 信 號 機 制
前面介紹了訊號的基本概念,在這一節中,我們將介紹核心如何實現訊號機制。即核心如何向乙個程序傳送訊號 程序如何接收乙個訊號 程序怎樣控制自己對訊號的反應 核心在什麼時機處理和怎樣處理程序收到的訊號。還要介紹一下setjmp和longjmp在訊號中起到的作用。1 核心對訊號的基本處理方法 核心給乙個程序...
linux 訊號機制
本文旨在弄懂linux中的訊號工作原理 kill l 命令可以檢視linux下所有訊號 2.1 使用者在終端按下某些鍵時,終端驅動程式會傳送訊號給前台程序 例如ctrl c產生sigint訊號,ctrl 產生sigquit訊號,ctrl z產生sigtstp訊號 2.2 硬體異常產生訊號,這些條件由...