Django学习之信号
如果我想对所有在数据库创建数据的时候记录一条日志。
比如我们在django中往数据库中增加一条数据,希望生成一条操作日志,或者在数据保存和数据保存之后都保存一条操作日志,那我们应该怎么办呢?
有很多人可能会想到用装饰器来实现,但是 装饰器一般是写在函数上面的,如果我们在函数中执行了不止一条数据库操作(如下面的代码),那记录下来的只能只有一条数据日志,也就是说装饰器只有在统一操作的时候记录下东西。
def signal(request): from app01 import models obj = models.UserInfo(user='root') obj.save() obj = models.UserInfo(user='root') obj.save() obj = models.UserInfo(user='root') obj.save()
那我们应该怎么做呢?
在django中,django在创建这个对象的前后预留了两个位置,在models.UserInfo()前后留了两个位置,在obj.save前后也留了两个位置,相当于有4个位置可以进行操作
我们查看一下save函数的源代码,发现save_base函数中触发了一个信号, 在这个post_save信号中我们可以注册很多函数,比如3个函数,如果我们一运行save函数,执行到post_save.send, 它会把那3个函数挨个执行一遍。
那我们只要找到这个信号,往这个信号中注册一个函数:一旦写了这个操作就帮你记录一下。就可以了。而我们程序的内部一点都不需要改动
django中内置信号:
Model signals pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发
如:models.UserInfo() pre_save # django的modal对象保存前,自动触发 post_save # django的modal对象保存后,自动触发
如:obj.save() pre_delete # django的modal对象删除前,自动触发 post_delete # django的modal对象删除后,自动触发
如:remove() m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发 class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发 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.我们先创建一个sg.py用来存放信号,并写上函数:
from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception from django.db.models.signals import class_prepared from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_delete, post_delete from django.db.models.signals import m2m_changed from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed from django.test.signals import template_rendered from django.db.backends.signals import connection_created def f1(sender, **kwargs):#这两个参数都会传到信号中的参数中 print("xxoo_callback") # print(sender, kwargs) #按顺序执行 pre_init.connect(f1) # xxoo.connect(callback) # xxoo指上述导入的内容
这里面想要用哪个信号就导入哪个
2.项目目录中的init.py中导入sg.py:
views.py:
1 def signal(request): 2 from app01 import models 3 obj = models.UserInfo(user='root') 4 print("end") 5 obj.save() 6 7 obj = models.UserInfo(user='root') 8 obj.save() 9 10 obj = models.UserInfo(user='root') 11 obj.save()
我们先注释掉print(sender,kwargs)看看运行效果
当然我们感觉如果内置的信号不够用 的话,我们还可以自定义信号:
1.创建一个信号
import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])#send中的参数
2.在信号中注册函数
def callback(sender, **kwargs): print("callback") print(sender,kwargs) pizza_done.connect(callback)
3.主动触发信号
from 路径 import pizza_done pizza_done.send(sender='seven',toppings=123, size=456)
和django的源码差不多,都调用send