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