Django 信号
django自带一套信号机制来帮助我们在框架的不同位置之间传递信息。也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(signals)发送给一组接受者(receivers)
信号系统三要素:
- 信号 <class: django.dispatch.Signal > 的实例
- 发送方 某一个信号的发送者
- 接收方 一个或多个信号的接收者
信号的分类:
- Django 内置信号, 框架内置的 Signal 实例, 发送 方 为 Django 框架
- 自定义 信号 , 开发者 手动创建 Signal 实例, 且需指定发送方 和 接收方
Django 内置信号:
框架位置: 位于框架 signals.py 文件中。 例如 框架内置的各 app 目录下的 djangocontribAPPsignals.py 文件中 和djangocoresignals.py 文件中。
# 在ORM模型的save()方法调用之前或之后发送信号:
django.db.models.signals.pre_save
django.db.models.signals.post_save
# 在ORM模型或查询集的delete()方法调用之前或之后发送信号:
django.db.models.signals.pre_delete
django.db.models.signals.post_delete
# 当多对多字段被修改时发送信号:
django.db.models.signals.m2m_changed
# 当接收和关闭HTTP请求时发送信号:
django.core.signals.request_started
django.core.signals.request_finished
# 规律 : 以 'pre' 开头的 代表动作之前的, 而以 'post' 开头 代表动作之后的
具体 Django 信号内容
定义信号
所有的信号都是django.dispatch.Signal
的实例
方法原型:
def __init__(self, providing_args=None, use_caching=False):[source]
"""
providing_args: 信号提供 给接收者 的参数列表
use_caching :是否对于每个不同的发送者缓存发送者所拥有的接收者
"""
# 注意: 参数可都为空
发送信号
Django中有两种方法用于发送信号。
Signal.send(sender, **kwargs)[source]
Signal.send_robust(sender,** kwargs)[source]
"""
注意: 1. 必须提供 sender 参数(大部分情况下是一个类名), 表明 发送方的身份
2. 可以提供任意数量的其他关键字参数
"""
send()和send_robust()返回一个元组对的列表[(receiver, response), ... ],表示接收器和响应值二元元组的列表。
例如: 在视图 函数可定义如下
class Panda(View):
def get(self,request):
Signal.send(sender=self.__class__,) ##
return HttpResponse("shiwei is Good")
def post(self, request):
Signal.send_robust(sender=self.__class__) ##
return JsonResponse({
"code": 200,
'msg': "is Successful",
})
接收信号
Django 使用 Signal 实例的 connect() 方法用于接收一个指定的信号,
方法原型:
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
"""
receiver : 当前信号连接的回调函数,也就是处理信号的函数。
sender : 指定从哪个发送方接收信号。
weak : 是否弱引用
dispatch_uid :信号接收器的唯一标识符,以防信号多次发送。
"""
注意: 接收信号时 可不指定 信号的发送方 sender 参数,代表 此种信号 都 接收。
第二种 接收信号的 方式为使用 装饰器。 在处理信号的回调函数之上。此种方式内部 也是依次调用每个 信号实例的 connct() 方法 来接收。
方法原型
def receiver(signal, **kwargs):
def _decorator(func):
if isinstance(signal, (list, tuple)): # 第一个 参数 可为信号实例的 元组 或 列表
for s in signal:
s.connect(func, **kwargs)
else:
signal.connect(func, **kwargs)
return func
return _decorator
信号接收器
所谓 信号接收器 就是 接收到信号之后的触发动作, 一般为一个函数,
def signal_callback(sender, **kwargs):
print("is my callback")
"""
注意:所有的接收器都必须接收一个sender参数和一个**kwargs通配符参数
"""
防止重复信号
为了防止重复信号,可以设置dispatch_uid
参数来标识你的接收器,标识符通常是一个字符串,如下所示
from django.core.signals import request_finished
request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
最后的结果是,对于每个唯一的dispatch_uid
值,你的接收器都只绑定到信号一次
Django 内置信号操作步骤
from django.core.signals import request_finished # 导入 信号
request_finished.connect(callback_func) # 接收 信号 , 并 指定 回调函数
自定义信号操作步骤
创建文件
Django 定义信号一般都存储于 app 目录下的 signals.py 文件中, 故首先在 app 目录下 创建一个 signals.py 文件
自定义信号
在 第一步定义的 signals.py 中:
from django.dispatch import Signal
suosuo_signal = Signal()
自定义信号接收器
可在任意位置, 一般 放置 与 和在 信号发送语句 同一个 文件中, 例如 视图文件 views.py 中
from django.dispatch import receiver
@receiver(signal=[suosuo_signal,], sender=SuoSuo) # signal 必须指定, sender 可选
def basket(sender, **kwargs): # 两个 参数必须 同样指定
print('Signal %s, callback func: basket '%sender.__name__)
print('SuoSuo 的 信号接收器')
自定义 信号发送语句
例如 在 views.py 中
from django.views import View
from django.http import HttpResponse, JsonResponse
from suosuo.signals import suosuo_signal
class SuoSuo(View):
def get(self,request):
suosuo_signal.send(sender=self.__class__,)
return HttpResponse("SuoSuo is Good")
def post(self, request):
suosuo_signal.send_robust(sender=self.__class__)
return JsonResponse({
"code": 200,
'msg': "is Successful",
})