权限菜单展示

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. How to Install LibreOffice 6.0 on Ubuntu 16.04 LTS +

    1. Add the LibreOffice 6.0 PPA The LibreOffice Fresh PPA is maintained by LibreOffice. It provides l ...

  2. 简单明了的掌握diff命令? 参考: http://www.ruanyifeng.com/blog/2012/08/how_to_read_diff.html

    diff是比较两个 文本文件, 或目录,(中名字相同的文件) diff 是按行来比较的, 只要两个对应的行, 不完全一致, 就报告为不同, 否则就视为相同. (一行中任意一点的不同...) 检查时, ...

  3. iis6-0 cve-2017-7269 批量验证脚本

    代码地址 import subprocess f = open('ips.txt', 'r') flines = f.readlines() vulnsrvs = 0 i = 1 for line i ...

  4. 【入门】Gradle的基本使用、在IDEA中的配置、常用命令

    一.介绍 java的源码构建工具,大致经历了 ant -> maven -> gradle 这个过程,每一次进步,都是在解决之前的工具所带来的问题,简单来说: 1. ant 功能虽然也很强 ...

  5. Entity Framework Core

    Entity Framework是一种支持 .NET 开发人员使用 .NET 对象处理数据库的对象关系映射程序 (O/RM). 它不要求提供开发人员通常需要编写的大部分数据访问代码. Entity F ...

  6. Sublime Text3 插件:DocBlockr与javascript注释规范

    原:http://www.ithao123.cn/content-719950.html 1.引子 在写代码的时候,尤其是写脚本,最需要注释了.目前脚本.样式的注释格式都有一个已经成文的约定规范(这些 ...

  7. Gym 100247C Victor's Research(有多少区间之和为S)

    https://vjudge.net/problem/Gym-100247C 题意: 给出一串数,求有多少个区间的和正好等于S. 思路:计算处前缀和,并且用map维护一下每个前缀和出现的次数.这样接下 ...

  8. List<Model>转String 、String 转List<string>

    var ltCode = from item in psw.VehicleInsuranceItem select item.Code; string code = string.Join(" ...

  9. JS基础---到底什么是闭包?它是如何形成的?

    1.闭包 先看一个简单的例子 function a() { var i = 0; function b() { alert(++i); } return b; }var c = a(); c(); 这 ...

  10. 【一】php 基础知识

    1 php标记,<?php php代码 ?> 2 注释:代码的解释和说明 多行注释 /**/ 单行注释 //.# 3“.”连接符 echo "hello".date(& ...