Django利用LogEntry生成历史操作实战记录
作者:Tsissan's?Blog 发布时间:2021-10-23 04:23:58
在开发测试平台的时候,虽然对某些关键功能做了权限设置,但毕竟是公司多人使用,有些数据的配置可能不小心被他人修改但未告知其他使用者,造成了诸多不便。所以决定开发一个操作历史表,可以方便查看数据地改动。
LogEntry是在后台开发中经常用到的模块,它在admin是默认开启的。
可以使用LogEntry模块记录所有用户的操作记录。一方面可以用来监督,另一方面可以用来做回滚。
使用LogEntry
ModelAdmin本身就有日志记录功能。当新建一个实体(Post、Category、Tag)时,ModelAdmin会创建一条变更日志记录。当修改一条内容时,ModelAdmin又会调用LogEntry来创建一条日志,记录这个变更。
ModelAdmin内部提供了两个方法,分别是log_addition和log_change。
log_addition记录新增日志。
log_change记录变更日志。
log_deletion记录删除日志。
我们可以看它们的定义来学习LogEntry模块
代码位置:Lib\site-packages\django\contrib\admin\options.py
def log_addition(self, request, object, message):
"""
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
"""
from django.contrib.admin.models import LogEntry, ADDITION
return LogEntry.objects.log_action(
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
object_repr=str(object),
action_flag=ADDITION,
change_message=message,
)
def log_change(self, request, object, message):
"""
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
"""
from django.contrib.admin.models import LogEntry, CHANGE
return LogEntry.objects.log_action(
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
object_repr=str(object),
action_flag=CHANGE,
change_message=message,
)
def log_deletion(self, request, object, object_repr):
"""
Log that an object will be deleted. Note that this method must be
called before the deletion.
The default implementation creates an admin LogEntry object.
"""
from django.contrib.admin.models import LogEntry, DELETION
return LogEntry.objects.log_action(
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
object_repr=object_repr,
action_flag=DELETION,
)
从以上代码可以看出:这两个方法都调用了LogEntry.objects.log_action方法,只是参数略有不同,可以看到,如果需要自定义变更记录的话,只需要传递对应的参数即可。以下简要介绍一下这些参数。
user_id:当前用户id
content_type_id:要保存内容的类型,上面的代码中使用的是get_.content_type_for_model方法拿到对应Model的类型id。这可以简单理解为ContentType为每个Model定义了一个类型id
object_id:记录变更实例的id
object_repr:实例的展示名称,可以简单理解为我们定义的__str__所返回的内容
action_flag:操作标记。admin的Model里面定义了几种基础的标记: ADDITION、CHANGE和DELETION。它用来标记当前参数是数据变更、新增,还是删除。
change_message:这是记录的消息,可以自行定义。我们可以把新添加的内容放进去(必要时可以通过这里来恢复),也可以把新旧内容的区别放进去。
理解了这几个参数,如果遇到类似的需求,就能直接使用Django现成的工具来完成了。
查询某个对象的变更
上面我们知道如何记录某个对象的变更日志了,那么问题来了,如何在询已经记录的变更呢?
其实这是简单的Model查询问题。假设我们记录的对象是Post的操作,现在来获取Post中id为1的所有变更日志,大概代码如下:
from django.contrib.admin.models import LogEntry, CHANGE
from django.contrib.admin.options import get_content_type_for_model
post = Post.objects.get(id=1)
log_entries = LogEntry.objects.filter(
content_type_id=get_content_type_for_model(post).id,
object_id=post.id)
这样我们就拿到了id为1的所有变更记录了。
在admin页面上查看操作日志
我们既知道如何记录变更日志,也知道如何获取变更日志,那么如何才能够在admin后台方便地查看操作日志呢?
新增如下配置(admin.py):
#最上面增加import
from django.contrib.admin.models import LogEntry
#文件最下方增加
@adnin.register(LogEntry, site=custom_site)
class LogEntryAdmin(admin.ModelAdmin):
list_display = ['object_repr','object_ id','action_flag','user','change_message']
这样就可以看到所有的变更记录了。如下图所示:
实战
虽然操作历史显示出来了,但是在django自带的admin后台才能看到,不是所有人都有进入admin后台权限,能不能有一种方法能在前端展示出来让每个人都可以查看呢?
前端代码:
<table class="table table-bordered" style="width: 60%;margin-left: 20%;text-align: center">
<caption style="text-align: center">
<span style="font-size: large;color: black">项目:【<span style="color: pink">{{ client.name }}</span>】的操作记录: </span>
</caption>
<thead>
<tr style="background-color: #cdd8e5">
<th style="width: 100px;text-align: center">操作时间</th>
<th style="width: 200px;text-align: center">操作对象</th>
<th style="width: 50px;text-align: center">对象id</th>
<th style="width: 100px;text-align: center">动作标志</th>
<th style="width: 100px;text-align: center">操作用户</th>
<th style="width: 300px;text-align: center">修改内容</th>
</tr>
</thead>
<tbody>
{% for i in objects %}
<tr>
<td>{{ i.action_time }}</td>
<td>{{ i.object_repr }}</td>
<td>{{ i.object_id }}</td>
<td>{{ i.get_action_flag_display }}</td>
<td>{{ i.user }}</td>
<td>{{ i.change_message }}</td>
</tr> {% endfor %}
</tbody>
</table>
这里有个坑,如果就利用{{i.action_flag}}获取操作标记的话,得到的是索引值,经过stackoverflow.com查阅,需要利用Django-doc(用您要在其文本表示形式中“翻译”的字段名称替换)来获取相应值,因此:get_fieldname_display,所以这里要写成{{ i.get_action_flag_display }}
后端代码(views.py):
# 导入所需的包
from django.contrib.admin.models import LogEntry, CHANGE, ADDITION, DELETION
from django.contrib.admin.options import get_content_type_for_model
res = dict()
res['objects'] = LogEntry.objects.all() # 获取到所有操作历史
# 只需要调用LogEntry.objects.log_action方法带入所需参数即可
LogEntry.objects.log_action(
user_id=request.user.pk, # 操作用户的id
content_type_id=get_content_type_for_model(object).pk, # 对应数据库Model的id
object_id=object.pk, # 操作对象的id
object_repr=object_repr, # 操作对象的名字
action_flag=DELETION, # ADDITION、CHANGE和DELETION三种方式选择合适的
change_message='' # 自定义消息,可以放入修改之后的数据
)
实现效果
参考资料:https://www.cnblogs.com/zihao1037/p/11057341.html
来源:https://www.cnblogs.com/lookingforfreedom/p/15717729.html


