from django.contrib import admin from django.contrib.admin.models import DELETION from django.contrib.contenttypes.models import ContentType 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 _ class LogEntryAdmin(admin.ModelAdmin): """Django管理员日志条目的自定义管理界面""" # 列表页过滤器配置:按内容类型过滤 list_filter = [ 'content_type' ] # 搜索字段配置:可按对象表示和变更消息搜索 search_fields = [ 'object_repr', 'change_message' ] # 列表页中可点击的链接字段 list_display_links = [ 'action_time', 'get_change_message', ] # 列表页显示的字段 list_display = [ '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): """修改权限控制:只允许超级用户或具有特定权限的用户查看(不允许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): """生成对象链接的显示""" object_link = escape(obj.object_repr) # 转义对象表示字符串 content_type = obj.content_type # 如果不是删除操作且内容类型存在,尝试生成可点击的链接 if obj.action_flag != DELETION and content_type is not None: try: # 构建管理员修改页面的URL url = reverse( 'admin:{}_{}_change'.format(content_type.app_label, content_type.model), args=[obj.object_id] ) # 创建HTML链接 object_link = '{}'.format(url, object_link) except NoReverseMatch: # 如果无法生成URL,保持原样 pass return mark_safe(object_link) # 标记为安全HTML # 设置对象链接字段的排序和显示名称 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)) user_link = escape(force_str(obj.user)) # 转义用户字符串 try: # 构建用户修改页面的URL url = reverse( 'admin:{}_{}_change'.format(content_type.app_label, content_type.model), args=[obj.user.pk] ) # 创建HTML链接 user_link = '{}'.format(url, user_link) except NoReverseMatch: # 如果无法生成URL,保持原样 pass return mark_safe(user_link) # 标记为安全HTML # 设置用户链接字段的排序和显示名称 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') def get_actions(self, request): """获取可用的批量操作,移除删除选中操作""" actions = super(LogEntryAdmin, self).get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] # 移除批量删除选项 return actions