from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.utils.html import format_html from import_export.admin import ImportExportModelAdmin from .models import Department, Role, Menu from .models import User # ========== 菜单管理 ========== @admin.register(Menu) class MenuAdmin(admin.ModelAdmin): list_display = ( 'name', 'code', 'menu_type_display', 'path', 'permission_code', 'parent_link', 'order_num', 'status') list_filter = ('menu_type', 'status', 'parent') search_fields = ('name', 'code', 'permission_code') ordering = ('order_num', 'id') list_editable = ('order_num', 'status') # 允许在列表页直接编辑 list_per_page = 20 # 自定义字段:显示菜单类型 def menu_type_display(self, obj): types = {0: '目录', 1: '菜单', 2: '按钮'} return types.get(obj.menu_type, '未知') menu_type_display.short_description = '类型' # 自定义字段:父菜单链接(可点击) def parent_link(self, obj): if obj.parent: url = f"/admin/users/menu/{obj.parent.id}/change/" return format_html('{}', url, obj.parent.name) return '-' parent_link.short_description = '父菜单' # ========== 角色管理 ========== class RoleMenuInline(admin.TabularInline): """ 内联管理:在角色编辑页直接分配菜单 """ model = Role.menus.through # 使用自动创建的中间表 verbose_name = "菜单权限" verbose_name_plural = "菜单权限" extra = 1 # 默认显示1个空行 # 优化显示:只显示关键字段 def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "menu": # 可以在这里过滤菜单选项,例如只显示状态为True的 kwargs["queryset"] = Menu.objects.filter(status=True) return super().formfield_for_foreignkey(db_field, request, **kwargs) @admin.register(Role) class RoleAdmin(admin.ModelAdmin): list_display = ('name', 'code', 'description', 'user_count', 'menu_count', 'status', 'created_at') list_filter = ('status', 'created_at') search_fields = ('name', 'code', 'description') ordering = ('-created_at',) list_per_page = 20 # 使用内联管理菜单权限 inlines = [RoleMenuInline] # 排除 menus 字段,因为已经在内联中处理 exclude = ('menus',) # 自定义字段:关联用户数量 def user_count(self, obj): count = obj.users.count() if count: url = f"/admin/users/user/?roles__id__exact={obj.id}" return format_html('{}', url, count) return 0 user_count.short_description = '用户数' # 自定义字段:关联菜单数量 def menu_count(self, obj): count = obj.menus.count() if count: url = f"/admin/users/menu/?roles__id__exact={obj.id}" return format_html('{}', url, count) return 0 menu_count.short_description = '菜单数' # ========== 用户管理 ========== class UserRoleInline(admin.TabularInline): """ 内联管理:在用户编辑页直接分配角色 """ model = User.roles.through verbose_name = "角色" verbose_name_plural = "角色" extra = 1 @admin.register(User) class UserAdmin(BaseUserAdmin, ImportExportModelAdmin): list_display = ('username', 'cname', 'dept', 'phone', 'is_active', 'is_staff') list_filter = ('is_active', 'is_staff', 'dept') search_fields = ('username', 'cname', 'phone',) fieldsets = ( (None, {'fields': ('username', 'password')}), ('个人信息', {'fields': ('cname', 'dept')}), ('权限', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}), ('重要日期', {'fields': ('last_login', 'date_joined')}), ) add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('username', 'cname', 'password1', 'password2', 'dept'), }), ) ordering = ('username', '-date_joined',) filter_horizontal = ('groups', 'user_permissions', 'roles') # 如果 roles 是 ManyToMany list_per_page = 20 # 使用内联管理角色 inlines = [UserRoleInline] # 排除 roles 字段,因为已经在内联中处理 exclude = ('roles',) # 自定义字段:显示所有角色名称 def role_names(self, obj): roles = obj.roles.all() if roles: names = ', '.join([role.name for role in roles]) return names[:50] + '...' if len(names) > 50 else names return '-' role_names.short_description = '角色' # ========== 部门管理 ========== @admin.register(Department) class DepartmentAdmin(admin.ModelAdmin): list_display = ('name_with_indent', 'parent_link', 'order', 'user_count') list_editable = ('order',) ordering = ('order', 'id') list_per_page = 30 def get_queryset(self, request): # 优化查询,避免 N+1 return super().get_queryset(request).select_related('parent') def name_with_indent(self, obj): """根据层级缩进显示部门名称""" level = 0 current = obj.parent while current: level += 1 current = current.parent indent = "=>" * level return format_html('{}{}', indent, obj.name) name_with_indent.short_description = "部门名称" name_with_indent.allow_tags = True def parent_link(self, obj): if obj.parent: url = f"/admin/users/department/{obj.parent.id}/change/" return format_html('{}', url, obj.parent.name) return '-' parent_link.short_description = "上级部门" def user_count(self, obj): count = obj.user_set.count() if count: url = f"/admin/users/user/?department__id__exact={obj.id}" return format_html('{}', url, count) return 0 user_count.short_description = "用户数"