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