在平时的开发过程中, 我们会遇到一些特殊的应用场景, 如果你想要在执行某种操作之前或者之后你能够得到通知, 并对其进行一些你想要的操作时, 你就可以用 Django 中的信号(signals).Django 提供一个 "信号分发器", 允许解耦的应用在框架的其它地方发生操作时会被通知到, 也就是说在特定事件发生时, 可以发送一个信号去通知所有注册了这个信号的回调, 在回调里进行想要的操作处理.
一. Django 内置信号
Django 内置了对数据表, migrate 命令, url 请求相关(request/response), 使用 test 测试, 连接数据库五大类信号.
- Model signals
- pre_init # model 执行构造方法前, 触发
- post_init # model 执行构造方法后, 触发
- pre_save # model 执行 save 对象保存前, 触发
- post_save # model 执行 save 对象保存前, 触发
- pre_delete # model 执行 delete 对象删除前, 触发
- post_delete # model 执行 delete 对象删除前, 触发
- m2m_changed # model 使用多对多字段操作第三张表前后, 触发
- class_prepared # 程序启动时, 检测已注册的 model 类, 对每个类, 触发
- Management signals
- pre_migrate # 执行 migrate 前, 触发
- post_migrate # 执行 migrate 后, 触发
- Request/response signals
- request_started # 请求到来前, 触发
- request_finished # 请求结束后, 触发
- got_request_exception # 请求异常后, 触发
- Test signals
- setting_changed # 使用 test 测试修改配置文件, 触发
- template_rendered # 使用 test 测试渲染模板时, 触发
- Database Wrappers
- connection_created # 创建数据库连接时, 触发
1. 常用内置信号参数介绍
(1)django.db.models.signals.pre_save
pre_save 处理程序的参数介绍
参数名 参数介绍
sender 模型类
instance 保存的实际实例(保存后的 model 数据对象)
raw 布尔值; True 如果模型完全按照提供的方式保存. 不应该查询 / 修改数据库中的其他记录, 因为数据库可能尚未处于一致状态
using 正在使用的数据库别名
update_fields 要传递给更新的字段集 model.save(), 或者 None 如果 update_fields 未传递给它 save()
(2)django.db.models.signals.post_save
post_save 处理程序的参数介绍
参数名 参数介绍
sender 模型类
instance 保存的实际实例
created 布尔值; True 如果创建了新记录(True 表示数据创建)
raw 布尔值; True 如果模型完全按照提供的方式保存. 不应该查询 / 修改数据库中的其他记录, 因为数据库可能尚未处于一致状态
using 正在使用的数据库别名
update_fields 要传递给更新的字段集 model.save(), 或者 None 如果 update_fields 未传递给它 save()
(3)django.db.models.signals.pre_delete
pre_delete 处理程序的参数介绍
参数名 参数介绍
sender 模型类
instance 要删除的实际实例
using 正在使用的数据库别名
(4)django.db.models.signals.post_delete
post_delete 处理程序的参数介绍
参数名 参数介绍
sender 模型类
instance 要删除的实际实例(该对象将不再存在于数据库中, 因此请谨慎对待此实例)
using 正在使用的数据库别名
更多信号参数介绍请参考 https://docs.djangoproject.com/zh-hans/2.1/ref/signals/
2. 内置信号监听方法
对于 Django 内置的信号, 仅需注册指定信号, 当程序执行相应操作时, 自动触发注册函数. 当你写好一个接收器 (receiver function) 用于接收到信号以后的回调处理后, 就需要将接收器连接到信号, 有两种方法, 手动连接, 跟使用 receiver 装饰器的方式.
手动连接实现方法:
- from django.db.models.signals import post_delete
- def my_callback(sender, **kwargs):
- print(sender)
- print("信号已接收")
- post_delete.connect(my_callback) # 信号连接接收器, 用于收到信号的回调, 如果想要指定某个表对象, 直接指定 sender
- # connect 参数接收
- """
- receiver - 将连接到此信号的回调函数. 回调函数名, 不带括号
- sender - 指定从中接收信号的特定发送方.
- weak - Django 默认将信号处理程序存储为弱引用. 因此, 如果您的接收器是本地功能, 它可能被垃圾收集. 为了防止这种情况, 请 weak=False 在调用信号 connect()方法时通过.
- dispatch_uid - 在可能发送重复信号的情况下信号接收器的唯一标识符.
- """
receiver 装饰器实现方法:
- from django.dispatch import receiver
- from django.db.models.signals import post_delete
- from App.models import UCenter
- @receiver(post_delete, sender=UCenter) # post_delete 指定信号触发类型, sender 指定到具体对象
- def delete_u2user(sender, instance, **kwargs): # instance 表示被删除的对象
- print(sender, instance)
更多信号操作相关问题参考文档 https://docs.djangoproject.com/zh-hans/2.1/topics/signals/
二. 自定义信号使用
1. 定义信号
- from django.dispatch import Signal
- test_signal = Signal(providing_args=["name", "age"]) # 声明一个 test_signal 的信号, 提供给接收器 name 跟 age 两个参数(可自定义参数)
2. 注册信号
- def my_callback(sender, **kwargs):
- print(sender)
- print("信号已接收")
- test_signal.connect(my_callback) # 注册信号, 指定接收器为 my_callback
3. 触发信号
- from xxx import test_signal
- test_signal.send(sender='test', name='zzq', age='18') # 触发信号, 发送 name,age 参数信息
当然这样在选择发送信号的方式有两种一种使用 Signal.send, 还有一种是 Signal.send_robut.
send()与 send_robust()处理接收器功能引起的异常的方式不同.
send()并不能捕获由接收器提出的任何异常; 它只是允许错误传播. 因此, 在面对错误时, 不是所有接收器都可以被通知信号.
send_robust()捕获从 Python Exception 类派生的所有错误, 并确保所有接收器都收到信号通知. 如果发生错误, 则会在引发错误的接收器的元组对中返回错误实例.
来源: https://www.cnblogs.com/zzqit/p/11120756.html