Django提供一种信号机制,一些动作发生时,会触发信号,然后监听了这个信号的函数就会被执行。比如,实现数据库每写入一条数据,写一条日志。要实现这个需求,可以通过全局的中间件来做,但是利用Django的信号机制会更灵活。中间件只作用在请求进来和响应出去时,而信号的散布范围更广。
我们先看看Django内置了哪些信号:
Model signals
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate # 执行migrate命令前,自动触发
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发
导入信号 –> 将回调函数注册到信号上 ;
注意,只有执行了注册代码,才能在信号发生时,执行注册的函数。因此,为了能在服务启动时,执行注册代码,应该将注册信号的操作写在项目的__init__.py
中
from django.db.models.signals import post_save # 导入信号
def callback1(sender, **kwargs): # 定义回调函数, 作为信号的接收者
print('create a new user')
print(sender, kwargs)
def callback2(sender, **kwargs):
pass
def callback3(sender, **kwargs):
pass
post_save.connect(callback1)
# 我们也可以为信号注册多个函数
# post_save.connect(callback2)
# post_save.connect(callback3)
下面在视图中往数据库新增一条记录:
def add(request):
u = UserInfo(name='sb',pwd='123')
u.save()
return HttpResponse('save ok')
通过浏览器访问http://127.0.0.1:8000/add/
来执行add视图,models.UserInfo
触发信号,回调函数收到信号,执行。查看打印结果:
create a new user
'app01.models.UserInfo' > {'signal': at 0x000001CA5118DDA0>, 'instance': , 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'}
回调的方式注册信号,我们也可以通过装饰器的方式:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save)
def callback(sender, **kwargs):
pass
我们可以将自定义的信号单独写在一个脚本:
import django.dispatch
my_signal = django.dispatch.Signal(providing_args=['arg1', 'arg2'])
# providing_args中的参数自定义
在项目的__init__.py
中注册自定义信号:
from my_signal import my_signal
def callback(sender, **kwargs):
pass
my_signal.connect(callback)
在需要用到自定义信号的地方,导入自定义信号,给它发送信号:
from my_signal import my_signal
my_signal.send(sender='', arg1='', arg2='')