DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • BBS

  • 订单平台

  • CRM

  • flask+layui

  • django+layui

    • 理论储备
    • 项目编写
    • 规则怪谈
    • 一些思考
    • 代码讲解
      • 部门
      • 时序图
        • 不分离
        • 半分离
      • 动态菜单
    • 部署
  • 供应链

  • 实战
  • django+layui
DC
2024-10-25
目录

代码讲解

# 部门

- 若部门只有两层
    res_data = []
    first_queryset = Department.objects.filter(pid_id__isnull=True)  # 拿到顶级部门
    if first_queryset:
        for item in first_queryset:
            item_data = item.json()
            res_data.append(item_data)
            for child in item.department_set.all():  # 顶级部门:顶级部门所有子部门=1:n so,是反向查询
                item_data['children'].append(child.json())
    print(res_data)
1
2
3
4
5
6
7
8
9
10

# 时序图

# 不分离

sequenceDiagram
    participant U as 用户
    participant B as 浏览器
    participant S as 服务器

    U ->> B: 点击部门菜单
    B ->> S: GET /departments/
    S ->> S: 查询db,将部门列表数据通过模版语法渲染到页面中
    S -->> B: 返回部门列表页面
    B ->> B: 渲染部门列表

    alt 新增部门
        U ->> B: 点击新增按钮
        B ->> S: GET /departments/add/
        S -->> B: 返回新增部门页面
        B ->> B: 渲染新增部门表单
        U ->> B: 填写表单并提交
        B ->> S: POST /departments/add/
        S -->> S: 校验新部门数据
        alt 校验通过
            S -->> S: 保存新部门数据
            S -->> B: 返回部门列表页面
            B ->> B: 跳转部门列表
        else 校验不通过
            S -->> B: 将错误信息渲染到表单上
            B ->> B: 展示含有错误信息的表单
        end
    end

    alt 修改部门
        U ->> B: 点击编辑按钮
        B ->> S: GET /departments/edit/{id}/
        S -->> B: 返回编辑部门页面
        B ->> B: 渲染编辑部门表单
        U ->> B: 修改表单并提交
        B ->> S: POST /departments/edit/{id}/
        S -->> S: 校验更新的数据,同上,以校验通过为例
        S -->> B: 返回部门列表页面
        B ->> B: 跳转部门列表
    end

    alt 删除部门
        U ->> B: 点击删除按钮
        B ->> S: GET /departments/delete/{id}/  // 请求删除确认页面
        S -->> B: 返回删除确认页面
        B ->> B: 渲染删除确认页面
        U ->> B: 确认删除
        B ->> S: POST /departments/delete/{id}/
        S -->> S: 校验删除的数据,同上,以校验通过为例
        S -->> B: 返回部门列表页面
        B ->> B: 跳转部门列表
    end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 半分离

sequenceDiagram
    participant U as 用户
    participant B as 浏览器
    participant S as 服务器

    U ->> B: 点击部门菜单
    B ->> S: GET /rbac/department/main.html
    S -->> B: 返回静态页面-部门主页
    B ->> B: 渲染部门主页


    U ->> B: 点击获取部门列表
    B ->> S: GET /api/v1/department/treetable/
    S -->> S: 查询部门列表,构建嵌套的数据结构
    S -->> B: 返回JSON数据
    B ->> B: 渲染部门列表到树形表格中


    alt 新增数据
        U ->> B: 点击新增按钮
        B ->> S: GET /rbac/department/add.html
        S -->> B: 返回静态页面-部门新增
        B ->> B: 渲染部门新增页面到iframe窗口中
        U ->> B: 点击新增提交按钮
        B ->> S: AJAX POST /api/v1/department/add/
        S -->> S: 新增数据处理
        S -->> B: 返回JSON数据
        B ->> B: 根据响应状态码和code字段处理响应
    end

    alt 修改数据
        U ->> B: 点击修改按钮
        B ->> S: GET /rbac/department/edit.html?id={id}
        S -->> S: 通过模版语法,根据id将对象数据渲染到表单中,实现自动填充
        S -->> B: 返回静态页面-部门修改
        B ->> B: 渲染部门修改页面到iframe窗口中
        U ->> B: 点击编辑提交按钮
        B ->> S: AJAX POST /api/v1/department/edit/
        S -->> S: 修改数据处理,要处理的对象的id在请求体中!
        S -->> B: 返回JSON数据
        B ->> B: 根据响应状态码和code字段处理响应
    end

    alt 删除数据
        U ->> B: 点击删除按钮
        B ->> S: AJAX POST /api/v1/department/del/
        S -->> S: 删除数据处理,要处理的对象的id在请求体中!
        S -->> B: 返回JSON数据
        B ->> B: 根据响应状态码和code字段处理响应
    end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 动态菜单

  1. pear.config.json文件中有几个地方需要注意下:

    "menu": {
        "data": "/menu/",  // - 菜单的数据接口
        "method": "GET",
        "accordion": true,
        "collapse": false,
        "control": false,
        "controlWidth": 500,
        "select": "10", 
        "select": "126", // - 默认选中的菜单的ID,需要去权限表里看下
        "async": true
    },
    "tab": {  // - tab 标签导航栏,就主体内容上面那一栏,会展示你点击过哪些菜单项
        "enable": true,
        "keepState": true,
        "session": true,
        "preload": false,
        "max": "30",
        "index": {  // - 默认选中的菜单信息
          "id": "126",
          "href": "view/analysis/index.html",  // 去权限表里看下,首页的路径也要一样
          "title": "首页"
        }
    },
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
  2. 实现的动态菜单逻辑如下:

