基于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 相关文章推荐
web.py获取上传文件名的正确方法
Aug 26 Python
在Python中处理列表之reverse()方法的使用教程
May 21 Python
在Python中操作时间之tzset()方法的使用教程
May 22 Python
详解在Python中处理异常的教程
May 24 Python
Python常用的内置序列结构(列表、元组、字典)学习笔记
Jul 08 Python
python读取txt文件并取其某一列数据的示例
Feb 19 Python
Python高级特性与几种函数的讲解
Mar 08 Python
Pyinstaller 打包exe教程及问题解决
Aug 16 Python
Django项目创建到启动详解(最全最详细)
Sep 07 Python
Pycharm中Python环境配置常见问题解析
Jan 16 Python
如何使用PyCharm引入需要使用的包的方法
Sep 22 Python
[原创]赚疯了!转手立赚800+?大佬的python「抢茅台脚本」使用教程
Jan 12 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实现用户在线时间统计详解
2011/10/08 PHP
php结合安卓客户端实现查询交互实例
2015/05/05 PHP
Yii2语言国际化自动配置详解
2018/08/22 PHP
PHP+mysql实现的三级联动菜单功能示例
2019/02/15 PHP
jquery 分页控件实现代码
2009/11/30 Javascript
JQuery Tips(3) 关于$()包装集内元素的改变
2009/12/14 Javascript
jQuery实现原理的模拟代码 -6 代码下载
2010/08/16 Javascript
jQuery中contents()方法用法实例
2015/01/08 Javascript
jquery拖拽效果完整实例(附demo源码下载)
2016/01/14 Javascript
百度地图给map添加右键菜单(判断是否为marker)
2016/03/04 Javascript
使用vue实现点击按钮滑出面板的实现代码
2017/01/10 Javascript
BootStrap Datetimepicker 汉化的实现代码
2017/02/10 Javascript
详解node-ccap模块生成captcha验证码
2017/07/01 Javascript
微信小程序实现验证码获取倒计时效果
2018/02/08 Javascript
微信小程序按钮去除边框线分享页面功能
2018/08/27 Javascript
微信小程序把百度地图坐标转换成腾讯地图坐标过程详解
2019/07/10 Javascript
Python中防止sql注入的方法详解
2017/02/25 Python
Python生成短uuid的方法实例详解
2018/05/29 Python
Python numpy.array()生成相同元素数组的示例
2018/11/12 Python
python 应用之Pycharm 新建模板默认添加编码格式-作者-时间等信息【推荐】
2019/06/17 Python
Python创建数字列表的示例
2019/11/28 Python
带你学习Python如何实现回归树模型
2020/07/16 Python
详解HTML5 LocalStorage 本地存储
2016/12/23 HTML / CSS
HTML5 微格式和相关的属性名称
2010/02/10 HTML / CSS
澳大利亚著名的纺织品品牌:Canningvale
2020/05/05 全球购物
ShellScript面试题一则-ShellScript编程
2014/06/24 面试题
飞利信loadrunner和软件测试笔试题
2012/09/22 面试题
超市端午节活动方案
2014/01/23 职场文书
公职人员索取回扣检举信
2014/04/04 职场文书
公务员政审单位鉴定材料
2014/05/16 职场文书
室内趣味活动方案
2014/08/24 职场文书
基层党员四风问题自我剖析材料
2014/09/29 职场文书
学校政风行风评议工作总结
2014/10/21 职场文书
2015年大学生入党自荐书
2015/03/24 职场文书
2019思想汇报范文
2019/05/21 职场文书
小程序自定义轮播图圆点组件
2022/06/25 Javascript