基于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程序中操作文件之isatty()方法的使用教程
May 24 Python
python实现简单点对点(p2p)聊天
Sep 13 Python
基于Python中单例模式的几种实现方式及优化详解
Jan 09 Python
Python实现的凯撒密码算法示例
Apr 12 Python
Python 创建空的list,以及append用法讲解
May 04 Python
python 快速把超大txt文件转存为csv的实例
Oct 26 Python
人工神经网络算法知识点总结
Jun 11 Python
Python类中的魔法方法之 __slots__原理解析
Aug 26 Python
Jupyter Notebook 实现正常显示中文和负号
Apr 24 Python
Python3+PyCharm+Django+Django REST framework配置与简单开发教程
Feb 16 Python
OpenCV-Python实现轮廓拟合
Jun 08 Python
Python将CSV文件转化为HTML文件的操作方法
Jun 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-accelerator网站加速PHP缓冲的方法
2008/07/30 PHP
yii添删改查实例
2015/11/16 PHP
php静态成员方法和静态的成员属性的使用方法
2017/10/26 PHP
javascript实现的使用方向键控制光标在table单元格中切换
2010/11/17 Javascript
jquery 圆形旋转图片滚动切换效果
2011/01/19 Javascript
最短的IE判断var ie=!-[1,]分析
2014/05/28 Javascript
jQuery使用empty()方法删除元素及其所有子元素的方法
2015/03/26 Javascript
AngularJS教程之环境设置
2016/08/16 Javascript
Javascript基于jQuery UI实现选中区域拖拽效果
2016/11/25 Javascript
ES6中class类用法实例浅析
2017/04/06 Javascript
微信小程序中form 表单提交和取值实例详解
2017/04/20 Javascript
jQuery实现的淡入淡出与滑入滑出效果示例
2018/04/18 jQuery
angular4 获取wifi列表中文显示乱码问题的解决
2018/10/20 Javascript
简单说说angular.json文件的使用
2018/10/29 Javascript
[45:10]NB vs Liquid Supermajor小组赛 A组胜者组决赛 BO3 第二场 6.2
2018/06/04 DOTA
Python中不同进制互相转换(二进制、八进制、十进制和十六进制)
2015/04/05 Python
详解Python中的多线程编程
2015/04/09 Python
初探TensorFLow从文件读取图片的四种方式
2018/02/06 Python
python数字图像处理之高级形态学处理
2018/04/27 Python
解决python升级引起的pip执行错误的问题
2018/06/12 Python
python中强大的format函数实例详解
2018/12/05 Python
Python3爬虫关于代理池的维护详解
2020/07/30 Python
CSS3截取字符串实例代码【推荐】
2018/06/07 HTML / CSS
5个你不知道的HTML5的接口介绍
2013/08/07 HTML / CSS
HTML5实现桌面通知 提示功能
2017/10/11 HTML / CSS
在html页面中取得session中的值的方法
2020/08/11 HTML / CSS
生产总经理岗位职责
2013/12/19 职场文书
各营销点岗位职责范本
2014/03/05 职场文书
《黄山奇石》教学反思
2014/04/19 职场文书
励志演讲稿300字
2014/08/21 职场文书
领导班子个人查摆问题对照检查材料
2014/10/02 职场文书
党政领导班子四风问题对照检查材料思想汇报
2014/10/02 职场文书
2015年幼儿园德育工作总结
2015/05/25 职场文书
团队执行力培训心得体会
2015/08/15 职场文书
教师实习自我鉴定总结
2019/08/20 职场文书
分享mysql的current_timestamp小坑及解决
2021/11/27 MySQL