基于Django signals 信號作用及用法詳解
1、Model signals
django.db.models.signales 作用于django的model操作上的一系列信號
1)pre_init()
django.db.models.signals.pre_init
當(dāng)模型實例化時調(diào)用,在__init__()之前執(zhí)行
三個參數(shù):
pre_init(sender, args, kwargs):
sender:創(chuàng)建實例的模型類
args:參數(shù)列表
kwargs:通過字典形式傳遞的參數(shù)
2)post_init()
django.db.models.signals.post_init
它和pre_init可以說是一對,也是作用于模型實例化時,它是在__init__()之后被執(zhí)行
它有兩個參數(shù):
post_init(sender, instance)
sender:同上,創(chuàng)建實例的模型類
instance:創(chuàng)建的實例
3)pre_save()
django.db.models.signals.pre_save
在model執(zhí)行save方法前被調(diào)用
5個參數(shù):
pre_save(sender,instance,raw,using,update_fields)
sender:model類
instance:保存的實例
raw:一個Boolean類型,如果model被全部保存則為True
using:使用的數(shù)據(jù)庫別名
update_fields:傳遞的待更新的字段集合,如果沒有傳遞,則為None
4)post_save()
djang.db.models.post_save
在model執(zhí)行完save方法后被調(diào)用
6個參數(shù)
post_save(sender,instance,created,raw,using,update_fields)
sender:model class
instance:被保存的model實例
created:Boolean值,如果創(chuàng)建了一個新的記錄則為True
raw:Boolean值,如果model被全部保存則為True
using:使用的數(shù)據(jù)庫別名
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:被刪除的實例
using:使用的數(shù)據(jù)庫別名
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:被刪除的實例,注意:此時,該實例已經(jīng)被刪除了,數(shù)據(jù)庫中不再有這條記錄,所以在使用這個實例的時候要格外注意
using:被使用的數(shù)據(jù)庫別名
7)m2m_changed()
django.db.models.signals.m2m_changed
當(dāng)一個model的ManyToManyField發(fā)生改變的時候被發(fā)送,嚴(yán)格的說,這并不是一個模型信號,因為它是被ManyToManyField發(fā)送的,但是因為它也實現(xiàn)了pre_save/post_save和pre_delete/post_delete,所以也在model signals中包含了。
參數(shù):
sender:描述ManyToManyField的中間模型類,這個中間模型類會在一個many-to-many字段被定義時自動被創(chuàng)建。我們可以通過使用many-to-many字段的through屬性來訪問它
instance:被更新的多對多關(guān)系的實例。它可以是上面的sender,也可以是ManyToManyField的關(guān)系類。
action:指明作用于關(guān)系更新類型的字符串,它可以是以下幾種情況:
'pre_add'/'post_add':在向關(guān)系發(fā)送一個或多個對象前 / 后發(fā)送
'pre_remove/post_remove':從關(guān)系中刪除一個或多個對象前 / 后發(fā)送
'pre_clear/post_clear':在關(guān)系解除之前 / 之后發(fā)送
reverse:正在修改的是正向關(guān)系或者反向關(guān)系,正向False,反向為True
model:被添加、刪除或清除的對象的類
pk_set:對于add/remove等,pk_set是一個從關(guān)系中添加或刪除的對象的主鍵 的集合, 對于clear,pk_set為None
舉例說明:
兩個實例,且關(guān)系如下:
class Topping(models.Model):passclass Pizza(models.Model):toppings = ManyToManyFields(Topping)
我們像這樣連接一個處理器
from django.db.models.signals import m2m_changeddef toppings_changed(sender, **kwargs):passm2m_changed.connect(toppings_changed, sender=Pizza.toppings.through)
然后我們對上面的類做如下操作
p = Pizza.objects.create(...)t = Topping.objects.create(...)p.toppings.add(t)
這樣,對應(yīng)的上面的參數(shù)分別如下:
sender:描述ManyToManyField的中間類,即Pizza.toppings.through
instance:被更新的多對多關(guān)系的實例,即P(本例中,Pizza對應(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}
我們再做下面的操作:
t.pizza_set.remove(p)
這樣,對應(yīng)的參數(shù)為:
sender:同上
instance:t(本例中,Topping實例被更改)
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)備好時發(fā)送,即當(dāng)模型被創(chuàng)建并注冊到Django的模型系統(tǒng)中時。
這個信號通常是在Django內(nèi)部使用,一般不會被第三方應(yīng)用使用。
2、Request/response signals
在處理請求時發(fā)出的信號
1)request_started()
django.core.signals.request_started
在Django開始處理HTTP請求時發(fā)送。
request_started(sender,environ)
2)request_finished()
django.core.signals.request_finished
在Django處理完HTTP請求時發(fā)送
3)got_request_exception()
django.core.signals.got_request_exception
在處理HTTP請求過程中遇到錯誤時發(fā)送。
3、使用信號
1)監(jiān)聽信號
即想要接收信號,可以使用Signals.connect()方法注冊一個接收器函數(shù),當(dāng)信號被發(fā)送時接收器函數(shù)被調(diào)用。
Signals.connect(receiver,sender=None,weak=True,dispatch_uid = None)
receiver:將連接到此信號的回調(diào)函數(shù)
sender:指定要接收信號的特定發(fā)送方
weak:Django默認(rèn)將信號處理程序存儲為弱引用。因此,如果我們的接收器是一個弱引用,那么它有可能會被垃圾回收機(jī)制給回收掉,為了防止這種情況,
我們在調(diào)用信號的connect()方法時,傳遞weak=False。
dispatch_uid:給信號接收方定義的唯一標(biāo)識,以防可能會有重復(fù)信號發(fā)送。
接下來以HTTP請求中的request_finished信號為例:
2)定義接收函數(shù)
def my_func_callback(sender, **kwargs):
print('request_finished')
如上,所有的接收函數(shù)必須要包含sender和關(guān)鍵字參數(shù)兩個參數(shù)。
3)連接接收函數(shù)
有兩種方法和將接收器和信號連接起來,我們可以選擇手動的連接線路,如下:
from django.core.signals import request_finished
request_finished.connect(my_func_callback)
我們還可以選擇通過裝飾器來連接信號和接收器
from django.dispatch import receiverfrom django.core.signals import request_finished@receiver(request_finished)def my_func_callback(sender, **kwargs):pass
注意:在實踐中,信號處理程序通常定義在與他們相關(guān)的應(yīng)用程序的信號子模塊中,信號接收器連接在我們的應(yīng)用程序配置類的ready()方法中。如果使用裝飾器方式,我們只需要在reader()中導(dǎo)入signals子模塊即可。
值得一提的是,在測試過程中,我們的ready()函數(shù)可能不止一次被執(zhí)行,因此我們要保護(hù)我們的信號不要被復(fù)制。
4)連接到特定發(fā)送者發(fā)送的信號
在很多情況下,我們的信號會被多次發(fā)送,但是實際上我們只對這些信號的某個子集感興趣,例如前面收的pre_save()信號
這時候,我們可以注冊只接收特定發(fā)送者發(fā)送的信號。如下,我們可以指定我們需要接收的某個模型發(fā)送的信號
from djang.db.models.signals import pre_savefrom django.dispatch import receiverfrom .model import MyModel@receiver(pre_save, sender=MyModel)def my_receiver(sender, **kwargs):pass
這樣,我們的my_receiver()函數(shù)將只有在MyModel被保存時被調(diào)用。
5)防止重復(fù)的信號:
在某些情況下,連接接收器到信號的代碼可能會運行多次,這可能會導(dǎo)致我們的接收器函數(shù)注冊不止一次,因此,對單個信號事件調(diào)用多次。
如我們使用信號在保存模型時發(fā)送電子郵件,則傳遞唯一標(biāo)識符作為dispatch_uid參數(shù),以識別接收函數(shù)。這個標(biāo)識符通常是一個字符串。
最終結(jié)果是,對于每個唯一的信號,我們的接收器函數(shù)將只綁定到該信號一次。
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_savefrom django.dispatch import receiverfrom django.contrib.auth import get_user_modeluser = get_user_model()@receiver(signal=post_save, sender=user)def create_user(sender, instance=None, created=False, **kwarg):password = instance.passwordinstance.set_password(password)instance.save()
然后在項目apps中重寫ready,將我們新建的my_signals引入即可
3、自定義信號
1)定義信號:
在項目根目錄新建文件self_signal.py
import django.dispatch
my_signal = django.dispatch.Signals(providing_args=['aaa','bbb'])
2)注冊信號(即信號接收器)
項目應(yīng)用下的__init__.py文件
from self_signal import my_signaldef register_my_signal(sender, **kwargs):print('my signal msg:', sender, **kwargs)my_signal.connect(register_my_signal)
3)觸發(fā)信號
views視圖中編寫如下:
from self_signal import my_signal
my_signal.send(sender='Python', aaa=111, bbb=2)
以上這篇基于Django signals 信號作用及用法詳解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. XML在語音合成中的應(yīng)用2. jscript與vbscript 操作XML元素屬性的代碼3. 不要在HTML中濫用div4. HTML5實戰(zhàn)與剖析之觸摸事件(touchstart、touchmove和touchend)5. .NET Framework各版本(.NET2.0 3.0 3.5 4.0)區(qū)別6. ASP基礎(chǔ)入門第四篇(腳本變量、函數(shù)、過程和條件語句)7. ASP將數(shù)字轉(zhuǎn)中文數(shù)字(大寫金額)的函數(shù)8. XML入門的常見問題(三)9. php使用正則驗證密碼字段的復(fù)雜強(qiáng)度原理詳細(xì)講解 原創(chuàng)10. HTTP協(xié)議常用的請求頭和響應(yīng)頭響應(yīng)詳解說明(學(xué)習(xí))
