From f7675c6ff7bf107a98044dd5508624a576ad9117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E9=9B=A8=E8=8F=B2?= <2574550132@qq.com> Date: Sun, 9 Nov 2025 21:38:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20logentryadmin.py=20?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- djangoblog/logentryadmin.py | 87 ++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/djangoblog/logentryadmin.py b/djangoblog/logentryadmin.py index 2f6a5353..4ac7f9b8 100644 --- a/djangoblog/logentryadmin.py +++ b/djangoblog/logentryadmin.py @@ -1,91 +1,136 @@ +#姜雨菲: 导入Django管理后台核心模块 from django.contrib import admin -from django.contrib.admin.models import DELETION -from django.contrib.contenttypes.models import ContentType +#姜雨菲: 导入日志相关常量和模型 +from django.contrib.admin.models import DELETION # 表示"删除"操作的常量 +from django.contrib.contenttypes.models import ContentType # 内容类型模型,用于关联不同模型 +#姜雨菲: 导入URL反向解析和异常处理 from django.urls import reverse, NoReverseMatch +# 导入字符串处理工具 from django.utils.encoding import force_str +# 导入HTML转义工具 from django.utils.html import escape +# 导入安全字符串标记工具(用于渲染HTML) from django.utils.safestring import mark_safe +# 导入国际化翻译工具 from django.utils.translation import gettext_lazy as _ class LogEntryAdmin(admin.ModelAdmin): + """ + 自定义管理员日志(LogEntry)的管理类 + 用于在Django admin后台展示和管理系统操作日志 + """ + + # 列表页的筛选器:按内容类型筛选 list_filter = [ 'content_type' ] + # 搜索字段:支持按对象表示和变更消息搜索 search_fields = [ - 'object_repr', - 'change_message' + 'object_repr', # 对象的字符串表示 + 'change_message' # 操作变更的描述信息 ] + # 列表页中可点击的链接字段 list_display_links = [ - 'action_time', - 'get_change_message', + 'action_time', # 操作时间 + 'get_change_message', # 变更消息 ] + + # 列表页展示的字段 list_display = [ - 'action_time', - 'user_link', - 'content_type', - 'object_link', - 'get_change_message', + 'action_time', # 操作时间 + 'user_link', # 操作用户(带链接) + 'content_type', # 操作的内容类型(模型) + 'object_link', # 操作的对象(带链接) + 'get_change_message', # 变更消息 ] def has_add_permission(self, request): + """禁用添加权限:不允许手动添加日志记录""" return False def has_change_permission(self, request, obj=None): + """ + 限制修改权限: + - 仅超级用户或拥有change_logentry权限的用户可查看 + - 禁止POST请求(即不允许修改日志内容) + """ return ( request.user.is_superuser or request.user.has_perm('admin.change_logentry') ) and request.method != 'POST' def has_delete_permission(self, request, obj=None): + """禁用删除权限:不允许删除日志记录""" return False def object_link(self, obj): + """ + 生成操作对象的链接(若对象存在) + 对于已删除的对象,仅显示文本;对于存在的对象,显示可点击的链接 + """ + # 先对对象的字符串表示进行HTML转义,防止XSS攻击 object_link = escape(obj.object_repr) + # 获取操作对象的内容类型 content_type = obj.content_type + # 如果不是删除操作且内容类型存在,尝试生成编辑链接 if obj.action_flag != DELETION and content_type is not None: - # try returning an actual link instead of object repr string try: + # 反向解析对象的编辑页面URL url = reverse( + # 生成admin的URL名称格式:app_label_model_change 'admin:{}_{}_change'.format(content_type.app_label, content_type.model), - args=[obj.object_id] + args=[obj.object_id] # 传递对象ID作为参数 ) + # 生成带链接的HTML object_link = '{}'.format(url, object_link) except NoReverseMatch: + # 若无法解析URL(如模型未注册到admin),则只显示文本 pass + # 标记为安全字符串,允许Django渲染HTML return mark_safe(object_link) - object_link.admin_order_field = 'object_repr' - object_link.short_description = _('object') + # 配置列表页字段的排序和显示名称 + object_link.admin_order_field = 'object_repr' # 允许按对象表示排序 + object_link.short_description = _('object') # 列表页显示的列名(支持国际化) def user_link(self, obj): + """生成操作用户的链接(指向用户编辑页面)""" + # 获取用户模型的内容类型 content_type = ContentType.objects.get_for_model(type(obj.user)) + # 对用户名进行HTML转义 user_link = escape(force_str(obj.user)) try: - # try returning an actual link instead of object repr string + # 反向解析用户编辑页面的URL url = reverse( 'admin:{}_{}_change'.format(content_type.app_label, content_type.model), - args=[obj.user.pk] + args=[obj.user.pk] # 传递用户ID作为参数 ) + # 生成带链接的HTML user_link = '{}'.format(url, user_link) except NoReverseMatch: + # 若无法解析URL,只显示用户名 pass + # 标记为安全字符串,允许渲染HTML return mark_safe(user_link) - user_link.admin_order_field = 'user' - user_link.short_description = _('user') + # 配置用户链接字段的排序和显示名称 + user_link.admin_order_field = 'user' # 允许按用户排序 + user_link.short_description = _('user') # 列表页显示的列名(支持国际化) def get_queryset(self, request): + """优化查询集:预加载content_type,减少数据库查询次数""" queryset = super(LogEntryAdmin, self).get_queryset(request) - return queryset.prefetch_related('content_type') + return queryset.prefetch_related('content_type') # 使用预加载优化性能 def get_actions(self, request): + """移除批量删除操作:不允许批量删除日志""" actions = super(LogEntryAdmin, self).get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] - return actions + return actions \ No newline at end of file