基于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中实现k-means聚类算法详解
Nov 11 Python
python如何去除字符串中不想要的字符
Jul 05 Python
用Python读取几十万行文本数据
Dec 24 Python
pyqt5 获取显示器的分辨率的方法
Jun 18 Python
python之pexpect实现自动交互的例子
Jul 25 Python
python面向对象之类属性和类方法案例分析
Dec 30 Python
python使用ctypes调用扩展模块的实例方法
Jan 28 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
Jun 03 Python
python如何保存文本文件
Jun 07 Python
python numpy库np.percentile用法说明
Jun 08 Python
python中pandas库中DataFrame对行和列的操作使用方法示例
Jun 14 Python
Pycharm2020.1安装中文语言插件的详细教程(不需要汉化)
Aug 07 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
thinkphp模板继承实例简述
2014/11/26 PHP
php+html5使用FormData对象提交表单及上传图片的方法
2015/02/11 PHP
ecshop 2.72如何修改后台访问地址
2015/03/03 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
2015/12/07 PHP
常见的5个PHP编码小陋习以及优化实例讲解
2021/02/27 PHP
js 加载时自动调整图片大小
2008/05/28 Javascript
jQuery温习篇 强大的JQuery选择器
2010/04/24 Javascript
Javascript 面向对象 继承
2010/05/13 Javascript
jQuery 获取URL的GET参数值的小例子
2013/04/18 Javascript
用js实现in_array的方法
2013/11/05 Javascript
JS+CSS 制作的超级简单的下拉菜单附图
2013/11/22 Javascript
JavaScript网页定位详解
2014/01/13 Javascript
关闭时刷新父窗口两种方法
2014/05/07 Javascript
javascript抽象工厂模式详细说明
2014/12/16 Javascript
常用的JavaScript WEB操作方法分享
2015/02/28 Javascript
js实现用户离开页面前提示是否离开此页面的方法(包括浏览器按钮事件)
2015/07/18 Javascript
js实现4个方向滚动的球
2017/03/06 Javascript
vue.js实现用户评论、登录、注册、及修改信息功能
2020/05/30 Javascript
angular $watch 一个变量的变化(实例讲解)
2017/08/02 Javascript
React如何利用相对于根目录进行引用组件详解
2017/10/09 Javascript
vue2.0 父组件给子组件传递数据的方法
2018/01/15 Javascript
浅谈Vue2.0中v-for迭代语法的变化(key、index)
2018/03/06 Javascript
Bootstrap开发中Tab标签页切换图表显示问题的解决方法
2018/07/13 Javascript
ptyhon实现sitemap生成示例
2014/03/30 Python
在Mac OS上部署Nginx和FastCGI以及Flask框架的教程
2015/05/02 Python
Python heapq使用详解及实例代码
2017/01/25 Python
python3 实现对图片进行局部切割的方法
2018/12/05 Python
Python通用循环的构造方法实例分析
2018/12/19 Python
Python 实现文件读写、坐标寻址、查找替换功能
2019/09/11 Python
python 可视化库PyG2Plot的使用
2021/01/21 Python
CSS3 分类菜单效果
2019/05/27 HTML / CSS
高三高考决心书
2014/03/11 职场文书
焦裕禄精神心得体会
2014/09/02 职场文书
党员学习党的群众路线思想汇报(5篇)
2014/09/10 职场文书
MYSQL(电话号码,身份证)数据脱敏的实现
2021/05/28 MySQL
Win11电源已接通但未充电怎么办?Win11电源已接通未充电的解决方法
2022/04/05 数码科技