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

相关推荐
可乐鸡翅yeah_8 小时前
hls.js 内存泄漏实战排查,直播 M3U8 长时间播放异常定位方案
开发语言·javascript·python·django·ecmascript·m3u8·m3u8在线
可乐鸡翅yeah_8 小时前
第三方接口对接 M3U8 流媒体排坑实战,解决外部服务商流兼容难题
前端·javascript·python·django·html·m3u8·m3u8在线
可乐鸡翅yeah_11 小时前
个人 / 外包流媒体项目交付实战,M3U8 验收与问题闭环完整工作流
运维·网络·python·低代码·django·m3u8·在线播放
2601_9620652516 小时前
从零创建一个 Django 项目
后端·python·django
千里码aicood17 小时前
Django 基于Django的电脑推荐与分析可视化系统设计与实现
python·django·电脑
汤姆yu18 小时前
基于Django的学习资料共享与智能推荐系统
后端·python·django·毕业设计·学习资料共享
Mr数据杨1 天前
【Codex】用学生入学评估模块建立新生能力画像
android·java·javascript·django·codex·项目开发
Mr数据杨1 天前
【Codex】用部门管理模块维护组织架构与管理层级
架构·django·codex·项目开发
Mr数据杨1 天前
【Codex】用附件管理模块统一维护系统文件资源
django·codex·项目开发
IT毕设实战小研1 天前
基于安卓的空气质量查询系统
android·大数据·vue.js·爬虫·python·django·课程设计