Django - - 進階- - Django中的訊號
阿新 • • 發佈:2018-11-27
目錄
- 訊號
- 內建訊號
- 模型訊號
- 管理訊號
- 請求/響應訊號
- 測試訊號
- 資料庫包裝器
- 使用訊號
- 自定義訊號
1,訊號
- Django 提供一個“訊號分發器”,允許解耦的應用在框架的其它地方發生操作時會被通知到。 簡單來說,訊號允許特定的sender通知一組receiver某些操作已經發生。 這在多處程式碼和同一事件有關聯的情況下很有用。
2,內建訊號
2.1 模型訊號
- django.db.models.signals模組定義了模型系統傳送的一組訊號。
2.1.1 pre_init
django.db.models.signals.pre_init
- 每當您例項化Django模型時,該訊號都會在模型的__init__()方法的開頭髮送。
- 帶有此訊號的引數:
- sender 剛建立了一個例項的模型類。
- ARGS 傳遞給__init__()的位置引數列表:
- kwargs 傳遞給__init__()的關鍵字引數的字典:
- 例如:
from app01 import models
p = models.Publisher(name='沙河出版社')
- 傳送到pre_init處理程式的引數將是:
引數 | 值 |
---|---|
sender | Publisher(類本身) |
ARGS | [](一個空列表,因為沒有位置引數傳遞給__init__()。) |
kwargs | {'name': “沙河出版社”} |
2.1.2 pre_save
django.db.models.signals.pre_save
- 這是在模型的save()方法的開頭髮送的。
- 帶有此訊號的引數:
- sender 模型類。
- instance 正在儲存的實際例項。
- raw 一個布林值True如果模型按照顯示的方式儲存(即當載入固定裝置時)。 不應該查詢/修改資料庫中的其他記錄,因為資料庫可能尚未處於一致狀態。
- using 正在使用的資料庫別名。
- update_fields 如果有欄位被傳遞給Model.save()方法那麼就是所傳遞的欄位集,否則就是None。
2.1.3 post_save
django.db.models.signals.post_save
- 像pre_save一樣,但是在save()方法的末尾傳送。
- 帶有此訊號的引數:
- sender 模型類。
- instance 正在儲存的實際例項。
- created 一個布林值True如果建立了新記錄。
- raw 一個布林值True如果模型按照顯示的方式儲存(即當載入固定裝置時)。 不應該查詢/修改資料庫中的其他記錄,因為資料庫可能尚未處於一致狀態。
- using 正在使用的資料庫別名。
- update_fields 如果有欄位被傳遞給Model.save()方法那麼就是所傳遞的欄位集,否則就是None。
2.1.4 pre_delete
django.db.models.signals.pre_delete
- 在模型的delete()方法和queryset的delete()方法的開頭髮送。
- 帶有此訊號的引數:
- sender 模型類。
- instance 正在刪除的實際例項。
- using 正在使用的資料庫別名。
2.1.5 post_delete
django.db.models.signals.post_delete
- 像pre_delete一樣,但是在模型的delete()方法和queryset的delete()方法的末尾傳送。
- 帶有此訊號的引數:
- sender 模型類。
- instance 正在刪除的實際例項。
- 請注意,該物件將不再位於資料庫中,所以要非常小心使用此例項。
- using 正在使用的資料庫別名。
2.1.6 m2m_changed
django.db.models.signals.m2m_changed
- 在模型例項上更改了ManyToManyField時傳送。 嚴格來說,這不是一個模型訊號,因為它是由ManyToManyField傳送的,但由於它補充了pre_save / post_save和pre_delete / post_delete當跟蹤模型的更改時,它包括在這裡。
- 帶有此訊號的引數:
- sender 描述ManyToManyField的中間模型類。 當定義多對多欄位時,此類自動建立;您可以使用多對多欄位上的through屬性訪問它。
- instance 多對多關係更新的例項。 這可以是sender或ManyToManyField相關的類的一個例項。
- action 指示在關係上完成的更新型別的字串。 這可以是以下之一:
- “pre_add” 在之前傳送一個或多個物件被新增到關係中。
- “post_add” 在之後傳送一個或多個物件被新增到關係中。
- “pre_remove” 在之前傳送一個或多個物件從關係中刪除。
- “post_remove” 在之後傳送一個或多個物件從關係中刪除。
- “pre_clear” 在之前傳送關係被清除。
- “post_clear” 之後傳送關係被清除。
- reverse 指示關係的哪一側被更新(即,如果它是正在被修改的正向或反向關係)。
- model 新增到,從關係中刪除或從關係中清除的物件的類。
- pk_set 對於pre_add,post_add,pre_remove和post_remove操作,這是一組主鍵值加入或從關係中刪除。對於pre_clear和post_clear操作,這是None。
- using 正在使用的資料庫別名。
2.1.7 class_prepared
django.db.models.signals.class_prepared
- 每當模型類“準備”時傳送 - 即,一旦模型已經被定義並在Django的模型系統中註冊。 Django內部使用這個訊號;它通常不會用於第三方應用程式。
- 由於此訊號是在應用程式登錄檔群集程序期間傳送的,並且在應用登錄檔完全填充後執行AppConfig.ready(),因此無法使用該方法連線接收器。 一種可能性是連線他們AppConfig.__init__(),注意不要匯入模型或觸發對應用程式登錄檔的呼叫。
- 使用此訊號傳送的引數:
- sender ready的model類。
2.2 管理訊號
2.2.1 pre_migrate
django.db.models.signals.pre_migrate
- 在開始安裝應用程式之前,由migrate命令傳送。 對於缺少models模組的應用,不會發送。
- 帶有此訊號的引數:
- sender 應用程式即將遷移/同步的AppConfig例項。
- APP_CONFIG 與sender相同。
- verbosity 指示manage.py在螢幕上列印多少資訊。 有關詳細資訊,請參閱--verbosity標誌。
- 監聽pre_migrate的函式應根據該引數的值調整輸出到螢幕的內容。
- interactive 如果interactive是True,則可以安全地提示使用者在命令列中輸入內容。 如果interactive為False,則偵聽此訊號的功能不應嘗試提示任何內容。
- 例如,當interactive為True時,django.contrib.auth應用程式僅提示建立超級使用者。
- using 命令將在其上執行的資料庫的別名。
- plan Django中的新功能1.10。遷移計劃將用於遷移執行。 雖然該計劃不是公共API,但這在允許罕見的情況下需要知道計劃。 一個計劃是兩個元組的列表,第一個專案是遷移類的例項,第二個專案顯示遷移是否回滾(True)或應用(False
- apps Django中的新功能1.10。包含遷移執行前的專案狀態的Apps的例項。 應該使用它來代替全域性apps登錄檔來檢索要執行操作的模型。
2.2.2 post_migrate
django.db.models.signals.post_migrate
- 在migrate(即使不進行遷移)和flush命令的末尾傳送。 對於缺少models模組的應用,不會發送。
- 此訊號的處理程式不得執行資料庫模式更改,因為如果在migrate命令期間執行,則可能會導致flush命令失敗。
- 帶有此訊號的引數:
- sender 剛剛安裝的應用程式的AppConfig例項。
- APP_CONFIG 與sender相同。
- verbosity 指示manage.py在螢幕上列印多少資訊。 有關詳細資訊,請參閱--verbosity標誌。
- 監聽post_migrate的函式應根據此引數的值調整輸出到螢幕的內容。
- interactive 如果interactive是True,則可以安全地提示使用者在命令列中輸入內容。 如果interactive為False,則偵聽此訊號的功能不應嘗試提示任何內容。
- 例如,當interactive為True時,django.contrib.auth應用程式僅提示建立超級使用者。
- using 用於同步的資料庫別名。 預設為default資料庫。
- plan Django中的新功能1.10。用於遷移執行的遷移計劃。 雖然該計劃不是公共API,但這在允許罕見的情況下需要知道計劃。 一個計劃是兩個元組的列表,第一個專案是遷移類的例項,第二個專案顯示遷移是否回滾(True)或應用(False
- apps Django中的新功能1.10。包含遷移執行後項目狀態的Apps的例項。 應該使用它來代替全域性apps登錄檔來檢索要執行操作的模型。
2.3 請求/響應訊號
- 處理請求時由核心框架傳送的訊號。
2.3.1 request_started
django.core.signals. request_started
當Django開始處理HTTP請求時傳送。
- 帶有此訊號的引數:
- sender 處理程式類 - 例如django.core.handlers.wsgi.WsgiHandler - 處理該請求。
- ENVIRON environ字典提供給請求。
2.3.2 request_finished
django.core.signals.request_finished
- 當Django完成向客戶端傳遞HTTP響應時傳送。
- 帶有此訊號的引數:
- sender 處理程式類,如上。
2.3.3 got_request_exception
django.core.signals. got_request_exception
- 當Django在處理傳入的HTTP請求時遇到異常時,會發送此訊號。
- 帶有此訊號的引數:
- sender 處理程式類,如上。
- request HttpRequest物件。
2.4 測試訊號
- 訊號只在running tests時傳送。
2.4.1 setting_changed
django.test.signals.setting_changed
當通過django.test.TestCase.settings()上下文管理器或django.test.override_settings()裝飾器/上下文管理器
實際傳送兩次:應用新值(“setup”)和恢復原始值(“拆除”)時。 使用enter引數來區分兩者。
您還可以從django.core.signals匯入此訊號,以避免在非測試情況下從django.test匯入。
- 帶有此訊號的引數:
- sender 設定處理程式。
- setting 設定的名稱。
- value 更改後的設定值。 對於最初不存在的設定,在“拆卸”階段,value為None。
- enter 一個布林值True如果應用設定,False如果還原。
2.4.2 template_rendered
django.test.signals.template_rendered
測試系統呈現模板時傳送。 在Django伺服器的正常操作期間不發出此訊號 - 它僅在測試期間可用。
- 帶有此訊號的引數:
- sender 被渲染的Template物件。
- template 與發信人相同
- context 模板呈現的Context。
2.5 資料庫包裝器
- 當資料庫連線啟動時,由資料庫包裝器傳送的訊號。
2.5.1 connection_created
django.db.backends.signals.connection_created
當資料庫包裝器與資料庫進行初始連線時傳送。 如果您想將任何後續連線命令傳送到SQL後端,這一點尤其有用。
- 帶有此訊號的引數:
- sender 資料庫包裝器類 - 即django.db.backends.postgresql.DatabaseWrapper或django.db.backends.mysql.DatabaseWrapper等
- connection 開啟的資料庫連線。 這可以在多資料庫配置中使用,以區分來自不同資料庫的連線訊號。
2.6 使用訊號
- 回到前面的面試圖,如何在Django中實現每一次ORM儲存到資料庫的時候執行指定操作?
2.6.1 Receiver函式
- Receiver可以是任何Python函式或者方法:
def my_callback(sender, **kwargs):
print(sender)
print(kwargs)
print("要儲存了啊!")
print('-' * 120)
2.6.2 監聽訊號
一旦某個指定訊號觸發,就執行我指定的receiver函式。
我們現在的需求是,模型層一執行儲存的動作就做什麼事。
所以應該是一旦觸發 pre_save 訊號就執行 my_callback,對於內建的訊號Django框架會自動幫我們觸發,我們只需要告訴它訊號觸發之後做什麼事就可以了:
pre_save.connect(my_callback)
接下來,只要涉及到ORMC鞥面的save()操作,都會自動執行我定義的my_callback函數了。
例如:
a3 = Author.objects.create(name='測試訊號-作者')
b3 = Book.objects.create(title='測試訊號-書')
- 輸出:
<class 'app02.models.Author'>
{'signal': <django.db.models.signals.ModelSignal object at 0x108e0d198>, 'instance': <Author: 測試訊號-作者>, 'raw': False, 'using': 'default', 'update_fields': None}
要儲存了啊!
------------------------------------------------------------------------------------------------------------------------
(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.001) INSERT INTO `app02_author` (`name`) VALUES ('測試訊號-作者'); args=['測試訊號-作者']
<class 'app02.models.Book'>
{'signal': <django.db.models.signals.ModelSignal object at 0x108e0d198>, 'instance': <Book: 測試訊號-書>, 'raw': False, 'using': 'default', 'update_fields': None}
要儲存了啊!
------------------------------------------------------------------------------------------------------------------------
(0.001) INSERT INTO `app02_book` (`title`) VALUES ('測試訊號-書'); args=['測試訊號-書']
2.6.3 使用裝飾器方式監聽訊號
# 使用裝飾器方式
from django.db.models.signals import pre_save
from django.dispatch import receiver
@receiver(pre_save)
def my_callback(sender, **kwargs):
print(sender)
print(kwargs)
print("要儲存了啊!")
print('-' * 120)
2.7 自定義訊號
- 上面列出來的都是Django框架內建的訊號,當然我們還可以自定義訊號。
2.7.1 定義訊號
- 所有訊號都是 django.dispatch.Signal 的例項。 providing_args是一個列表,由訊號將提供給監聽者的引數名稱組成。 理論上是這樣,但是實際上並沒有任何檢查來保證向監聽者提供了這些引數。
- 舉個例子:
# 自定義訊號
from django.dispatch import Signal
bath_done = Signal(providing_args=['amount', 'temperature'])
- 這裡定義了一個洗澡水燒好了的訊號,它接受兩個引數:amount表示水量,temperature表示溫度。
2.7.2 註冊receiver
from django.dispatch import receiver
@receiver(bath_done)
def my_action(sender, **kwargs):
print(sender)
print(kwargs)
print('脫衣服泡個澡吧!')
2.7.3 觸發訊號
- 斯嘉麗燒好了一浴缸40度的洗澡水,杜蘭特要開喝了。
bath_done.send(sender='斯嘉麗', amount='一浴缸', temperature='40°')
- 轉自:https://www.cnblogs.com/liwenzhou/p/9745331.html