1. 程式人生 > >Django - - 進階- - Django中的訊號

Django - - 進階- - Django中的訊號

目錄

  • 訊號
  • 內建訊號
    • 模型訊號
    • 管理訊號
    • 請求/響應訊號
    • 測試訊號
    • 資料庫包裝器
    • 使用訊號
    • 自定義訊號

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