【Dv3Admin】系统视图菜单管理API文件解析

后台菜单管理模块是权限控制系统的核心部分,决定了用户可以访问的功能范围和页面结构。通过菜单配置可动态生成前端路由,实现权限隔离与导航逻辑统一,成为前后端联动的基础。

内容围绕 dvadmin/system/views/menu.py 文件展开,分析菜单接口的增删改查实现、路由数据生成、批量操作与顺序调整方法,结合序列化器设计与权限绑定机制,解读模块在实际系统中的角色与重要性。

文章目录

  • menu.py
  • 项目源码解析
  • 应用案例
  • 总结

本系统采用 Django 框架搭建后台管理平台,dvadmin/system/views/menu.py 文件属于系统权限管理模块。菜单模块负责定义系统功能入口结构,通过配置菜单层级关系与前端页面路由映射,实现前后端统一的权限体系管理。该模块支持菜单的增删改查操作,关联按钮权限、字段权限等子模块,确保权限系统的完整性与灵活性。

项目特点 描述
技术栈 Django + Django Rest Framework
功能定位 后台菜单管理、路由生成、权限控制入口管理
设计原则 菜单、按钮、字段三级权限体系,灵活配置功能访问
配置方式 后台界面动态配置菜单结构,实时生效

dvadmin/system/views/menu.py 文件提供菜单管理相关接口,通过继承自定义基础类 CustomModelViewSet 实现菜单记录的查询、创建、更新、删除操作。文件内部定义了 MenuSerializer 序列化器负责数据校验与格式转换,支持批量删除、菜单树形结构返回等扩展功能。该模块为权限系统提供了基础数据支持,配合角色管理模块可实现基于角色的菜单授权。

模块职责 说明
定义菜单序列化器 统一管理菜单数据的输入与输出格式
菜单列表接口 支持分页查询、条件筛选,返回菜单基础信息
菜单树结构接口 返回带层级关系的菜单树,用于前端动态生成路由导航
菜单增删改接口 允许后台管理人员灵活新增、编辑或删除菜单项
支持批量操作 实现批量删除菜单记录,提升后台管理效率

在构建权限控制平台、后台管理系统、内容管理系统等项目中,需要通过菜单模块定义功能入口,并与权限系统关联。通过 dvadmin/system/views/menu.py 提供的接口,可以动态配置系统菜单,控制不同角色的功能访问范围,实现前后端分离项目中的动态路由生成、权限拦截等核心功能。

使用场景 说明
后台动态菜单管理 后台界面可添加、编辑、删除菜单,实时生效
前端基于菜单生成路由 前端应用通过菜单接口生成左侧导航栏及页面路由
角色授权菜单选择 后台授权角色时,选择关联的菜单权限范围
多层级菜单支持 支持二级、三级甚至更多层级的菜单结构
功能模块分组与展示优化 通过菜单配置功能模块分组,提高系统可用性与易用性

项目源码解析

菜单数据标准序列化

MenuSerializer 负责把菜单表数据格式化输出,附加了菜单按钮权限集合 menuPermission 和子节点存在标记 hasChild。它与 Menu 模型和 MenuButton 模型的数据联动密切,增强了菜单管理的可扩展性,适用于后台管理和前端路由构建。

python 复制代码
class MenuSerializer(CustomModelSerializer):
    menuPermission = serializers.SerializerMethodField(read_only=True)
    hasChild = serializers.SerializerMethodField()

    def get_menuPermission(self, instance):
        queryset = instance.menuPermission.order_by('-name').values('id', 'name', 'value')
        return queryset if queryset else None

    def get_hasChild(self, instance):
        hasChild = Menu.objects.filter(parent=instance.id)
        return bool(hasChild)

    class Meta:
        model = Menu
        fields = "__all__"
        read_only_fields = ["id"]

菜单创建处理器

MenuCreateSerializer 用于新增菜单时自动处理排序逻辑,避免手动输入排序值。它根据同一父节点下已有菜单的最大排序值进行递增,保持菜单顺序自然生长,提升了数据录入的便捷性和一致性。

python 复制代码
class MenuCreateSerializer(CustomModelSerializer):
    name = serializers.CharField(required=False)

    def create(self, validated_data):
        menu_obj = Menu.objects.filter(parent_id=validated_data.get('parent', None)).order_by('-sort').first()
        last_sort = menu_obj.sort if menu_obj else 0
        validated_data['sort'] = last_sort + 1
        return super().create(validated_data)

    class Meta:
        model = Menu
        fields = "__all__"
        read_only_fields = ["id"]

前端菜单路由序列化器

WebRouterSerializer 定义了前端所需路由数据格式,将菜单的地址、组件、可见性、缓存策略等关键信息打包。它通过字段映射简化前后端接口对接,提高了菜单动态渲染的效率和一致性。

python 复制代码
class WebRouterSerializer(CustomModelSerializer):
    path = serializers.CharField(source="web_path")
    title = serializers.CharField(source="name")

    class Meta:
        model = Menu
        fields = (
            'id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link', 'link_url',
            'is_catalog', 'web_path', 'component', 'component_name', 'cache', 'visible',
            'is_iframe', 'is_affix', 'status'
        )
        read_only_fields = ["id"]

