项目编写
# 项目创建
创建python项目
pear_admin_django
, 并用poetry创建虚拟环境..poetry add django==3.2
将项目变成django项目创建了三个app - base、rbac、systems
- base放所有的数据表、rbac实现基于角色权限、systems 业务系统.
- 记得修改下每个app的apps.py
- 项目根目录下创建apps文件,将base放到里面
- 记得将 apps/base/apps.py 里的 name = 'base' 改为 name = 'apps.base'
- 注册app 'apps.base.apps.BaseConfig',
- 配置Django项目的快速启动, 在settings.py里注册app时就会有提示了!
基于全局变量的形式配置settings文件.. (若是Flask还可以基于类的形式)
在settings.py的最后写代码
try: from .local_settings import * except ImportError: pass
1
2
3
4在settings.py的同级目录下创建 local_settings.py 文件. (线上服务器也需建立它,自己写线上的配置
在项目根目录下添加忽略文件.
.gitignore
.idea/ .venv/ __pycache__/ migrations/ node_modules zdc_test/ *.py[cod] *$py.class .DS_Store **/.DS_Store
1
2
3
4
5
6
7
8
9
10
11
12
在项目根目录下创建static和templates文件夹..
将项目上传到gitee中, 进行代码的管理.
在gitee上创建项目后 在终端输入以下命令 git init git remote add origin https://gitee.com/One_PieceDC/pear_admin_django.git git add . git commit -m "第一次提交,项目初始化" git push origin main 提交远端时没报错,但远端也没更新,看打印输出: fatal: the remote end hung up unexpectedly 这是因为提交远端的文件太大,执行命令: git config --local http.postBuffer 524288000
1
2
3
4
5
6
7
8
9
目前, 项目的结构树长这样!
pear_admin_django
├── .venv
├── apps
│ ├── base
│ ├── rbac
│ └── system
├── db.sqlite3
├── manage.py
├── pear_admin_django
│ ├── asgi.py
│ ├── local_settings.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── poetry.lock
├── pyproject.toml
├── static
└── templates
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 引入前端模版
不要急,慢慢搞的. 返回index.html首页的视图函数是切入点,然后按照 前端模版的运行逻辑逐步去完善!
在总路由里写路由和视图,先验证对不对,然后将 路由和视图 放到rbac这个app下不同的业务文件夹中!
前端模版 pear admin layui 单页版的gitee地址:
https://gitee.com/pear-admin/Pear-Admin-Layui
后端引入前端模版,进行静态文件的初始化
前端模版自己单独运行时
- 构建url -- 协议+域名+端口 [拼接] 写的路径, 浏览器根据url地址发送请求
- 项目根据路径在项目目录上直接找html、css、js、png, 并返回
- ☆ 前端模版的运行逻辑 - 双击index.html,用浏览器打开 - 浏览器执行index.html中这行代码时admin.setConfigurationPath("config/pear.config.json"); 浏览器会加载配置文件pear.config.json里的内容 - pear.config.json 里根据配置发送请求 eg: "image": "admin/images/logo.png" 在html、json等文件中只要看到路径,不管是html模版还是css、png其它静态资源,都是直接拼接的. > href="./component/pear/css/pear.css" -- http://127.0.0.1:8080/component/pear/css/pear.css image: "admin/images/logo.png" -- http://127.0.0.1:8080/admin/images/logo.png href: "view/analysis/index.html" -- http://127.0.0.1:8080/view/analysis/index.html
1
2
3
4
5
6
7
8
9
10后端引入前端模版
- 构建url -- 协议+域名+端口 [拼接] 写的路径, 浏览器根据url地址向 [后端] 发送请求
- 若请求的资源是css、js、png, 后端会根据静态文件的查找规则在项目目录结构中直接找,不需要视图函数
- 若请求的资源是html, 就得经过视图函数返回对应的html模版,当然,返回的html也得遵循模版查找规则
- 什么查找规则呢?
后端Django对于html、css、js、png的查找规则
简单来说, 模版不需要templates前缀(但需要走视图函数的逻辑),在 [templates目录下] 找写的路径.
css, js, png [需要static前缀](表明不需要视图函数), 在 [static的上级目录下] 找写的路径..模版的查找顺序
比如视图函数 return render(request, 'view/analysis/index.html') 'DIRS': [os.path.join(BASE_DIR, 'templates')], # 可去该路径下找'view/analysis/index.html'模版文件 'APP_DIRS': True # 可去注册的app路径下找到templates目录,在该目录下找模版文件
1
2
3
4Img、css、js的查找顺序
STATIC_URL = '/staic/' # 前缀 STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] # 去哪找 !!基于上述的配置!!(这是前提 """ STATIC_URL必须得有. 1 根据 <img src='/static/web/1.png'> 得到url 2. 浏览器根据url发送请求 http://127.0.0.1:8000/static/web/1.png 3. 服务器优先在项目根目录下找路径 /static/web/1.png; 若没找到就按注册顺序去已注册的app下找路径 /static/web/1.png ★ 经验:多app的情况,会在app的templates、static目录下再嵌套一层命名为app名字的目录.该目录下放模版!! """
1
2
3
4
5
6
7
8
9
10
11
12
13具体操作
将前端模版 pear admin layui中的
admin
、component
、config
三个目录复制到后端的static
目录里将前端模版 pear admin layui中的
view
目录复制到 后端的templates
目录里将前端模版 pear admin layui中的
index.html
、login.html
复制到templates
目录中进行静态文件里路径的修改, 举例 (浏览器控制台的网络可以看是否改正确
<link rel="stylesheet" href="./component/pear/css/pear.css" /> 修正成 <link rel="stylesheet" href="/static/component/pear/css/pear.css"/> /component/pear/css/pear.css 放在后端项目根目录下的staic文件夹里!! pear.config.json里 "href": "view/analysis/index.html" 保持原样,懒得改了! > 就按照http://127.0.0.1:8080/view/analysis/index.html发送请求 写个名为/view/analysis/index.html的路由,进行路由匹配 匹配的视图函数 return render(request, 'view/analysis/index.html') 返回index.html 将index.html放在后端项目根目录下的templates/view/analysis文件夹里
1
2
3
4
5
6
7
8
9
10可以在 index.html 中给 html 标签添加
lang='zh-CN'
, 每次刷新时就不会弹出翻译提示了 + 时区的设置
# 项目数据表的设计
ORM的编写必须在app中, 用名为models的包来实现, 将原本写在models.py中的ORM表拆分成一个个的py文件.
关于ORM表,也拆分到了一个个py文件中,还根据来自不同的app,放在了不同的文件夹中 因为使用了包,所以在调用上跟 这些py文件放在同一个文件夹下 没差别!! 但代码更清晰一点! - 思考?若rbac的用户表满足不了,systems中自己弄个用户表. 方案一 一对一外键, 一张表的字段被拆分到了两表中,不妥 方案二 继承+abstract = True 让rbac中的用户表迁移时不生成表 方案三 你直接使用rbac的用户表 对其进行更改,使其满足systems的标准. 这种更方便!!
1
2
3
4
5
6ORM代码编写完后, 启动mysql数据库, 执行命令进行数据库的迁移..
- 在pycharm中连接mysql数据库后.
在mysql的终端, 执行命令create database pear_admin_django character set utf8mb4;
- 在Django中
local_setting.py
中进行mysql的配置, 开始数据库的迁移.
- 在pycharm中连接mysql数据库后.
用脚本批量添加测试数据
name,age,sex x,,10 y,,22 csv文件中 某个字段值没写 模拟的就是表单中有该字段,但该字段没填??Hhh
1
2
3
4
5
# rbac模块
关于rbac, 基于角色的用户权限管理系统.. 我大体分为了5个模块, 登陆、部门管理、权限管理、角色管理、用户管理..
这些功能的实现更重要的是想清楚有哪些需求, 用怎样的技术实现更合适, 代码编写反而不是最难的..
各个模块的需求详看规则怪谈..
# layui前端框架
下面我们来康康利用layui前端框架, 帮助我在项目开发过程中, 解决了哪些通用性的问题, 以便往后遇到类似需求可复用..
[主页]
1. 解决了树形表格中根据排序字段的大小实现列表数据排序的问题
2. 解决了树形表格中的全部折叠和全部展开 -- To do: 若指定到第几层如何实现,待解决.
3. 解决了表格中,数据样式的问题. by templet属性 + es6语法
eg: 根据值的不同,展示对应的`菜单`、`节点`、`权限`的徽章
4. hide:True 可以让该列在表格中自动隐藏,当然可以在主页表格中选择展示哪些列.
5. 一行table标签,数据通过layui的组件自动渲染
- 头部工具栏 > 新增的iframe、全部折叠、全部展开
- 行工具栏 > 编辑的iframe<需实现自动填充表单>、删除
6. 启动|禁用按钮的复选框事件 - 注: 某个权限的禁用会影响动态菜单的展示以及中间件里权限的鉴定
7. 在ORM表的json方法中实现了日期数据的处理!
8. 日期范围的选择!
2
3
4
5
6
7
8
9
10
11
[新增、编辑 的表单]
1. 实现了 选择不同的单选框,在表单中显示隐藏不同的表单项 - <单选框事件“监听类型切换”>
2. 实现了 表单中,鼠标悬浮在表单项上,会有提示的功能.
3. 权限模块的新增编辑页面,解决了图标选择问题
-- https://gitee.com/wujiawei0926/iconpicker
4. 权限模块的新增编辑页面,解决了下拉框选择问题(下拉展示的是权限树
-- https://gitee.com/honestno1/combotree
>> 关于3、4 我直接添加到了pear里面!!
5. 解决了图标选择、下拉框单选、下拉框展示树、单选框 在编辑页面的表单里默认选择的问题!!
6. 权限模块 对权限实现了软删除. 部门、用户、角色同理!
2
3
4
5
6
7
8
9
[授权 树]
1. 利用了 tree 组件,实现了对角色授权!
[其它]
1. X_FRAME_OPTIONS = 'SAMEORIGIN' # 避免'X-Frame-Options' to 'deny' 的报错! 解决弹窗被浏览器劫持问题
2. 解决CSRF
let token = "{{ csrf_token }}";
$.ajaxSetup({
headers: {'X-CSRFTOKEN': `${token}`},
});
2
3
4
5
6
# pear admin前端模版
[一些注意事项]
1. 基于combotree实现的树,返回的json数据中名字相关的字段只能叫做name,若是title,它识别不了.
combotree组件render时,data是接收静态数据,ajaxUrl才是发送ajax请求的参数.
<实践过程中,报了个错 说在pear中找不到combotree组件的的treetable依赖,放进去就好.不要纠结为啥!
>> ★★★ 后来,我直接添加到了pear里面!!
2. 实现动态菜单时,规定了是名为type字段,其值的含义可想象成0是目录,1是文件; 地址规定了是名为href的字段
3. pear.config.json里,首页对应的默认选中的菜单的ID一定要设置正确!!
4. {{ edit_obj.pid_id|default:'' }} 数据库中字段值为null,前端会显示None,当None时我们让前端显示为空
2
3
4
5
6
7
[一些思考或待解决或尝试过无果的问题]
1. _blank的形式打开节点,需要加载下layui.js
若添加后,默认的内部打开的节点,会因为添加了layui.js而出现样式错误 (挺奇怪的
若改为添加layui.js和pear.js,控制台会报错,重复加载模块组件的错误.
> 尝试解决无果,我觉得全部都选择默认的内部打开即可!!
!!! 后续我解决了这个问题 内部打开不要用_component,要用_iframe
2. 想着自动发现路由,改写下源码,给path加上text属性,但想想还是算了,暂时没必要折腾这个!
3. 半分离的编辑参照不分离的编辑的逻辑,按道理在返回编辑页面之前,不仅要实现表单数据的自动填充,
还得判断该id是否有对应的对象,我思考了下:
url上没有?params参数,request.GET.get('id')值为空, filter first后也为空,展示的编辑表单都为空,无伤大雅!
4. 动态菜单函数添加一个超级用户判断,使得添加新权限后,超级用户不用给自己授权,就能刷新展示新的菜单??
没必要,superman老老实实给自己授权就好.
5. 若我在右上角的头像的下拉菜单里,添加了"个人中心"的选项,它不用引入css、js,用的就是index.html里的.
而且你若引入了,左侧的动态菜单的展开关闭的js动画会抽搐.
而为了后面能给角色授权,个人中心相关的几个url也要一并写在权限中,意味着它也会出现在动态菜单中!!
出现在动态菜单中的话,这个个人中心的页面就得添加js、css..
前后的分析需求是矛盾的,不能同时实现. > 解决方案:在头像下拉中只保留注销选项,个人中心的选项删除掉!让个人中心出现在动态菜单里.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pear admin layui 的开源项目中有 柱状图、折线图 的模版, 需要时可以去参考..
加载的配置文件,每个配置项啥意思, 参考
https://gitee.com/pear-admin/pear-admin-flask/blob/master/applications/view/system/rights.py
[主页]
To do: 若n:n,后端ORM表的json方法将对应字段处理下,前端再自行处理下.
To do: 组合搜索
[新增、编辑 的表单]
6. To do:权限模块 新增编辑时 对于权限的标识和url与系统中的是否匹配?! (因为这东西涉及权限校验,马虎不得.
下拉框展示可添加的节点、权限的URL和标识?没有则显示暂无可添加的节点和权限?
> 菜单-权限管理,一般开发完就不会动了,所以需要开发一个接口扫描功能吗??没必要吧!!
[其它]
2. To do: 短信验证码登陆?
3. To do: 将pear.config.json的配置的获取改为接口,而不是直接加载json文件?
- 该角色分配给了其他用户使用,无法删除!
- 权限那里是否开启 除了超级管理员,哪怕给某个角色分配了该权限,该权限没有开启也不会生效!!
- 用户那里账号不可用的话,是登陆不了的!!
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
to -1 -2 -3 还是在seccess里弄..
完善下登陆认证和权限认证.. 整理下需求和已完成的功能出来..
form = UserAddForm(request.POST)
my_l = []
for name, field in form.fields.items():
print(name, field)
my_l.append(name)
print(my_l)
if not form.is_valid():
return res_json_data.no_valid_api(form)
2
3
4
5
6
7
8