current_user = User.objects.first()
rights_obj_set = set()
for role_obj in current_user.role_list.all():      # 跨表拿到当前用户的所有角色
    for rights_obj in role_obj.rights_list.all():  # 根据角色跨表拿到当前用户的所有权限
        # 拿到全部权限,剔除掉type是auth的,剩下的就是可以做菜单的!
        if rights_obj.type != "auth":
            rights_obj_set.add(rights_obj)

# rights_obj_set是一大堆可作菜单的权限对象!! 根据对象的属性进行排序,先排pid,pid相同的排id. 倒叙排列!
rights_list = [rights_obj.menu_json() for rights_obj in rights_obj_set]
rights_list.sort(key=lambda x: (x["pid"], x["id"]), reverse=True)
print(rights_list)
1
2
3
4
5
6
7
8
9
10
11
12

结果像是下面这个样子:(简化了下

[
  {'id': 128, 'pid': 124, 'title': '数据分析', 'sort': 4},
  {'id': 127, 'pid': 124, 'title': '分析页','sort': 3},
  {'id': 126, 'pid': 124, 'title': '首页','sort': 1},
  {'id': 125, 'pid': 124, 'title': '工作台','sort': 2},
  {'id': 116, 'pid': 100, 'title': '员工管理','sort': 4},
  {'id': 111, 'pid': 100, 'title': '部门管理','sort': 1},
  {'id': 106, 'pid': 100, 'title': '角色管理','sort': 3},
  {'id': 101, 'pid': 100, 'title': '权限管理','sort': 2},
  {'id': 124, 'pid': 0, 'title': '工作空间','sort': 1},
  {'id': 100, 'pid': 0, 'title': '系统管理','sort': 2}
]
1
2
3
4
5
6
7
8
9
10
11
12

构建菜单树形结构: (不是特别好理解) - 可以断点调试,看看样子. 下面是以两层结构为例, 没有用递归..
F8一行行执行代码, option+command+R直接跳到下一个断点处, 跳过去时, 该断点处的这行代码是没有执行的哦!

menu_dict = {}

for menu_item in rights_list:
    # 根据父级ID将菜单项添加到字典中
    if menu_item["pid"] not in menu_dict:
        menu_dict[menu_item["pid"]] = [menu_item]
    else:
        menu_dict[menu_item["pid"]].append(menu_item)
   
    # 如果菜单项已经有子节点,准备将其子节点移入 > 字典是可变的
    if menu_item["id"] in menu_dict:
        menu_item["children"] = deepcopy(menu_dict[menu_item["id"]])
        menu_item["children"].sort(key=lambda item: item["sort"])
        del menu_dict[menu_item["id"]]

# 返回顶级菜单项并按排序字段排序
sorted(menu_dict.get(0, []), key=lambda item: item["sort"])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • for循环上面rights_list的数据, 第一条至第8条数据都只会执行for循环里的第一个if语句, 新字典大概长这样

    • {'124': [第1条,第2条,第3条,第4条] , '100': [第5条,第6条,第7条,第8条]}
  • 循环到第9条,第10条数据时, 执行的是for循环里的第一个以及第二个if语句, 新字典大概长这样

    {
      '0': [ 
            第9条多个了children属性,对应的值是[第1条,第2条,第3条,第4条] ,
            第10条多个了children属性,对应的值是[第5条,第6条,第7条,第8条] ,
          ]
    }
    
    1
    2
    3
    4
    5
    6
  • 最后, 取了key值为0对应的value.

最终效果长这样(简化了)

[
    {'id': 124, 'pid': 0, 'title': '工作空间', 'sort': 1,'children': [
            {'id': 126, 'pid': 124, 'title': '首页', 'sort': 1},
            {'id': 125, 'pid': 124, 'title': '工作台', 'sort': 2},
            {'id': 127, 'pid': 124, 'title': '分析页', 'sort': 3},
            {'id': 128, 'pid': 124, 'title': '数据分析', 'sort': 4}
     ]}, 
    {'id': 100, 'pid': 0, 'title': '系统管理', 'sort': 2, 'children': [
            {'id': 111, 'pid': 100, 'title': '部门管理', 'sort': 1}, 
            {'id': 101, 'pid': 100, 'title': '权限管理', 'sort': 2}, 
            {'id': 106, 'pid': 100, 'title': '角色管理', 'sort': 3}, 
            {'id': 116, 'pid': 100, 'title': '员工管理', 'sort': 4}
     ]}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14

一些思考
部署

← 一些思考 部署→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式