菜单管理接口控制器

MenuViewSet 实现菜单资源的标准增删改查接口,同时扩展了多种自定义接口,包括前端路由生成、菜单懒加载查询、菜单移动排序等。与 Menu 模型、RoleMenuPermission 权限模型深度协作,是整个权限体系路由和展示层的重要组成模块。

python 复制代码
class MenuViewSet(CustomModelViewSet):
    queryset = Menu.objects.all()
    serializer_class = MenuSerializer
    create_serializer_class = MenuCreateSerializer
    update_serializer_class = MenuCreateSerializer
    search_fields = ['name', 'status']
    filter_fields = ['parent', 'name', 'status', 'is_link', 'visible', 'cache', 'is_catalog']

list 方法根据请求参数动态过滤菜单数据,支持分页,也支持按父节点懒加载子菜单结构。默认只查询一级菜单,提升了前端加载速度和用户体验。

python 复制代码
def list(self, request):
    request.query_params._mutable = True
    params = request.query_params
    parent = params.get('parent', None)
    page = params.get('page', None)
    limit = params.get('limit', None)
    if page:
        del params['page']
    if limit:
        del params['limit']
    if params:
        queryset = self.queryset.filter(parent=parent) if parent else self.queryset.filter()
    else:
        queryset = self.queryset.filter(parent__isnull=True)
    queryset = self.filter_queryset(queryset)
    serializer = MenuSerializer(queryset, many=True, request=request)
    data = serializer.data
    return SuccessResponse(data=data)

web_router 动态生成当前用户可访问的前端路由数据,区分超级管理员和普通用户,按照角色绑定权限菜单生成菜单树结构。该接口保证前后端动态权限同步,提升系统灵活性。

python 复制代码
@action(methods=['GET'], detail=False, permission_classes=[])
def web_router(self, request):
    user = request.user
    if user.is_superuser:
        queryset = self.queryset.filter(status=1).order_by("sort")
    else:
        role_list = user.role.values_list('id', flat=True)
        menu_list = RoleMenuPermission.objects.filter(role__in=role_list).values_list('menu_id', flat=True)
        queryset = Menu.objects.filter(id__in=menu_list).order_by("sort")
    serializer = WebRouterSerializer(queryset, many=True, request=request)
    data = serializer.data
    return SuccessResponse(data=data, total=len(data), msg="获取成功")

get_all_menu 用于后台菜单管理模块,返回系统内所有菜单数据。如果是超级管理员返回全部,否则根据用户角色返回权限内菜单,确保数据访问符合权限控制规则。

python 复制代码
@action(methods=['GET'], detail=False, permission_classes=[])
def get_all_menu(self, request):
    user = request.user
    queryset = self.queryset.all()
    if not user.is_superuser:
        role_list = user.role.values_list('id', flat=True)
        menu_list = RoleMenuPermission.objects.filter(role__in=role_list).values_list('menu_id')
        queryset = Menu.objects.filter(id__in=menu_list)
    serializer = WebRouterSerializer(queryset, many=True, request=request)
    data = serializer.data
    return SuccessResponse(data=data, total=len(data), msg="获取成功")

move_up 用于调整菜单的顺序,将当前菜单节点与同一父节点下排序更小的节点互换位置,实现菜单结构的手动调整。该接口保证了菜单顺序的灵活调整,便于前端结构优化。

python 复制代码
@action(methods=['POST'], detail=False, permission_classes=[])
def move_up(self, request):
    menu_id = request.data.get('menu_id')
    try:
        menu = Menu.objects.get(id=menu_id)
    except Menu.DoesNotExist:
        return ErrorResponse(msg="菜单不存在")
    previous_menu = Menu.objects.filter(sort__lt=menu.sort, parent=menu.parent).order_by('-sort').first()
    if previous_menu:
        previous_menu.sort, menu.sort = menu.sort, previous_menu.sort
        previous_menu.save()
        menu.save()
    return SuccessResponse(data=[], msg="上移成功")

move_down 用于将当前菜单节点与同一父节点下排序更大的节点互换位置,实现向下移动操作。配合 move_up 接口,用户可以灵活调整菜单展示顺序,优化系统管理体验。

python 复制代码
@action(methods=['POST'], detail=False, permission_classes=[])
def move_down(self, request):
    menu_id = request.data['menu_id']
    try:
        menu = Menu.objects.get(id=menu_id)
    except Menu.DoesNotExist:
        return ErrorResponse(msg="菜单不存在")
    next_menu = Menu.objects.filter(sort__gt=menu.sort, parent=menu.parent).order_by('sort').first()
    if next_menu:
        next_menu.sort, menu.sort = menu.sort, next_menu.sort
        next_menu.save()
        menu.save()
    return SuccessResponse(data=[], msg="下移成功")

应用案例

动态菜单系统在权限与路由控制中的集成实践

