基于Django signals 信号作用及用法详解


Posted in Python onMarch 28, 2020

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 信号作用及用法详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python爬取国外天气预报网站的方法
Jul 10 Python
轻松掌握python设计模式之访问者模式
Nov 18 Python
Python实现的连接mssql数据库操作示例
Aug 17 Python
如何用python写一个简单的词法分析器
Dec 18 Python
python 通过可变参数计算n个数的乘积方法
Jun 13 Python
python+opencv像素的加减和加权操作的实现
Jul 14 Python
django实现支付宝支付实例讲解
Oct 17 Python
浅析python中while循环和for循环
Nov 19 Python
VS2019+python3.7+opencv4.1+tensorflow1.13配置详解
Apr 16 Python
python3 简单实现组合设计模式
Jul 02 Python
爬虫代理的cookie如何生成运行
Sep 22 Python
python爬虫 requests-html的使用
Nov 30 Python
浅谈django 模型类使用save()方法的好处与注意事项
Mar 28 #Python
Django 实现对已存在的model进行更改
Mar 28 #Python
浅谈Django QuerySet对象(模型.objects)的常用方法
Mar 28 #Python
django使用F方法更新一个对象多个对象字段的实现
Mar 28 #Python
Django 拼接两个queryset 或是两个不可以相加的对象实例
Mar 28 #Python
使用Django实现把两个模型类的数据聚合在一起
Mar 28 #Python
使用python客户端访问impala的操作方式
Mar 28 #Python
You might like
php面向对象全攻略 (十六) 对象的串行化
2009/09/30 PHP
探讨PHP删除文件夹的三种方法
2013/06/09 PHP
php实例分享之通过递归实现删除目录下的所有文件详解
2014/05/15 PHP
让你的PHP,APACHE,NGINX支持大文件上传
2021/03/09 PHP
JavaScript使用cookie
2007/02/02 Javascript
判断JavaScript对象是否可用的最正确方法分析
2008/10/03 Javascript
JS控制输入框内字符串长度
2014/05/21 Javascript
JavaScript中的无阻塞加载性能优化方案
2014/10/10 Javascript
jQuery使用load()方法载入另外一个网页文件内的指定标签内容到div标签的方法
2015/03/25 Javascript
详解JavaScript对W3C DOM模版的支持情况
2015/06/16 Javascript
由ReactJS的Hello world说开来
2015/07/02 Javascript
Ztree新增角色和编辑角色回显问题的解决
2016/10/25 Javascript
100多个基础常用JS函数和语法集合大全
2017/02/16 Javascript
Bootstrap3 模态框使用实例
2017/02/22 Javascript
详解Vue 实例中的生命周期钩子
2017/03/21 Javascript
关于Stream和Buffer的相互转换详解
2017/07/26 Javascript
完美解决axios在ie下的兼容性问题
2018/03/05 Javascript
JavaScript时间日期操作实例小结【5个示例】
2018/12/22 Javascript
一文秒懂JavaScript构造函数、实例、原型对象以及原型链
2020/08/25 Javascript
python算法表示概念扫盲教程
2017/04/13 Python
python实现排序算法解析
2018/09/08 Python
如何在VSCode上轻松舒适的配置Python的方法步骤
2019/10/28 Python
Python基于WordCloud制作词云图
2019/11/29 Python
Python如何在循环内使用list.remove()
2020/06/01 Python
Pytorch 解决自定义子Module .cuda() tensor失败的问题
2020/06/23 Python
基于html和CSS3制作酷炫的导航栏
2015/09/23 HTML / CSS
使用Canvas操作像素的方法
2018/06/14 HTML / CSS
意大利香水和彩妆护肤品购物网站:Ditano
2017/08/13 全球购物
美国社交购物市场:MassGenie
2019/02/18 全球购物
英国休闲奢华的缩影:Crew Clothing
2019/05/05 全球购物
统计员岗位职责
2013/11/14 职场文书
我爱祖国演讲稿
2014/09/02 职场文书
公司备用金管理制度
2015/08/04 职场文书
90条交通安全宣传标语
2019/10/12 职场文书
Python基础之教你怎么在M1系统上使用pandas
2021/05/08 Python
MySQL 自动填充 create_time 和 update_time
2022/05/20 MySQL