From 9e31e3db5ee3538e615425bb45e4c40c99c69254 Mon Sep 17 00:00:00 2001 From: plhw57tbe <2723863608@qq.com> Date: Sun, 19 Oct 2025 23:21:41 +0800 Subject: [PATCH] Update logentryadmin.py --- .../djangoblog/logentryadmin.py | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/DjangoBlog-master/djangoblog/logentryadmin.py b/src/DjangoBlog-master/djangoblog/logentryadmin.py index 2f6a535..ac3f7cb 100644 --- a/src/DjangoBlog-master/djangoblog/logentryadmin.py +++ b/src/DjangoBlog-master/djangoblog/logentryadmin.py @@ -1,27 +1,37 @@ +# 导入 Django Admin 核心模块:用于自定义后台管理界面 from django.contrib import admin +# 导入 Admin 日志相关常量和模型:处理日志操作类型(如删除) from django.contrib.admin.models import DELETION from django.contrib.contenttypes.models import ContentType +# 导入 Django URL 和字符串处理工具:生成反向链接、处理编码和转义 from django.urls import reverse, NoReverseMatch from django.utils.encoding import force_str from django.utils.html import escape from django.utils.safestring import mark_safe +# 导入国际化工具:支持后台文字的多语言翻译 from django.utils.translation import gettext_lazy as _ +# 自定义 LogEntry Admin 类:用于在 Django 后台管理 Admin 操作日志(记录用户对模型的增删改操作) class LogEntryAdmin(admin.ModelAdmin): + # 列表页筛选器:按“内容类型”(即操作的模型,如 Article、Comment)筛选日志 list_filter = [ 'content_type' ] + # 列表页搜索框:支持按“对象名称”(如文章标题)和“操作描述”(如“修改了标题”)搜索 search_fields = [ 'object_repr', 'change_message' ] + # 列表页可点击的链接:点击“操作时间”或“操作描述”可进入日志详情页 list_display_links = [ 'action_time', 'get_change_message', ] + + # 列表页展示的字段:操作时间、操作用户(带链接)、操作模型、操作对象(带链接)、操作描述 list_display = [ 'action_time', 'user_link', @@ -30,62 +40,81 @@ class LogEntryAdmin(admin.ModelAdmin): 'get_change_message', ] + # 权限控制:禁止添加日志(日志由系统自动生成,不允许手动添加) def has_add_permission(self, request): return False + # 权限控制:仅允许超级用户或拥有“修改日志”权限的用户查看/修改日志,且禁止 POST 请求(避免提交修改) def has_change_permission(self, request, obj=None): 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): + # 转义对象名称(避免 XSS 攻击) object_link = escape(obj.object_repr) + # 获取操作对象的内容类型(即所属模型) content_type = obj.content_type + # 若操作不是“删除”(DELETION)且内容类型存在(排除异常情况) if obj.action_flag != DELETION and content_type is not None: - # try returning an actual link instead of object repr string try: + # 生成对象编辑页的 URL(格式:admin/应用名/模型名/change/对象ID/) url = reverse( 'admin:{}_{}_change'.format(content_type.app_label, content_type.model), args=[obj.object_id] ) + # 将对象名称转为链接(点击跳转到编辑页) object_link = '{}'.format(url, object_link) except NoReverseMatch: + # 若无法生成链接(如模型未注册到 Admin),则保留纯文本名称 pass + # 标记为安全 HTML(告诉 Django 无需转义,避免链接被当作文本显示) 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)) + # 转义用户名(避免 XSS 攻击) 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] ) + # 将用户名转为链接(点击跳转到用户编辑页) user_link = '{}'.format(url, user_link) except NoReverseMatch: + # 若无法生成链接(如用户模型未注册到 Admin),则保留纯文本用户名 pass 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): queryset = super(LogEntryAdmin, self).get_queryset(request) 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 + del actions['delete_selected'] # 删除“批量删除”操作 + return actions \ No newline at end of file