1. 程式人生 > 程式設計 >基於Django signals 訊號作用及用法詳解

基於Django signals 訊號作用及用法詳解

1、Model signals

django.db.models.signales 作用於django的model操作上的一系列訊號

1)pre_init()

django.db.models.signals.pre_init

當模型例項化時呼叫,在__init__()之前執行

三個引數:

pre_init(sender,args,kwargs):

sender:建立例項的模型類

args:引數列表

kwargs:通過字典形式傳遞的引數

2)post_init()

django.db.models.signals.post_init

它和pre_init可以說是一對,也是作用於模型例項化時,它是在__init__()之後被執行

它有兩個引數:

post_init(sender,instance)

sender:同上,建立例項的模型類

instance:建立的例項

3)pre_save()

django.db.models.signals.pre_save

在model執行save方法前被呼叫

5個引數:

pre_save(sender,instance,raw,using,update_fields)

sender:model類

instance:儲存的例項

raw:一個Boolean型別,如果model被全部儲存則為True

using:使用的資料庫別名

update_fields:傳遞的待更新的欄位集合,如果沒有傳遞,則為None

4)post_save()

djang.db.models.post_save

在model執行完save方法後被呼叫

6個引數

post_save(sender,instance,created,raw,using,update_fields)

sender:model class

instance:被儲存的model例項

created:Boolean值,如果建立了一個新的記錄則為True

raw:Boolean值,如果model被全部儲存則為True

using:使用的資料庫別名

update_fields:傳遞的待更新的欄位集合,如果沒有傳遞,則為None

5)pre_delete()

django.db.models.signals.pre_delete

在執行model的delete()或者queryset的delete()方法前呼叫

pre_delete(sender,instance,using)

sender:model class

instance:被刪除的例項

using:使用的資料庫別名

6)post_delete()

django.db.models.signals.post_delete

在執行model的delete()或者queryset的delete()方法後呼叫

post_delete(sender,instance,using)

sender:model class

instance:被刪除的例項,注意:此時,該例項已經被刪除了,資料庫中不再有這條記錄,所以在使用這個例項的時候要格外注意

using:被使用的資料庫別名

7)m2m_changed()

django.db.models.signals.m2m_changed

當一個model的ManyToManyField發生改變的時候被髮送,嚴格的說,這並不是一個模型訊號,因為它是被ManyToManyField傳送的,但是因為它也實現了pre_save/post_save和pre_delete/post_delete,所以也在model signals中包含了。

引數:

sender:描述ManyToManyField的中間模型類,這個中間模型類會在一個many-to-many欄位被定義時自動被建立。我們可以通過使用many-to-many欄位的through屬性來訪問它

instance:被更新的多對多關係的例項。它可以是上面的sender,也可以是ManyToManyField的關係類。

action:指明作用於關係更新型別的字串,它可以是以下幾種情況:

"pre_add"/"post_add":在向關係傳送一個或多個物件前 / 後傳送

"pre_remove/post_remove":從關係中刪除一個或多個物件前 / 後傳送

"pre_clear/post_clear":在關係解除之前 / 之後傳送

reverse:正在修改的是正向關係或者反向關係,正向False,反向為True

model:被新增、刪除或清除的物件的類

pk_set:對於add/remove等,pk_set是一個從關係中新增或刪除的物件的主鍵 的集合, 對於clear,pk_set為None

舉例說明:

兩個例項,且關係如下:

class Topping(models.Model):

pass

class Pizza(models.Model):


toppings = ManyToManyFields(Topping)

我們像這樣連線一個處理器

from django.db.models.signals import m2m_changed

def toppings_changed(sender,**kwargs):

pass

m2m_changed.connect(toppings_changed,sender=Pizza.toppings.through)

然後我們對上面的類做如下操作

p = Pizza.objects.create(...)

t = Topping.objects.create(...)

p.toppings.add(t)

這樣,對應的上面的引數分別如下:

sender:描述ManyToManyField的中間類,即Pizza.toppings.through

instance:被更新的多對多關係的例項,即P(本例中,Pizza對應被更改)

action:先是"pre_add",然後執行上面的操作add(),最後再呼叫了"post_add"

reverse:本例中,Pizza包含了ManyToManyField topping,然後呼叫P.toppings.add(),所以這是正向更新,故reverse為False

model:被新增刪除或清除的類,本例中 Topping 被新增到Pizza

pk_set:{t.id}

我們再做下面的操作:

t.pizza_set.remove(p)

這樣,對應的引數為:

sender:同上

instance:t(本例中,Topping例項被更改)

action:先是"pre_remove",然後執行上面的remove,再執行"post_remove"

reverse:True,本例中,是反向操作

model:p

