Files
server/users/admin.py
T

180 lines
6.0 KiB
Python

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('<a href="{}">{}</a>', 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('<a href="{}">{}</a>', 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('<a href="{}">{}</a>', 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('<a href="{}">{}</a>', 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('<a href="{}">{}</a>', url, count)
return 0
user_count.short_description = "用户数"