在后台管理系统中,菜单结构不仅承担页面导航职责,更是用户权限体系的核心入口。项目通过 dvadmin/system/views/menu.py 模块构建了完整的菜单资源管理体系,支持菜单的层级构建、路由信息生成、权限角色绑定、排序调整与前端懒加载展示,解决了动态配置页面结构与权限控制统一的问题。

功能点 内容描述
场景需求 菜单结构既需满足页面导航需求,又需作为用户权限体系的核心入口,实现动态配置页面结构与权限控制的统一。
核心模块 dvadmin/system/views/menu.py:实现菜单资源管理体系。
支持功能 - 层级构建:支持多层级菜单的创建,满足复杂页面导航需求。
- 路由信息生成:为前端动态生成页面路由信息,实现无缝对接。
- 权限角色绑定:菜单与权限角色绑定,确保基于角色的访问控制。
- 排序调整:支持按需调整菜单显示顺序,优化用户体验。
- 前端懒加载展示:按需加载菜单数据,提升页面加载性能与效率。
应用场景 - 动态导航:根据用户角色动态展示对应的菜单项。 - 权限控制:确保用户仅能访问被授权的页面与功能。
优势 - 统一管理菜单与权限,降低维护成本。 - 动态适配多角色、多权限的复杂场景需求。
扩展能力 - 可与多种前端框架(如 Vue、React)集成,动态渲染菜单结构。 - 支持国际化菜单名称与动态多语言切换。

管理员可在后台添加菜单项,例如:

http 复制代码
POST /api/system/menu/

{
  "name": "用户管理",
  "web_path": "/user",
  "component": "system/user/index",
  "parent": null,
  "is_catalog": false
}

该操作调用 MenuCreateSerializer 自动生成排序字段,系统根据当前菜单父节点下已有菜单项的最大排序值自动加一,保证菜单按创建顺序有序排列。前端可根据此数据动态生成页面路由和导航结构。

用户登录系统后,前端通过以下接口获取该用户可访问的菜单路由:

http 复制代码
GET /api/system/menu/web_router/

调用 MenuViewSet.web_router() 方法,系统判断当前用户是否为超级管理员,若是则返回所有状态为启用的菜单项,否则根据其绑定角色返回授权内菜单数据,并返回如下格式:

json 复制代码
[
  {
    "id": 1,
    "path": "/user",
    "component": "system/user/index",
    "title": "用户管理",
    "visible": true,
    "cache": true,
    "is_link": false
  }
]

前端通过该数据生成左侧导航菜单与路由配置,实现权限内菜单的动态加载与展示。

管理员也可以调整菜单顺序,比如将"角色管理"菜单上移,通过接口:

http 复制代码
POST /api/system/menu/move_up/

{
  "menu_id": 8
}

系统会查找该菜单在同级菜单中的前一个排序项,并交换二者 sort 字段,完成排序更新。调用 move_down 接口则可实现向下移动操作,整个过程无需刷新页面,调整立即生效。

系统还提供 get_all_menu 接口用于后台授权页面加载所有菜单项,支持基于角色授权功能权限,前端通过该接口加载完整菜单树:

http 复制代码
GET /api/system/menu/get_all_menu/

返回值依据当前用户权限做过滤,确保普通用户仅能看到自己有权访问的菜单项。整个菜单管理模块支撑了页面导航配置、权限粒度控制、菜单分组展示等功能,是权限系统与前端路由联动的基础。

总结

模块通过标准视图集封装菜单管理接口,结合定制序列化器完成数据校验与输出。新增与排序逻辑联动,简化后台录入流程。菜单树接口和动态路由接口适配不同前端场景,保证了权限系统与导航结构的一致性。整体代码结构清晰,具备良好的扩展性与维护性。

接口中过多依赖 ORM 查询与逻辑处理混合,缺乏查询优化。菜单树接口在节点多时可能产生性能瓶颈。排序调整通过交换字段完成,未加事务控制,存在数据竞争风险。如重构,可引入异步查询优化树结构生成,细化接口权限分离,提升稳定性与性能。

相关推荐
伍六星10 小时前
Flask和Django,你怎么选?
数据库·django·flask
Mr数据杨16 小时前
【Dv3Admin】系统视图登录日志API文件解析
django
白嫖不白嫖18 小时前
Django、Flask、FastAPI与Jupyter对比
django·flask·fastapi
一刀到底21119 小时前
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
python·django·fastapi
KENYCHEN奉孝19 小时前
Django 5 学习笔记总纲
笔记·学习·django
工业互联网专业21 小时前
基于django+vue的健身房管理系统-vue
vue.js·python·django·毕业设计·源码·课程设计·健身房管理系统
红鼻子时代1 天前
Django RBAC项目后端实战 - 03 DRF权限控制实现
后端·python·django·rabc
zhangsan09331 天前
web框架(Django 与 FastAPI)
django·fastapi
Python智慧行囊2 天前
Python 中 Django 中间件:原理、方法与实战应用
python·中间件·架构·django·开发