pk_set:{p.id}

8)class_prepared

django.db.models.signals.class_prepared

當模型類準備好時傳送,即當模型被建立並註冊到Django的模型系統中時。

這個訊號通常是在Django內部使用,一般不會被第三方應用使用。

2、Request/response signals

在處理請求時發出的訊號

1)request_started()

django.core.signals.request_started

在Django開始處理HTTP請求時傳送。

request_started(sender,environ)

2)request_finished()

django.core.signals.request_finished

在Django處理完HTTP請求時傳送

3)got_request_exception()

django.core.signals.got_request_exception

在處理HTTP請求過程中遇到錯誤時傳送。

3、使用訊號

1)監聽訊號

即想要接收訊號,可以使用Signals.connect()方法註冊一個接收器函式,當訊號被髮送時接收器函式被呼叫。

Signals.connect(receiver,sender=None,weak=True,dispatch_uid = None)

receiver:將連線到此訊號的回撥函式

sender:指定要接收訊號的特定傳送方

weak:Django預設將訊號處理程式儲存為弱引用。因此,如果我們的接收器是一個弱引用,那麼它有可能會被垃圾回收機制給回收掉,為了防止這種情況,

我們在呼叫訊號的connect()方法時,傳遞weak=False。

dispatch_uid:給訊號接收方定義的唯一標識,以防可能會有重複訊號傳送。

接下來以HTTP請求中的request_finished訊號為例:

2)定義接收函式

def my_func_callback(sender,**kwargs):

print("request_finished")

如上,所有的接收函式必須要包含sender和關鍵字引數兩個引數。

3)連線接收函式

有兩種方法和將接收器和訊號連線起來,我們可以選擇手動的連線線路,如下:

from django.core.signals import request_finished

request_finished.connect(my_func_callback)

我們還可以選擇通過裝飾器來連線訊號和接收器

from django.dispatch import receiver

from django.core.signals import request_finished

@receiver(request_finished)

def my_func_callback(sender,**kwargs):

pass

注意:在實踐中,訊號處理程式通常定義在與他們相關的應用程式的訊號子模組中,訊號接收器連線在我們的應用程式配置類的ready()方法中。如果使用裝飾器方式,我們只需要在reader()中匯入signals子模組即可。

值得一提的是,在測試過程中,我們的ready()函式可能不止一次被執行,因此我們要保護我們的訊號不要被複制。

4)連線到特定傳送者傳送的訊號

在很多情況下,我們的訊號會被多次傳送,但是實際上我們只對這些訊號的某個子集感興趣,例如前面收的pre_save()訊號

這時候,我們可以註冊只接收特定傳送者傳送的訊號。如下,我們可以指定我們需要接收的某個模型傳送的訊號

from djang.db.models.signals import pre_save

from django.dispatch import receiver

from .model import MyModel

@receiver(pre_save,sender=MyModel)

def my_receiver(sender,**kwargs):

pass

這樣,我們的my_receiver()函式將只有在MyModel被儲存時被呼叫。

5)防止重複的訊號:

在某些情況下,連線接收器到訊號的程式碼可能會執行多次,這可能會導致我們的接收器函式註冊不止一次,因此,對單個訊號事件呼叫多次。

如我們使用訊號在儲存模型時傳送電子郵件,則傳遞唯一識別符號作為dispatch_uid引數,以識別接收函式。這個識別符號通常是一個字串。

最終結果是,對於每個唯一的訊號,我們的接收器函式將只繫結到該訊號一次。

from django.core.signals import request_finished

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

如我們註冊時儲存密碼需要用到post_save,新建my_signals.py,在檔案中加入下面程式碼:

from django.db.models.signals import post_save

from django.dispatch import receiver

from django.contrib.auth import get_user_model

user = get_user_model()

@receiver(signal=post_save,sender=user)

def create_user(sender,instance=None,created=False,**kwarg):

password = instance.password

instance.set_password(password)

instance.save()

然後在專案apps中重寫ready,將我們新建的my_signals引入即可

基於Django signals 訊號作用及用法詳解

3、自定義訊號

1)定義訊號:

在專案根目錄新建檔案self_signal.py

import django.dispatch

my_signal = django.dispatch.Signals(providing_args=["aaa","bbb"])

2)註冊訊號(即訊號接收器)

專案應用下的__init__.py檔案

from self_signal import my_signal

def register_my_signal(sender,**kwargs):

print("my signal msg:",sender,**kwargs)

my_signal.connect(register_my_signal)

3)觸發訊號

views檢視中編寫如下:

from self_signal import my_signal

my_signal.send(sender="Python",aaa=111,bbb=2)

以上這篇基於Django signals 訊號作用及用法詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。