权限菜单展示

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 权限管理(二)的更多相关文章

  1. 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权

    原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...

  2. 【Python】django权限管理

    参考:http://www.cnblogs.com/esperyong/ 参考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#t ...

  3. django权限管理(一)

    权限:权限就是一个包含正则的url. Rbac 权限管理: Role-Based Access Control,基于角色的访问控制.用户通过角色与权限进行关联,一个用户可以有多个角色,一个角色可以有多 ...

  4. 一.8.django权限管理/drf权限管理

    1.什么是权限管理: .权限管理,一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源 .权限管理好比如钥匙,有了钥匙就能把门打开,但是权限设置是有级别之分的,假如这个系 ...

  5. SQL Server与Oracle对比学习:权限管理(二) 一些有趣的比喻

    http://blog.csdn.net/weiwenhp/article/details/8094739 目录(?)[-] SQL Server权限管理 login 与user的区别 角色role ...

  6. Shiro集成SSM基于动态URL权限管理(二)

    这个案例基于上一个demo扩展而来.所以数据库表,在Shiro集成SSM基于URL权限管理(一)开篇的一致.如果上个demo操作的建议重新导入一次,避免出现问题. 而这次都不是通过固定写在方法上的注解 ...

  7. Django学习手册 - 权限管理(二)

    从数据库获取数据后,对数据进行清洗 目标: 数据1,存放至session 中的数据 数据2,显示至前端的菜单数据 清洗数据: 1.session存放的数据:(menu_leaf_dict) 2.前端菜 ...

  8. Django web框架之权限管理二

    1. login登录 def login(request): if request.method=="GET": return render(request,'login.html ...

  9. Django 权限管理

    对于Django而言,虽然自带了一些基本的通用权限限制,但现实中,可能我们更希望自己去定义业务权限划分 Django对于权限这块的部分验证方法 user = request.user user.is_ ...

随机推荐

  1. 没有使用Material组件

    // 这个App没有使用Material组件, 如Scaffold. // 一般来说, app没有使用Scaffold的话,会有一个黑色的背景和一个默认为黑色的文本颜色. // 这个app,将背景色改 ...

  2. Django 创建项目笔记

    基本命令 mkdir mysite # 创建项目目录,常取名mysite cd mysite virtualenv env # env\Scripts\activate.bat # Win pip i ...

  3. LOJ6285 数列分块入门9(分块)

    昨天对着代码看了一晚上 然后今天终于在loj上过了 数列分块入门9题撒花★,°:.☆( ̄▽ ̄)/$:.°★ . 然后相当玄学 块的大小调成\(\sqrt{n}\)会TLE,改成150就过了 啧 然后就 ...

  4. Git回顾

    抄自廖雪峰的官方网站 完整图文请访问https://github.com/Mrlution/study/tree/master/git 关于repository 我认为repository是一个存放代 ...

  5. 6、tcp_wrapper

    iptables的链接跟踪表最大容量为/proc/sys/net/ipv4/ip_conntrack_max,链接碰到各种状态的超时后就会从表中删除. 所以解決方法一般有两个: (1) 加大 ip_c ...

  6. ASP.NET MVC AntiForgeryToken

    你开发一个网站,其中有个功能:新闻发布. 你是这样实现的: 1.保存新闻的方法是:/News/Save  POST提交 2.接受两个参数:title和content 有一天,你登录网站(浏览器会保存相 ...

  7. HDU 5452 Minimum Cut(LCA)

    http://acm.hdu.edu.cn/showproblem.php?pid=5452 题意: 有一个连通的图G,先给出图中的一棵生成树,然后接着给出图中剩余的边,现在要删除最少的边使得G不连通 ...

  8. 什么是java OOM?如何分析及解决oom问题?

    最近查找了很多关于OOM,甚至于Java内存管理以及JVM的相关资料,发现这方面的东西太多了,竟有一种眼花缭乱的感觉,要想了解全面的话,恐非一篇文章能说清的,因此按照自己的理解整理了一篇,剩下的还需要 ...

  9. sublime text3 license

    —– BEGIN LICENSE —– Michael Barnes Single User License EA7E-821385 8A353C41 872A0D5C DF9B2950 AFF6F6 ...

  10. NOI2017 游记

    成功在NOI2017退役……现在的我已经是一只退役狗了 结果也一直到了退役,我都还不会半平面交,不会单纯形,不会非旋转版Treap…… FWT我也不熟,分治FFT我也只写过一道板子题 但是现在已经退役 ...