基于Django signals 信号作用及用法详解
作者:陌上花开缓缓归! 发布时间:2021-08-01 10:59:52
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引入即可
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)
来源:https://www.cnblogs.com/fiona-zhong/p/9983996.html


猜你喜欢
- Python学习笔记--坐标轴范围参靠视频:《Python数据可视化分析 matplotlib教程》链接:https://www.bilib
- Conditional-CSS允许你针对单一浏览器或浏览器组写出有逻辑条件的可维护的特定的CSS声明。使CSS针对特定的浏览器。简化你对CS
- 程序是从上到下顺序执行的,同时可以通过一些控制语句来改变执行的路线,受控制语句影响下,程序最终的执行路线就是控制流。js 里面的控制语句有
- 参与测试的浏览器:IE6 / IE7 / IE8 / FF3 / OP9.6 / SF3 / Chrome2操作系统:Windows我喜欢p
- 一、环境要求windows系统,python3.6+安装模块pip install pyqt5pip install pygame二、游戏介
- 什么是命令行参数?命令行参数是在运行时给予程序/脚本的标志。它们包含我们程序的附加信息,以便它可以执行。并非所有程序都有命令行参数,因为并非
- 计划任务工具-windows计划任务工具根据自己设定的具体时间,频率,命令等属性来规定所要执行的计划。效果图代码# -*- coding:
- 前几天和一个小伙伴交流了一下nodejs中epoll和处理请求的一些知识,今天简单来聊一下nodejs处理请求的逻辑。我们从listen函数
- 安装的 MySQL 5.1.48 或是 MySQL 5.5.8,配置好最后点击 Execute 按钮了,但是进行不到 Start servi
- python3 manage.py makemigrations # 生成数据库迁移文件python3 manage.py migrate
- vuex状态刷新网页时数据被清空问题vuex状态管理,在网页刷新数据被清空的解决方法。在main.js中写入下面的代码段(亲测有效)//刷新
- 目的: 从数据库读取二进制位图图形数据资料, 透过 ImageMagickObject 组件即时制作缩略图,并显示在网页上 (ge
- vue切换“页面”(路由)时保持滚动条回到顶部vue项目做pc端的时候,发现在两个页面切换时 滚动条
- 通过上篇文章给大家介绍了SqlServer应用之sys.dm_os_waiting_tasks 引发的疑问(上) ,说了一下sys.dm_e
- 1.操作数据库 1.1创建数据库create + database + 数据库名称当然如果我们不知道数据库是否存在,如果存在就不创
- 前言使用Django服务网页时,只要用户执行导致页面更改的操作,即使该更改仅影响页面的一小部分,它都会将完整的HTML模板传递给浏览器。 但
- 本文通过将同一个数据集在三种不同的简便项窗口部件中显示。三个窗口的数据得到实时的同步,数据和视图分离。当添加或删除数据行,三个不同的视图均保
- 0 环境Python版本:3.6.8系统版本:macOS MojavePython Jupyter Notebook1 引言七月了,大家最近
- 本文较为详细的分析了了Python的对象体系。分享给大家供大家参考。具体如下:Guido用C语言创造了Python,在Python的世界中一
- 场景我们一般没必要过度优化 Go 程序性能。但是真正需要时,Go 提供的 pprof 工具能帮我们快速定位到问题。比如,我们团队之前有一个服