Django 权限管理(二)
权限菜单展示
1.展示的效果
实现该效果,涉及到的核心点(突破点)
1. 权限分类:
(1)菜单权限 (主要用来展示的权限(url)如查看权限 url, 如上图中的每个权限都归类为菜单权限,主要用来构建权限列表)。
(2)按钮权限(主要用来 添加,删除,修改 的权限url )。
(3) 实现 权限分类的方法。
在权限model类 Permission ,设置一个 type 字段 type = model.Charfield(max_length=32,choices=(("menu","菜单权限"),(“button”,"按钮权限")),default="menu"))
后端通过该type 字段判断哪些权限需要展示。
2. 权限的树形结构。构建 权限分层,就是权限归类。如 信息管理 权限下有--- 客户管理权限,订单管理权限,客户管理权限下有查看客户权限,订单管理权限下有查看订单。
(1)自关联。
在权限model类Permission 中设置一个字段自关联字段,类似一对多 的情况,就是一个父权限可以多个子权限, 该字段用于记录每个权限的父权限id
#自关联,解决 层级关系问题,谁是谁的子权限 ,树形结构
parent = models.ForeignKey("Permission",on_delete=models.CASCADE,null=True,blank=True) #null = True 该权限的父权限可以为空, blank=True 添加该权限时可以不填内容。
(2)权限列表树形结构数据的构建
需要通过菜单权限列表,构建出以下类型的数据结构,如何实现。
default_data = [
{
"text": '信息管理',
"href": '',
"tags": ['2'],
"nodes": [
{
"text": '客户管理',
"href": '',
"tags": ['1'],
"nodes": [
{
"text": '查看客户',
"href": '/stark/app1/customer/',
"tags": ['0']
},
]
},
{
"text": '订单管理',
"href": '',
"tags": ['1'],
"nodes": [
{
"text": '查看订单',
"href": '/stark/app1/order/',
"tags": ['0']
},
]
},
]
}, {
"text": '权限管理',
"href": '',
"tags": ['0']
}, ]
实现逻辑:
1. 用户登录成功后,获取该用户的权限,并构建权限列表
def permission_init(request,user_obj):
queryset = user_obj.roles.all().values(
"permissions__title", # 跨表
"permissions__url",
"permissions__type",
"permissions__parent",
"permissions__id",
).distinct() # [{'permissions__title': '查看客户', 'permissions__url': '/stark/app1/customer/'},.....]
# 准备一个权限列表,用来装用户所有的权限
permissions_list = []
for per in queryset:
permissions_list.append(
{
"url": per.get("permissions__url"),
"title": per.get("permissions__title"),
"type": per.get("permissions__type"),
"pid": per.get("permissions__parent"),
"id": per.get("permissions__id"),
}
)
# 将权限列表注入session ,用户下次登录可以获取到该权限列表
request.session["permission_list"] = permissions_list
2.获取用户的权限列表
(1)先经过,权限类型过滤,判断是菜单权限还是按钮权限,过滤出菜单权限,用于展示到页面。
(2)通过 菜单权限列表,构建 树形结构数据(前端需要展示的树形结构数据)
(3)权限列表路径展开问题的解决
难点在于如何给当前选择的路径的所有父权限,设置属性。state :{“expanded”:True}
from django import template
import json
register = template.Library() @register.inclusion_tag("rbac/menu.html")
def get_menu(request):
permission_list = request.session.get("permission_list") #获取用户的权限列表
per_list = []
permission_dic ={}
#循环重构字典 , 每一个权限的id 为键,新字典为value ,构成一个新的字典
for per_dic in permission_list:
new_per_dic = {}
#剔除非菜单权限
if per_dic.get("type") == "button":
continue
#对菜单权限,重构数据结构,以id 值为键,新数据结构为value值
new_per_dic["text"] = per_dic["title"]
new_per_dic["href"] = per_dic["url"] or ""
new_per_dic["pid"] = per_dic["pid"] or ""
new_per_dic["nodes"] = []
#new_per_dic["state"] = {"expanded":True} #此属性 设置节点展开 ,bootstrap_view 插件中的语法state :expanded为True 时节点时展开的
permission_dic[per_dic.get("id")] = new_per_dic #重构出的字典大致结构如下:
# permission_dic={
# 1:{"text":"信息管理","href":"","nodes":[],"pid":None},
# 2:{"text":"权限管理","href":"","nodes":[],"pid":None},
# 3:{"text":"客户管理","href":"","nodes":[],"pid":1},
# 4:{"text":"订单管理","href":"","nodes":[],"pid":1},
# 6:{"text":"查看客户","href":"","nodes":[],"pid":3},
# 7:{"text":"查看订单","href":"","nodes":[],"pid":4},
# }
# 路径展开
current_path = request.path #过滤出一级权限,也就是 父pid 为None 的权限 ,加入已经准备好的数据列表
for id,dic in permission_dic.items():
#找到根节点,也就是一级权限
if not dic["pid"]:
per_list.append(dic)
else:
permission_dic[dic["pid"]]["nodes"].append(dic) #路径展开逻辑
if dic["href"]==current_path: #找到当前的路径
pid =dic["pid"] #找到当前路径的父级 pid
#通过while 循环不断的往上找父及诶单,并将父节点设置 相关的属性 while pid:
permission_dic[pid]["state"] = {"expanded":True}
pid = permission_dic[pid]["pid"]
#为什么需要用json格式的,因为python代码 None,Ture 在js 语法中不能识别,所以需要转化成json字符串给插件
return {"default_data": json.dumps(per_list)}
inclusion_tag("filename.html")
1. 该自定义标签,返回必须是一个字典形式,一般该方法需要带参数reuqest , 是通过render 方法进行渲染的。在全局可以应用,该标签。
2. 应用场景,权限菜单栏,在增,删,改,查页面都需要通过动态数据渲染出菜单权限栏时,用此中方法可以解决代码重复问题。
3. 实现 效果: 给调用该方法的页面返回一个html 前端标签代码。相当于 通过该标签方法,得到后端数据,返回字典格式的数据,该数据
在 filename.html 渲染后,将该filename.html后的效果返回给前端页面调用该方法的位置。
该方法写在 上图rbac.py 中:
from django import template
import json
register = template.Library() @register.inclusion_tag("rbac/menu.html")
def get_menu(request):
permission_list = request.session.get("permission_list")
per_list = []
permission_dic ={}
#循环重构字典 , 每一个权限的id 为键,新字典为value ,构成一个新的字典
for per_dic in permission_list:
new_per_dic = {}
#剔除非菜单权限
if per_dic.get("type") == "button":
continue
#对菜单权限,重构数据结构,以id 值为键,新数据结构为value值
new_per_dic["text"] = per_dic["title"]
new_per_dic["href"] = per_dic["url"] or ""
new_per_dic["pid"] = per_dic["pid"] or ""
new_per_dic["nodes"] = []
#new_per_dic["state"] = {"expanded":True} #此属性 设置节点展开 ,bootstrap_view 插件中的语法state :expanded为True 时节点时展开的
permission_dic[per_dic.get("id")] = new_per_dic #重构出的字典大致结构如下:
# permission_dic={
# 1:{"text":"信息管理","href":"","nodes":[],"pid":None},
# 2:{"text":"权限管理","href":"","nodes":[],"pid":None},
# 3:{"text":"客户管理","href":"","nodes":[],"pid":1},
# 4:{"text":"订单管理","href":"","nodes":[],"pid":1},
# 6:{"text":"查看客户","href":"","nodes":[],"pid":3},
# 7:{"text":"查看订单","href":"","nodes":[],"pid":4},
# }
# 路径展开
current_path = request.path #过滤出一级权限,也就是 父pid 为None 的权限 ,加入已经准备好的数据列表
for id,dic in permission_dic.items():
#找到根节点,也就是一级权限
if not dic["pid"]:
per_list.append(dic)
else:
permission_dic[dic["pid"]]["nodes"].append(dic) #路径展开逻辑
if dic["href"]==current_path: #找到当前的路径
pid =dic["pid"] #找到当前路径的父级 pid
#通过while 循环不断的往上找父及诶单,并将父节点设置 相关的属性 while pid:
permission_dic[pid]["state"] = {"expanded":True}
pid = permission_dic[pid]["pid"]
#为什么需要用json格式的,因为python代码 None,Ture 在js 语法中不能识别,所以需要转化成json字符串给插件
return {"default_data": json.dumps(per_list)}
@register.inclusion_tag("rbac/menu.html")
menu.html:(该标签html ,参数文件)
<div id="treeview" class="small"> </div> <script src="/static/bootstrap-treeview/js/bootstrap-treeview.js"></script> <script type="text/javascript">
// API文档参数列表: https://www.cnblogs.com/tangzeqi/p/8021637.html $(function () { var options = {
data:{{ permission_tree_list|safe }}, //data属性是必须的,是一个对象数组 Array of Objects.
color: "", //所有节点使用的默认前景色,这个颜色会被节点数据上的backColor属性覆盖. String
backColor: "#22282e", //所有节点使用的默认背景色,这个颜色会被节点数据上的backColor属性覆盖. String
borderColor: "#000000", //边框颜色。如果不想要可见的边框,则可以设置showBorder为false。 String
nodeIcon: "glyphicon glyphicon-stop", //所有节点的默认图标
checkedIcon: "glyphicon glyphicon-check", //节点被选中时显示的图标 String
collapseIcon: "glyphicon glyphicon-minus", //节点被折叠时显示的图标 String
expandIcon: "glyphicon glyphicon-plus", //节点展开时显示的图标 String
emptyIcon: "glyphicon", //当节点没有子节点的时候显示的图标 String
enableLinks: false, //是否将节点文本呈现为超链接。前提是在每个节点基础上,必须在数据结构中提供href值。 Boolean
highlightSearchResults: true, //是否高亮显示被选中的节点 Boolean
levels: 2, //设置整棵树的层级数 Integer
multiSelect: false, //是否可以同时选择多个节点 Boolean
onhoverColor: "#F5F5F5", //光标停在节点上激活的默认背景色 String
selectedIcon: "glyphicon glyphicon-stop", //节点被选中时显示的图标 String searchResultBackColor: "", //当节点被选中时的背景色
searchResultColor: "", //当节点被选中时的前景色 selectedBackColor: "", //当节点被选中时的背景色
selectedColor: "#FFFFFF", //当节点被选中时的前景色 showBorder: true, //是否在节点周围显示边框
showCheckbox: false, //是否在节点上显示复选框
showIcon: true, //是否显示节点图标
showTags: false, //是否显示每个节点右侧的标记。前提是这个标记必须在每个节点基础上提供数据结构中的值。
uncheckedIcon: "glyphicon glyphicon-unchecked", //未选中的复选框时显示的图标,可以与showCheckbox一起使用
}; $('#treeview').treeview({ color: "white",
onhoverColor:"#394555",
selectedColor:"white",
showBorder: false,
expandIcon: 'glyphicon glyphicon-chevron-right',
collapseIcon: 'glyphicon glyphicon-chevron-down',
nodeIcon: 'glyphicon glyphicon-bookmark',
enableLinks: true,
levels: 1,
showIcon: false,
selectedBackColor: "",
backColor: "#22282e",
highlightSearchResults: true,
data: {{ permission_tree_list|safe }},
}); $('#treeview').on('nodeSelected', function (event, data) {
console.log(data);
}) });
</script>
menu.html
base.html :(调用该标签的文件)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
{% block title %}
<title>Starter Template for Bootstrap</title>
{% endblock title %}
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/site.css">
<script src="/static/js/jquery-3.3.1.js"></script> </head> <body> <div class="container-fluid site-wrapper"> <!-- site-navbar -->
<div class="site-navbar navbar-fixed-top">
<span class="site-navbar-title">CRM后台管理</span>
</div> <!-- /.site-navbar --> <div class="row"> <!-- site-menu -->
<div class="site-menu"> <p class="site-menu-title">主菜单</p> {% block side_bar %}
{% load rbac %} {% get_menu request %}
{% endblock side_bar %} </div> <!-- /.site-menu --> <!-- site-body -->
<div class="site-body"> <div class="site-content-wrap"> {% block content %} {% endblock content %} </div> </div> <!-- site-body --> </div> </div><!-- /.container-fluid --> <script src="/static/bootstrap/js/bootstrap.js"></script> <script src="/static/js/site.js"></script> {% block script %} {% endblock script %} </body>
</html>
base.html 调用该标签的文件
Django 权限管理(二)的更多相关文章
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- 【Python】django权限管理
参考:http://www.cnblogs.com/esperyong/ 参考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#t ...
- django权限管理(一)
权限:权限就是一个包含正则的url. Rbac 权限管理: Role-Based Access Control,基于角色的访问控制.用户通过角色与权限进行关联,一个用户可以有多个角色,一个角色可以有多 ...
- 一.8.django权限管理/drf权限管理
1.什么是权限管理: .权限管理,一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源 .权限管理好比如钥匙,有了钥匙就能把门打开,但是权限设置是有级别之分的,假如这个系 ...
- SQL Server与Oracle对比学习:权限管理(二) 一些有趣的比喻
http://blog.csdn.net/weiwenhp/article/details/8094739 目录(?)[-] SQL Server权限管理 login 与user的区别 角色role ...
- Shiro集成SSM基于动态URL权限管理(二)
这个案例基于上一个demo扩展而来.所以数据库表,在Shiro集成SSM基于URL权限管理(一)开篇的一致.如果上个demo操作的建议重新导入一次,避免出现问题. 而这次都不是通过固定写在方法上的注解 ...
- Django学习手册 - 权限管理(二)
从数据库获取数据后,对数据进行清洗 目标: 数据1,存放至session 中的数据 数据2,显示至前端的菜单数据 清洗数据: 1.session存放的数据:(menu_leaf_dict) 2.前端菜 ...
- Django web框架之权限管理二
1. login登录 def login(request): if request.method=="GET": return render(request,'login.html ...
- Django 权限管理
对于Django而言,虽然自带了一些基本的通用权限限制,但现实中,可能我们更希望自己去定义业务权限划分 Django对于权限这块的部分验证方法 user = request.user user.is_ ...
随机推荐
- Bootstrap3基础 btn-primary/warning... 三类按钮的六种样式
内容 参数 OS Windows 10 x64 browser Firefox 65.0.2 framework Bootstrap 3.3.7 editor ...
- POJ 2955 Brackets(区间DP)题解
题意:问最多有几个括号匹配 思路:用dp[i][j]表示i到j最多匹配,若i和j构成匹配,那么dp[i][j] = dp[i + 1][j - 1] + 2,剩下情况dp[i][j] = max(dp ...
- (转)ElasticSearch学习
(二期)21.全文搜索引擎Elasticsearch [课程21]elasticsearch.xmind82.1KB [课程21]lucene.xmind0.8MB [课程21]基本用法....api ...
- P4145 上帝造题的七分钟2 / 花神游历各国
思路 每个数不会被开方超过log次,对每个数暴力开方即可 代码 #include <algorithm> #include <cstring> #include <cst ...
- 利用Python 脚本生成 .h5 文件 代码
利用Python 脚本生成 .h5 文件 import os, json, argparse from threading import Thread from Queue import Queue ...
- NLog汇总
相关文章 NLog文章系列——系列文章目录以及简要介绍 Elasticsearch,Kibana,Logstash,NLog实现ASP.NET Core 分布式日志系统 ElasticSearch+N ...
- 4、iptables扩展匹配及网络防火墙功能
关于centos7 firewalld http://www.ibm.com/developerworks/cn/linux/1507_caojh/index.html 如何保存及重载规则: ...
- php CLI SAPI 内置Web Server
PHP 5.4.0起, CLI SAPI 提供了一个内置的Web服务器. 这个内置的Web服务器主要用于本地开发使用,不可用于线上产品环境. URI请求会被发送到PHP所在的的工作目录(Working ...
- Java中String类型细节
Java中String类型细节 一 . String两种初始化方式 1 . String str1= “abc”;//String类特有的创建字符对象的方式,更高效 在字符串缓冲区中检测”abc”是否 ...
- 一篇好文之Android数据库 GreenDao的完全解析
数据库GreenDao.jpg 之前在开发过程中,数据库基本上会使用Litepal或者SQlite自己写,最近换新环境,公司原先使用的数据库就是GreenDao,在各种情况的作用下,准备了解下Gree ...