You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tentest/doc/DjangoBlog/djangoblog/logentryadmin.py

137 lines
6.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from django.contrib import admin # 导入Django Admin核心模块
from django.contrib.admin.models import DELETION # 导入表示"删除"操作的常量
from django.contrib.contenttypes.models import ContentType # 导入内容类型模型(用于关联不同模型)
from django.urls import reverse, NoReverseMatch # 导入URL反向解析工具及异常
from django.utils.encoding import force_str # 用于字符串编码转换兼容Python 2/3
from django.utils.html import escape # 用于HTML转义防止XSS攻击
from django.utils.safestring import mark_safe # 标记安全的HTML字符串允许在模板中渲染
from django.utils.translation import gettext_lazy as _ # 国际化翻译工具
class LogEntryAdmin(admin.ModelAdmin):
"""
wr自定义LogEntry模型的Admin配置类
LogEntry是Django自带的模型用于记录管理员在后台的操作日志如新增、修改、删除对象
此类控制日志在Admin后台的显示、搜索、过滤及操作权限
"""
#wr 列表页的过滤条件(右侧过滤器):按内容类型(即操作的模型类型)过滤
list_filter = [
'content_type'
]
#wr 搜索字段可通过对象名称object_repr和操作描述change_message搜索日志
search_fields = [
'object_repr',
'change_message'
]
#wr 列表页中可点击的字段(点击跳转到日志详情页)
list_display_links = [
'action_time', #wr 操作时间
'get_change_message', #wr 操作描述(自定义方法)
]
#wr 列表页显示的字段(按顺序排列)
list_display = [
'action_time', #wr 操作时间
'user_link', #wr 操作人(带链接的自定义字段)
'content_type', #wr 操作的模型类型(如文章、用户等)
'object_link', #wr 操作的对象(带链接的自定义字段)
'get_change_message', #wr 操作描述Django原生方法返回格式化的操作信息
]
def has_add_permission(self, request):
"""
wr控制是否允许添加日志条目返回False禁止手动添加日志
原因:日志是系统自动记录的,不允许人工干预
"""
return False
def has_change_permission(self, request, obj=None):
"""
wr控制是否允许修改日志条目仅允许超级用户或有修改权限的用户以非POST方式访问即仅查看
原因:日志记录应保持原始性,禁止修改
"""
return (
request.user.is_superuser or #wr 超级用户有权限
request.user.has_perm('admin.change_logentry') #wr 有明确权限的用户
) and request.method != 'POST' #wr 禁止POST请求即禁止提交修改
def has_delete_permission(self, request, obj=None):
"""
wr控制是否允许删除日志条目返回False禁止删除日志
原因:日志是系统操作记录,需长期保存用于审计
"""
return False
def object_link(self, obj):
"""
wr自定义字段显示操作对象的链接若存在
功能如果操作不是删除且能获取到内容类型尝试生成对象的Admin修改页链接
"""
object_link = escape(obj.object_repr) #wr 转义对象名称防止XSS
content_type = obj.content_type #wr 获取操作的模型类型
#wr 若操作不是删除,且内容类型存在(即有对应的模型)
if obj.action_flag != DELETION and content_type is not None:
try:
#wr 生成对象在Admin中的修改页URL格式admin:应用名_模型名_change
url = reverse(
'admin:{}_{}_change'.format(content_type.app_label,
content_type.model),
args=[obj.object_id] #wr 传入对象ID
)
#wr 生成带链接的对象名称
object_link = '<a href="{}">{}</a>'.format(url, object_link)
except NoReverseMatch:
#wr 若URL反向解析失败如模型未注册到Admin则仅显示对象名称
pass
return mark_safe(object_link) #wr 标记为安全HTML允许在页面渲染链接
#wr 配置自定义字段的排序和显示名称
object_link.admin_order_field = 'object_repr' #wr 允许按对象名称排序
object_link.short_description = _('object') #wr 列表页表头显示名称(支持国际化)
def user_link(self, obj):
"""
wr自定义字段显示操作人的链接跳转到用户的Admin修改页
"""
#wr 获取操作人User模型的内容类型
content_type = ContentType.objects.get_for_model(type(obj.user))
user_link = escape(force_str(obj.user)) #wr 转义用户名并确保为字符串
try:
#wr 生成用户在Admin中的修改页URL
url = reverse(
'admin:{}_{}_change'.format(content_type.app_label,
content_type.model),
args=[obj.user.pk] #wr 传入用户ID
)
#wr 生成带链接的用户名
user_link = '<a href="{}">{}</a>'.format(url, user_link)
except NoReverseMatch:
#wr 若URL解析失败仅显示用户名
pass
return mark_safe(user_link) #wr 标记为安全HTML
#wr 配置自定义字段的排序和显示名称
user_link.admin_order_field = 'user' #wr 允许按用户排序
user_link.short_description = _('user') #wr 列表页表头显示名称(支持国际化)
def get_queryset(self, request):
"""
wr优化查询集预加载content_type关联数据减少数据库查询次数
提升列表页加载性能避免N+1查询问题
"""
queryset = super(LogEntryAdmin, self).get_queryset(request)
return queryset.prefetch_related('content_type') #wr 预加载content_type
def get_actions(self, request):
"""
wr移除"删除选中项"操作:确保日志无法通过批量操作删除
"""
actions = super(LogEntryAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected'] #wr 删除批量删除操作
return actions