Files
djangoadmin-wiki/DjangoAdmin_Django_EleVue/zh/volume4/business/menu.md
T
2026-09-12 23:12:15 +08:00

121 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
:::tip 菜单管理
菜单管理是 RBAC 权限系统的基础,负责管理系统的导航菜单和权限节点。支持目录/菜单(type=0)和权限按钮节点(type=1)两种类型,通过树形结构组织。
:::
## 菜单类型
| type | 名称 | 说明 | 用途 |
|------|------|------|------|
| `0` | 目录/菜单 | 页面路由 | 前端侧边栏分组 + 路由生成 |
| `1` | 节点 | 权限按钮 | 控制操作权限 |
## 菜单模型
```python
# application/menu/models.py
from application.models import BaseModel
class Menu(BaseModel):
"""菜单模型类"""
class Meta:
db_table = 'django_menu'
name = models.CharField(max_length=150, verbose_name='菜单名称')
icon = models.CharField(max_length=50, null=True, blank=True, verbose_name='菜单图标')
parent_id = models.IntegerField(default=0, verbose_name='上级ID')
path = models.CharField(max_length=255, null=True, blank=True, verbose_name='菜单路径')
component = models.CharField(max_length=255, null=True, blank=True, verbose_name='菜单组件')
permission = models.CharField(max_length=150, null=True, blank=True, verbose_name='权限节点')
target = models.IntegerField(default=1, verbose_name='打开方式:0-组件 1-内链 2-外链')
type = models.IntegerField(default=0, verbose_name='菜单类型:0-菜单 1-节点')
status = models.IntegerField(default=0, verbose_name='菜单状态:0-正常 1-停用')
hide = models.IntegerField(default=1, verbose_name='是否可见:0-可见 1-不可见')
sort = models.IntegerField(default=0, verbose_name='排序')
note = models.CharField(max_length=255, null=True, blank=True, verbose_name='备注')
```
## 权限节点格式
权限节点采用 `sys:module:action` 三段式命名:
```
1 -> 查询(sys:{module}:page)
5 -> 添加(sys:{module}:add)
10 -> 修改(sys:{module}:update)
15 -> 删除(sys:{module}:delete)
20 -> 详情(sys:{module}:detail)
25 -> 设置状态(sys:{module}:status)
30 -> 批量删除(sys:{module}:batchDelete)
```
## 菜单树构建
使用 children_map 字典实现非递归树构建:
```python
# application/menu/services.py
def get_tree(data, parent_id):
"""获取树状结构(非递归,children_map 分组)"""
children_map = {}
for item in data:
pid = item["parentId"]
if pid not in children_map:
children_map[pid] = []
children_map[pid].append(item)
def build(pid):
result = []
for item in children_map.get(pid, []):
item["children"] = build(item["id"])
result.append(item)
return result
return build(parent_id)
```
## 用户权限查询
权限查询通过 ORM 关联实现:
```python
# application/menu/services.py
def get_user_permissions(user_id):
"""获取用户的权限节点列表"""
if user_id == 1:
# 超管拥有全部权限
menu_list = Menu.objects.filter(type=1, is_delete=False)
else:
# 通过 user -> role -> menu 关联查询
menu_list = Menu.objects.filter(
type=1,
is_delete=False,
status=0,
rolemenu__role__userrole__user_id=user_id,
rolemenu__role__is_delete=False,
).distinct()
return [item.permission for item in menu_list]
```
## API 接口
| 接口 | 方法 | 权限节点 | 说明 |
|------|------|---------|------|
| `/menu/list` | GET | `sys:menu:list` | 菜单列表 |
| `/menu/detail/<int:menu_id>` | GET | `sys:menu:detail` | 菜单详情 |
| `/menu/add` | POST | `sys:menu:add` | 新增菜单 |
| `/menu/update` | POST | `sys:menu:update` | 编辑菜单 |
| `/menu/delete/<int:menu_id>` | POST | `sys:menu:delete` | 删除菜单 |
## 总结
菜单管理模块具备以下特点:
```
1. 树形结构:通过 parent_id 形成多级菜单树,非递归构建
2. 权限节点:type=1 按钮节点,sys:module:action 格式
3. 缓存联动:菜单增删改后清理权限缓存
4. 环路防护:编辑时检测父级不能是自身或下级
5. 级联删除:删除菜单时一并清理权限节点和 role_menu 关联
```