基于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 相关文章推荐
Android分包MultiDex策略详解
Oct 30 Python
python机器学习案例教程——K最近邻算法的实现
Dec 28 Python
Python3爬虫教程之利用Python实现发送天气预报邮件
Dec 16 Python
python绘制已知点的坐标的直线实例
Jul 04 Python
关于pytorch中网络loss传播和参数更新的理解
Aug 20 Python
Python3 无重复字符的最长子串的实现
Oct 08 Python
python图像处理模块Pillow的学习详解
Oct 09 Python
python os.path.isfile()因参数问题判断错误的解决
Nov 29 Python
Python中求对数方法总结
Mar 10 Python
解决pycharm debug时界面下方不出现step等按钮及变量值的问题
Jun 09 Python
python 元组和列表的区别
Dec 30 Python
Python中字符串对象语法分享
Feb 24 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+mysql来做一个功能强大的在线计算器
2010/10/12 PHP
PHP常用数组函数介绍
2014/07/28 PHP
php实现获取文章内容第一张图片的方法
2014/11/04 PHP
windows7下php开发环境搭建图文教程
2015/01/06 PHP
PHP中FTP相关函数小结
2016/07/15 PHP
Jquery知识点一 Jquery的ready和Dom的onload的区别
2011/01/15 Javascript
jQuery div层的放大与缩小简单实现代码
2013/03/28 Javascript
JS二维数组的定义说明
2014/03/03 Javascript
纯javascript版日历控件
2016/11/24 Javascript
JS 终止执行的实现方法
2016/11/24 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案
2017/03/13 Javascript
jQuery滑动到底部加载下一页数据的实例代码
2017/05/22 jQuery
微信小程序实现锚点功能
2019/11/20 Javascript
[00:50]深扒TI7聊天轮盘语音出处6
2017/05/11 DOTA
python 使用get_argument获取url query参数
2017/04/28 Python
Python中顺序表原理与实现方法详解
2019/12/03 Python
Python Django路径配置实现过程解析
2020/11/05 Python
python单例模式的应用场景实例讲解
2021/02/24 Python
HTML5实现的图片无限加载的瀑布流效果另带边框圆角阴影
2014/03/07 HTML / CSS
化学实验员岗位职责
2013/12/28 职场文书
自立自强的名人事例
2014/02/10 职场文书
《狮子和兔子》教学反思
2014/03/02 职场文书
文明倡议书范文
2014/04/15 职场文书
小学二年级学生评语
2014/04/21 职场文书
师范生求职自荐信
2014/06/14 职场文书
医院护士党的群众路线教育实践活动对照检查材料思想汇报
2014/10/04 职场文书
兼职安全员岗位职责
2015/02/15 职场文书
办公室主任岗位职责范本
2015/03/31 职场文书
幼儿园重阳节活动总结
2015/05/05 职场文书
昆虫记读书笔记
2015/06/26 职场文书
如何制定一份可行的计划!
2019/06/21 职场文书
2019年最新借条范本!
2019/07/08 职场文书
Python3 使用pip安装git并获取Yahoo金融数据的操作
2021/04/08 Python
SQL实现LeetCode(196.删除重复邮箱)
2021/08/07 MySQL
golang 语言中错误处理机制
2021/08/30 Golang