权限菜单展示

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. Bootstrap3基础 input-group glyphicon 输入框组与glyphicon图标

      内容 参数   OS   Windows 10 x64   browser   Firefox 65.0.2   framework     Bootstrap 3.3.7   editor    ...

  2. HDU 4366 Successor(dfs序 + 分块)题解

    题意:每个人都有一个上司,每个人都有能力值和忠诚值,0是老板,现在给出m个询问,每次询问给出一个x,要求你找到x的所有直系和非直系下属中能力比他高的最忠诚的人是谁 思路:因为树上查询很麻烦,所以我们直 ...

  3. (转载)WinformGDI+入门级实例——扫雷游戏(附源码)

    本文将作为一个入门级的.结合源码的文章,旨在为刚刚接触GDI+编程或对相关知识感兴趣的读者做一个入门讲解.游戏尚且未完善,但基本功能都有,完整源码在文章结尾的附件中. 整体思路: 扫雷的游戏界面让我从 ...

  4. 在mybatis中resultMap与resultType的区别

    MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMapresultType是直接表示返回类型的,而resultMap则是对外部ResultMa ...

  5. ISTQB学习笔记

    学习ISTQB大纲此文记录初次阅读时不够明确的地方 第一章:软件测试基础1. 引起软件缺陷的原因人都会犯错误(error,mistake),因此人设计的代码或文档中会引入缺陷(defect, faul ...

  6. 【转】Windows下selenium+python自动化测试环境搭建

    原文链接:http://www.cnblogs.com/test-of-philosophy/articles/4322918.html 搭建平台:windows 1.安装python,下载地址:ht ...

  7. python requests post和get

    import requests import time import hashlib import os import json from contextlib import closing impo ...

  8. sklearn dataset 模块学习

    sklearn.datasets官网:http://scikit-learn.org/stable/datasets/ sklearn.datasets 模块主要提供一些导入.在线下载及本地生成数据集 ...

  9. Javascript 常用设计模式

    转载自:https://blog.csdn.net/buptlyz/article/details/52018193 单例模式(模块模式):确保始终只创建一个实例的对象时使用的设计模式. 为什么需要采 ...

  10. pytorch-1.0 踩坑记录

    参加百度的一个竞赛,官方要求把提交的代码测试环境pyorch1.0,于是将自己计算机pytorch升级到1.0. 在ubuntu下用conda install pytorch 命令安装时,效果很差,解 ...