這篇文章主要介紹了基于Django signals信號(hào)有什么用,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),美蘭企業(yè)網(wǎng)站建設(shè),美蘭品牌網(wǎng)站建設(shè),網(wǎng)站定制,美蘭網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,美蘭網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。1、Model signals
django.db.models.signales 作用于django的model操作上的一系列信號(hào)
1)pre_init()
django.db.models.signals.pre_init
當(dāng)模型實(shí)例化時(shí)調(diào)用,在__init__()之前執(zhí)行
三個(gè)參數(shù):
pre_init(sender, args, kwargs):
sender:創(chuàng)建實(shí)例的模型類
args:參數(shù)列表
kwargs:通過字典形式傳遞的參數(shù)
2)post_init()
django.db.models.signals.post_init
它和pre_init可以說是一對(duì),也是作用于模型實(shí)例化時(shí),它是在__init__()之后被執(zhí)行
它有兩個(gè)參數(shù):
post_init(sender, instance)
sender:同上,創(chuàng)建實(shí)例的模型類
instance:創(chuàng)建的實(shí)例
3)pre_save()
django.db.models.signals.pre_save
在model執(zhí)行save方法前被調(diào)用
5個(gè)參數(shù):
pre_save(sender,instance,raw,using,update_fields)
sender:model類
instance:保存的實(shí)例
raw:一個(gè)Boolean類型,如果model被全部保存則為True
using:使用的數(shù)據(jù)庫(kù)別名
update_fields:傳遞的待更新的字段集合,如果沒有傳遞,則為None
4)post_save()
djang.db.models.post_save
在model執(zhí)行完save方法后被調(diào)用
6個(gè)參數(shù)
post_save(sender,instance,created,raw,using,update_fields)
sender:model class
instance:被保存的model實(shí)例
created:Boolean值,如果創(chuàng)建了一個(gè)新的記錄則為True
raw:Boolean值,如果model被全部保存則為True
using:使用的數(shù)據(jù)庫(kù)別名
update_fields:傳遞的待更新的字段集合,如果沒有傳遞,則為None
5)pre_delete()
django.db.models.signals.pre_delete
在執(zhí)行model的delete()或者queryset的delete()方法前調(diào)用
pre_delete(sender,instance,using)
sender:model class
instance:被刪除的實(shí)例
using:使用的數(shù)據(jù)庫(kù)別名
6)post_delete()
django.db.models.signals.post_delete
在執(zhí)行model的delete()或者queryset的delete()方法后調(diào)用
post_delete(sender, instance,using)
sender:model class
instance:被刪除的實(shí)例,注意:此時(shí),該實(shí)例已經(jīng)被刪除了,數(shù)據(jù)庫(kù)中不再有這條記錄,所以在使用這個(gè)實(shí)例的時(shí)候要格外注意
using:被使用的數(shù)據(jù)庫(kù)別名
7)m2m_changed()
django.db.models.signals.m2m_changed
當(dāng)一個(gè)model的ManyToManyField發(fā)生改變的時(shí)候被發(fā)送,嚴(yán)格的說,這并不是一個(gè)模型信號(hào),因?yàn)樗潜籑anyToManyField發(fā)送的,但是因?yàn)樗矊?shí)現(xiàn)了pre_save/post_save和pre_delete/post_delete,所以也在model signals中包含了。
參數(shù):
sender:描述ManyToManyField的中間模型類,這個(gè)中間模型類會(huì)在一個(gè)many-to-many字段被定義時(shí)自動(dòng)被創(chuàng)建。我們可以通過使用many-to-many字段的through屬性來訪問它
instance:被更新的多對(duì)多關(guān)系的實(shí)例。它可以是上面的sender,也可以是ManyToManyField的關(guān)系類。
action:指明作用于關(guān)系更新類型的字符串,它可以是以下幾種情況:
"pre_add"/"post_add":在向關(guān)系發(fā)送一個(gè)或多個(gè)對(duì)象前 / 后發(fā)送
"pre_remove/post_remove":從關(guān)系中刪除一個(gè)或多個(gè)對(duì)象前 / 后發(fā)送
"pre_clear/post_clear":在關(guān)系解除之前 / 之后發(fā)送
reverse:正在修改的是正向關(guān)系或者反向關(guān)系,正向False,反向?yàn)門rue
model:被添加、刪除或清除的對(duì)象的類
pk_set:對(duì)于add/remove等,pk_set是一個(gè)從關(guān)系中添加或刪除的對(duì)象的主鍵 的集合, 對(duì)于clear,pk_set為None
舉例說明:
兩個(gè)實(shí)例,且關(guān)系如下:
class Topping(models.Model): pass class Pizza(models.Model): toppings = ManyToManyFields(Topping)
我們像這樣連接一個(gè)處理器
from django.db.models.signals import m2m_changed def toppings_changed(sender, **kwargs): pass m2m_changed.connect(toppings_changed, sender=Pizza.toppings.through)
然后我們對(duì)上面的類做如下操作
p = Pizza.objects.create(...) t = Topping.objects.create(...) p.toppings.add(t)
這樣,對(duì)應(yīng)的上面的參數(shù)分別如下:
sender:描述ManyToManyField的中間類,即Pizza.toppings.through
instance:被更新的多對(duì)多關(guān)系的實(shí)例,即P(本例中,Pizza對(duì)應(yīng)被更改)
action:先是"pre_add",然后執(zhí)行上面的操作add(),最后再調(diào)用了"post_add"
reverse:本例中,Pizza包含了ManyToManyField topping,然后調(diào)用P.toppings.add(),所以這是正向更新,故reverse為False
model:被添加刪除或清除的類,本例中 Topping 被添加到Pizza
pk_set:{t.id}
我們?cè)僮鱿旅娴牟僮鳎?/strong>
t.pizza_set.remove(p)
這樣,對(duì)應(yīng)的參數(shù)為:
sender:同上
instance:t(本例中,Topping實(shí)例被更改)
action:先是"pre_remove",然后執(zhí)行上面的remove,再執(zhí)行"post_remove"
reverse:True,本例中,是反向操作
model:p
pk_set:{p.id}
8)class_prepared
django.db.models.signals.class_prepared
當(dāng)模型類準(zhǔn)備好時(shí)發(fā)送,即當(dāng)模型被創(chuàng)建并注冊(cè)到Django的模型系統(tǒng)中時(shí)。
這個(gè)信號(hào)通常是在Django內(nèi)部使用,一般不會(huì)被第三方應(yīng)用使用。
2、Request/response signals
在處理請(qǐng)求時(shí)發(fā)出的信號(hào)
1)request_started()
django.core.signals.request_started
在Django開始處理HTTP請(qǐng)求時(shí)發(fā)送。
request_started(sender,environ)
2)request_finished()
django.core.signals.request_finished
在Django處理完HTTP請(qǐng)求時(shí)發(fā)送
3)got_request_exception()
django.core.signals.got_request_exception
在處理HTTP請(qǐng)求過程中遇到錯(cuò)誤時(shí)發(fā)送。
3、使用信號(hào)
1)監(jiān)聽信號(hào)
即想要接收信號(hào),可以使用Signals.connect()方法注冊(cè)一個(gè)接收器函數(shù),當(dāng)信號(hào)被發(fā)送時(shí)接收器函數(shù)被調(diào)用。
Signals.connect(receiver,sender=None,weak=True,dispatch_uid = None)
receiver:將連接到此信號(hào)的回調(diào)函數(shù)
sender:指定要接收信號(hào)的特定發(fā)送方
weak:Django默認(rèn)將信號(hào)處理程序存儲(chǔ)為弱引用。因此,如果我們的接收器是一個(gè)弱引用,那么它有可能會(huì)被垃圾回收機(jī)制給回收掉,為了防止這種情況,
我們?cè)谡{(diào)用信號(hào)的connect()方法時(shí),傳遞weak=False。
dispatch_uid:給信號(hào)接收方定義的唯一標(biāo)識(shí),以防可能會(huì)有重復(fù)信號(hào)發(fā)送。
接下來以HTTP請(qǐng)求中的request_finished信號(hào)為例:
2)定義接收函數(shù)
def my_func_callback(sender, **kwargs):
print("request_finished")
如上,所有的接收函數(shù)必須要包含sender和關(guān)鍵字參數(shù)兩個(gè)參數(shù)。
3)連接接收函數(shù)
有兩種方法和將接收器和信號(hào)連接起來,我們可以選擇手動(dòng)的連接線路,如下:
from django.core.signals import request_finished
request_finished.connect(my_func_callback)
我們還可以選擇通過裝飾器來連接信號(hào)和接收器
from django.dispatch import receiver from django.core.signals import request_finished @receiver(request_finished) def my_func_callback(sender, **kwargs): pass
注意:在實(shí)踐中,信號(hào)處理程序通常定義在與他們相關(guān)的應(yīng)用程序的信號(hào)子模塊中,信號(hào)接收器連接在我們的應(yīng)用程序配置類的ready()方法中。如果使用裝飾器方式,我們只需要在reader()中導(dǎo)入signals子模塊即可。
值得一提的是,在測(cè)試過程中,我們的ready()函數(shù)可能不止一次被執(zhí)行,因此我們要保護(hù)我們的信號(hào)不要被復(fù)制。
4)連接到特定發(fā)送者發(fā)送的信號(hào)
在很多情況下,我們的信號(hào)會(huì)被多次發(fā)送,但是實(shí)際上我們只對(duì)這些信號(hào)的某個(gè)子集感興趣,例如前面收的pre_save()信號(hào)
這時(shí)候,我們可以注冊(cè)只接收特定發(fā)送者發(fā)送的信號(hào)。如下,我們可以指定我們需要接收的某個(gè)模型發(fā)送的信號(hào)
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()函數(shù)將只有在MyModel被保存時(shí)被調(diào)用。
5)防止重復(fù)的信號(hào):
在某些情況下,連接接收器到信號(hào)的代碼可能會(huì)運(yùn)行多次,這可能會(huì)導(dǎo)致我們的接收器函數(shù)注冊(cè)不止一次,因此,對(duì)單個(gè)信號(hào)事件調(diào)用多次。
如我們使用信號(hào)在保存模型時(shí)發(fā)送電子郵件,則傳遞唯一標(biāo)識(shí)符作為dispatch_uid參數(shù),以識(shí)別接收函數(shù)。這個(gè)標(biāo)識(shí)符通常是一個(gè)字符串。
最終結(jié)果是,對(duì)于每個(gè)唯一的信號(hào),我們的接收器函數(shù)將只綁定到該信號(hào)一次。
from django.core.signals import request_finished
request_finished.connect(my_receiver, dispatch_uid="my_unique_identifier")
如我們注冊(cè)時(shí)保存密碼需要用到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()
然后在項(xiàng)目apps中重寫ready,將我們新建的my_signals引入即可
3、自定義信號(hào)
1)定義信號(hào):
在項(xiàng)目根目錄新建文件self_signal.py
import django.dispatch
my_signal = django.dispatch.Signals(providing_args=["aaa","bbb"])
2)注冊(cè)信號(hào)(即信號(hào)接收器)
項(xiàng)目應(yīng)用下的__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)觸發(fā)信號(hào)
views視圖中編寫如下:
from self_signal import my_signal
my_signal.send(sender="Python", aaa=111, bbb=2)
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“基于Django signals信號(hào)有什么用”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!