猜你喜欢
- file_get_contents的超时处理话说,从PHP5开始,file_get_content已经支持context了(手册上写着:5.
- 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。示例 1:输入: head = [4,5,1,
- 我有大量的重要数据要从SQL Server导出到Access或Excel文件中去,手工做太麻烦,还有其它的好办法吗?有,我们在 SQL Se
- cli 的全称 command-line interface(命令行界面),也就是前端同学常用的脚手架,比如 yo、vue cli、reac
- 前言:tkinter提供了3种布局管理方式:1、pack2、grid3、place每种布局管理器都非常有用,根据不同的需求,选择对应的布局方
- 概述据说fastapi是目前最快的异步框架,遂决定将其和django异步进行并发比较。先说结果fastapi的异步可以使整体运行速度非常均衡
- 前言写这次博客其实事出有因,前几天呢,一个非常优秀的学姐在QQ空间里晒了自己的CSDN博客的总阅读量,达到了7万+,很厉害了,而且确实她的博
- MySQL批量插入数据脚本#!/bin/bashi=1;MAX_INSERT_ROW_COUNT=$1;while [ $i -le $MA
- 模块之turtle小故事前两天朋友说:“常文啊!听说你会python,那能不能用python画一些好看的图呢?”然后我特意去学了一下turt
- 利用Python制作自动抢火车票小程序,过年再也不要担心没票了!前言每次过年很多人都会因为抢不到火车票而回不了家,所以小编利用Python写
- SQL Server推荐使用 SET 而不是 SELECT 对变量进行赋值。当表达式返回一个值并对一个变量进行赋值时,推荐使用 SET 方法
- Python中生成器和迭代器的区别(代码在Python3.5下测试):Num01–>迭代器定义:对于list、string、tuple
- 这个分页使用的是0游标,也就是Rs.Open Sql,Conn,0,1。但是感觉也快不了多少,10万条数据的分页时间300多豪秒之间。风格A
- 前言本文将由浅入深详细介绍yield以及generator,包括以下内容:什么generator,生成generator的方法,genera
- 本文实例讲述了JS小游戏的象棋暗棋源码,分享给大家供大家参考。具体如下:游戏运行后如下图所示:Javascript 部分:/** chine
- 最近人工智能等多门课需要复现论文,近两年的论文很多都是基于Pytorch环境做的实验,所以,这里总结一下Pytorch的安装教程,做好最快、
- 写models.py时缺少了一个 verbose_name,导致数据库出现问题,整了很久,摸索出重新建立数据库的方法:首先删除每个app中的
- jupyter notebookjupyter不被识别为内部或外部命令,可操作程序或批处理文件'上次 jupyter noteboo
- 本文实例讲述了Python实现获取系统临时目录及临时文件的方法。分享给大家供大家参考,具体如下:在开发应用程序的过程中,会有一些临时的信息,
- 本文实例讲述了python追加元素到列表的方法。分享给大家供大家参考。具体实现方法如下:scores = ["1",&q