解决力度到按钮的级别

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  方案:添加一个新表,permissiongroup,一对多 permission表。

        给permission表新添加一个字段,code字段。为什么加code字段,与不同的url一一对应,方便之后直接拿 code,而不是拿一长串url来堆下面踢掉的request.permission_code进行比对。

from django.db import models

# Create your models here.

class UserInfo(models.Model):
name=models.CharField(max_length=,verbose_name='用户名')
pwd=models.CharField(max_length=,verbose_name='密码')
email=models.CharField(max_length=,verbose_name='邮箱')
roles=models.ManyToManyField(to='Role')
def __str__(self):
return self.name class Role(models.Model):
name=models.CharField(max_length=,verbose_name='角色名')
permissions=models.ManyToManyField(to='Permission',blank=True)
def __str__(self):
return self.name class PermissionGroup(models.Model):
name=models.CharField(max_length=)
def __str__(self):
return self.name class Permission(models.Model):
name=models.CharField(max_length=,verbose_name='权限名')
url=models.CharField(max_length=,verbose_name='网址',default=None)
code=models.CharField(max_length=,default='select')
permissiongroup=models.ForeignKey(to=PermissionGroup,default=)
def __str__(self):
return self.name

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

init_permission 文件中,初始化生成的格式进行更改。

  直接利用ORM操作拿到的queryset列表并不能满足我们的需要。我们需要下面这种格式的数据。为什么这样做,为了解决粒度问题。

  所以这一步的升级做法是将拿到的queryset表---->两层字典。

{: {'code': ['select'], 'url': ['/user/select/']},
: {'code': ['select'], 'url': ['/order/select/']}}

{

  permissiongroup_id:{

            "code":[  ],

            "url":[  ],

            }

}

  注释掉的是之前的代码

from django.conf import settings
from pprint import pprint
def init_permission(user,request):
permission_list = user.roles.filter(permissions__name__isnull=False).values('permissions__name',
'permissions__code',
'permissions__permissiongroup__id',
'permissions__url').distinct()
print(permission_list)
''' '''
# url_list = []
# for item in permission_list:
# url_list.append(item.get('permissions__url'))
permission_dict={}
for item in permission_list:
id=item.get('permissions__permissiongroup__id')
if id not in permission_dict:
permission_dict[id]={}
permission_dict[id]['url']=[item.get('permissions__url')]
permission_dict[id]['code']=[item.get('permissions__code')]
else:
permission_dict[id]['url'].append(item.get('permissions__url'))
permission_dict[id]['code'].append(item.get('permissions__code'))
# pprint(permission_dict) request.session[settings.PERMISSION_SESSION_KEY] = permission_dict

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

中间件的代码也要随之改动

  

from django.shortcuts import render,redirect,HttpResponse
import re
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
class RbacMiddleware(MiddlewareMixin):
def process_request(self,request):
# 获取白名单
permission_valid_url=settings.PERMISSION_VALID_URL
for url in permission_valid_url:
if re.match(url,request.path_info):
return None # 获取权限
permission_dict = request.session.get(settings.PERMISSION_SESSION_KEY) if not permission_dict:
return HttpResponse('未能读取到该用户的信息')
# 对用户请求的url进行匹配
'''
{: {'url': ['/order/select/'], 'code': ['select']}, : {'url': ['/user/select/'], 'code': ['select']}}
'''
flag=False
for value in permission_dict.values():
url_list=value.get('url')
code_list=value.get('code')
for reg in url_list:
reg='^{}$'.format(reg)
if re.match(reg,request.path_info):
flag=True
break
if flag:
request.permission_code=code_list #给当前用户 赋予 此用户当前组拥有的权限的代号
break
if not flag:
return HttpResponse('无权访问') # flag = False
# for url in url_list:
# url='^{}$'.format(url)
# if re.match(url, request.path_info):
# flag = True
# break
# if not flag:
# return HttpResponse('无权访问')
return None

  有一个很关键的点是,如果在某个permissiongroup中,匹配到用户拥有访问的当前网页的权限,然后,把这个当前网页所属的那个组的所拥有的所有权限的code/url列表赋予到request的某个属性上。

  这样,顺利通过中间件后,所有的不属于白名单的视图函数都可以拿到request的这个属性。

  实现这个功能的核心代码是:

for reg in url_list:
reg='^{}$'.format(reg)
if re.match(reg,request.path_info):
flag=True
break
if flag:
request.permission_code=code_list #给当前用户 赋予 此用户当前组拥有的权限的代号
break

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

在前端实现力度到按钮级别

  视图函数

  

def userselect(request):
'''
根据有无权限,
显示所有的用户信息
:param request:
:return:
'''
# if request.session.get('url_list'):
# url_list=request.session.get('url_list')
# flag = False
# for url in url_list:
# if re.match(url,request.path_info):
# flag=True
# break
# if not flag:
# return HttpResponse('无权访问')
# users = UserInfo.objects.all()
# return render(request, 'userselect.html', {'users': users})
# else:
# return redirect('/login/')
# permission_code=request.permission_code #中间件给request.permission_code,基于此,实现对力度到按钮级别
users = UserInfo.objects.all()
return render(request, 'userselect.html', {'users': users,'permission_code':permission_code})

  

  前端代码

  

<div class="container">
<div class="row">
<div class="col-md-offset-3 col-md-5">
{% if 'add' in permission_code %}
<span>新增</span>
{% endif %}
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>序号</th>
<th>用户名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ user.name }}</td>
<td>
{% if 'edit' in permission_code %}
<span>编辑</span>
{% endif %}
{% if 'delete' in permission_code %}
<span>删除</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>

  

  最终效果如下:

  登录名为吴华:

  

  登录名为左国梁:

我就问你牛不牛逼!

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  基于类的封装,继承实现权限封装。很有逼格的东西

  做法:将判辑函数,封装带类中。将对象传给前端。

  优点:代码可以重用。(继承),在不同的页面中,传不同的对象即可。

  假设有这种场景,页面是以上面的html代码写的,每个页面都是如此。看起来没有什么问题。如果code 变动了,那么每个前端的代码都需要改动,这是不应该。

 <td>
{% if 'edit' in permission_code %}
<span>编辑</span>
{% endif %}
{% if 'delete' in permission_code %}
<span>删除</span>
{% endif %}
</td>

{% if 'edit' in permission_code %}  这段代码太死了。或者说有更好的方法,运用类。

在rbac文件夹下,新建一个permission文件夹,建一个base.py,定义一个BasePermissio类。

class BasePermission(object):
def __init__(self,codes):
self.codes=codes def select(self):
if 'select' in self.codes:
return True
def delete(self):
if 'delete' in self.codes:
return True
def edit(self):
if 'edit' in self.codes:
return True
def add(self):
if 'add' in self.codes:
return True

  在views.py文件视图函数中,导入自定义类,进行以下修改。

from django.shortcuts import render,HttpResponse,redirect
import re
from rbac.models import *
from rbac.service.init_permission import init_permission
from rbac.permission.base import BasePermission class OrderPermission(BasePermission):
def report(self):
if 'report' in self.codes:
return True def userselect(request):
'''
根据有无权限,
显示所有的用户信息
:param request:
:return:
'''
# permission_code=request.permission_code
permission_obj=BasePermission(request.permission_code)
users = UserInfo.objects.all()
# return render(request, 'userselect.html', {'users': users,'permission_code':permission_code})
return render(request, 'userselect.html', {'users': users,'permission_obj':permission_obj}) def orderselect(request):
# perminssion_code=request.permission_code
permission_obj = BasePermission(request.permission_code)
pass

  注释掉的之前的代码。通过对照,可以看出,之前我们是将拿到的code列表直接传给前端。后面,我们是把类实例化后的对象传给前端,前端拿到这个对象,可以调用类的方法,进行判断。实质性的逻辑是写在类里面的。

  每个前端都接收一个对象,这个对象可以使BasePermission,也可以是继承派生而来的。可以使用父类的,也可以添加自己的。OrderPermission就是这种情况,有属于自己的'report'权限。

  前端代码

<div class="container">
<div class="row">
<div class="col-md-offset-3 col-md-5">
{% if 'add' in permission_code %}
<span>新增</span>
{% endif %}
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>序号</th>
<th>用户名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ user.name }}</td>
<td>
{# {% if 'edit' in permission_code %}#}
{% if permission_obj.codes.edit %}
<span>编辑</span>
{% endif %}
{# {% if 'delete' in permission_code %}#}
{% if permission_obj.codes.delete %}
<span>删除</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  动态生成菜单

  方法1:模板+js,模板继承

    问题:菜单展开和收缩问题:效果会滞后  。

  在templates加入以下模板。

  layout.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
margin: ;
}
.pg-header{
height: 48px;
background-color: chocolate;
}
</style>
</head>
<body>
<div class="pg-header">表头</div>
<div>
<div style="width: 20%;float: left;background-color: cadetblue">
<ul>
<li><a id="m1" href="/menu1/">菜单一</a></li>
<li><a id="m2" href="/menu2/">菜单二</a></li>
<li><a id='m3' href="/menu3/">菜单三</a></li>
</ul> </div>
<div style="width: 80%;float: left">
{% block body %} {% endblock %} </div>
</div>
{% block js %}{% endblock %} </body>
</html>

  menu1

{% extends 'layout.html' %}

{% block body %}
<h1>菜单一内容</h1>
{% endblock %} {% block js %}
<script>
document.getElementById('m1').style.color = 'red';
</script>
{% endblock %}

  menu2

{% extends 'layout.html' %}

{% block body %}
<h1>菜二内容</h1>
{% endblock %} {% block js %}
<script>
document.getElementById('m2').style.color = 'red';
</script>
{% endblock %}

  menu3

{% extends 'layout.html' %}

{% block body %}
<h1>菜单三内容</h1>
{% endblock %} {% block js %}
<script>
document.getElementById('m3').style.color = 'red';
</script>
{% endblock %}

  感受:模板继承,就是生成新页面,模板的东西一个不少,在模板的基础上丰富的很多新的东西。 其实就是一个新的html页面。

  当然,url路由也要相应的添加。

  方法2:

  新添加一个新的表---菜单表,是比权限组更高一级的表格。

  权限 新添加一个字段,自关联。select/权限作为父级,add/ delete/ edit/ 是它的儿子。

from django.db import models

# Create your models here.
class Menu(models.Model):
name=models.CharField(max_length=) class UserInfo(models.Model):
name=models.CharField(max_length=,verbose_name='用户名')
pwd=models.CharField(max_length=,verbose_name='密码')
email=models.CharField(max_length=,verbose_name='邮箱')
roles=models.ManyToManyField(to='Role')
def __str__(self):
return self.name class Role(models.Model):
name=models.CharField(max_length=,verbose_name='角色名')
permissions=models.ManyToManyField(to='Permission',blank=True)
def __str__(self):
return self.name class PermissionGroup(models.Model):
name=models.CharField(max_length=)
menu=models.ForeignKey(to='Menu',default=)
def __str__(self):
return self.name class Permission(models.Model):
name=models.CharField(max_length=,verbose_name='权限名')
url=models.CharField(max_length=,verbose_name='网址',default=None)
code=models.CharField(max_length=,default='select')
permissiongroup=models.ForeignKey(to=PermissionGroup,default=)
parent=models.ForeignKey(verbose_name='组内可以作为菜单的权限',to='Permission',null=True)
def __str__(self):
return self.name

  init_permission 随之改动,将需要的信息放在session的MENU_SESSION_KEY中。

  

from django.conf import settings
from pprint import pprint
def init_permission(user,request):
# permission_list = user.roles.filter(permissions__name__isnull=False).values('permissions__name',
# 'permissions__code',
# 'permissions__permissiongroup__id',
# 'permissions__url').distinct() permission_list = user.roles.filter(permissions__name__isnull=False).values('permissions__id',#权限id
'permissions__name',#权限名称
'permissions__code',#权限代号
'permissions__url',#权限url
'permissions__parent__id',#
'permissions__permissiongroup__id',#权限所在组的id
'permissions__permissiongroup__menu__id',#权限所在组所在菜单id
'permissions__permissiongroup__menu__name',#权限所在组所在菜单名称
).distinct()
# 获取想要的数据,放入session,专门用于生成菜单
menu_list=[]
for item in permission_list:
temp={
'id':item['permissions__id'],
'name':item['permissions__name'],
'code':item['permissions__code'],
'url':item['permissions__url'],
'pidi':item['permissions__parent__id'],
'menu_id':item['permissions__permissiongroup__menu__id'],
'menu_name':item['permissions__permissiongroup__menu__name'],
}
menu_list.append(temp)
request.session[settings.MENU_SESSION_KEY]=menu_list
pprint(menu_list)
# url_list = []
# for item in permission_list:
# url_list.append(item.get('permissions__url'))
permission_dict={}
for item in permission_list:
id=item.get('permissions__permissiongroup__id')
if id not in permission_dict:
permission_dict[id]={}
permission_dict[id]['url']=[item.get('permissions__url')]
permission_dict[id]['code']=[item.get('permissions__code')]
else:
permission_dict[id]['url'].append(item.get('permissions__url'))
permission_dict[id]['code'].append(item.get('permissions__code'))
# pprint(permission_dict) request.session[settings.PERMISSION_SESSION_KEY] = permission_dict

  更新数据库

  

  输出:

  

[{'code': 'add',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '添加订单',
'pidi': ,
'url': '/order/add/'},
{'code': 'edit',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '编辑订单',
'pidi': ,
'url': '/order/edit/(\\d+)'},
{'code': 'delete',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '删除订单',
'pidi': ,
'url': '/order/delete/(\\d+)'},
{'code': 'select',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '查询订单',
'pidi': None,
'url': '/order/select/'},
{'code': 'add',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '添加用户',
'pidi': ,
'url': '/user/add/'},
{'code': 'delete',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '删除用户',
'pidi': ,
'url': '/user/delete/(\\d+)'},
{'code': 'edit',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '编辑用户',
'pidi': ,
'url': '/user/edit/(\\d+)'},
{'code': 'select',
'id': ,
'menu_id': ,
'menu_name': '用户管理',
'name': '查询用户',
'pidi': None,
'url': '/user/select/'}]

 

在视图函数中,读取MENU_SESSION_KEY。转变两次样式,到最终需要的样式。

def userselect(request):
'''
根据有无权限,
显示所有的用户信息
:param request:
:return:
'''
permission_obj=BasePermission(request.permission_code)
users = UserInfo.objects.all() menu_list=request.session[settings.MENU_SESSION_KEY]
"""
menu_dict = {
: {'id': , 'title': '用户列表', 'pid': None, 'url': '/users/', 'menu_id': , 'menu_title': '用户管理', "active": True},
: {'id': , 'title': '订单列表', 'pid': None, 'url': '/orders/', 'menu_id': , 'menu_title': '订单管理',"active": False},
: {'id': , 'title': '角色列表', 'pid': None, 'url': '/roles/', 'menu_id': , 'menu_title': '用户管理',"active": False},
: {'id': , 'title': '送货列表', 'pid': None, 'url': '/deliver/', 'menu_id': , 'menu_title': '订单管理',"active": False},
}
"""
menu_dict={}
for item in menu_list:
pid=item['pid']
if not pid:
item['active']=False #!!!item在这里改动,列表也会随之改动
menu_dict[item[id]]=item
for item in menu_list:
pid=item['pid']
url = "^%s$" % item['url']
if re.match(url,request.path_info):
if pid:
menu_dict[pid]['active']=True
else:
item['active']=True """
menu_dict = {
: {
'title': '用户管理',
'active': True,
'children': [
{'title': '用户列表', 'url': '/users/', 'active': True},
{'title': '订单列表', 'url': '/roles/', 'active': False },
]
},
: {
'title': '订单管理',
'active': False,
'children': [
{'title': '订单列表', 'url': '/orders/', 'active': False},
{'title': '送货列表', 'url': '/deliver/', 'active': False },
]
},
}
"""
result={}
for item in menu_dict:
menu_id=item['menu_id']
if menu_id in result:
temp={'name':item['name'],'url':item['url'],'active':item['active']}
result[menu_id]['children'].append(temp)
if item['active']:
result[menu_id]['active']=True
else:
result[menu_id]={
'name':item['menu_name'],
'active':item['active'],
'children':[
{'name':item['name'],'url':item['url'],'active':item['active']}
]
}
return render(request, 'userselect.html', {'users': users,'permission_obj':permission_obj})

day02-菜单处理的更多相关文章

  1. Day02:我的Python学习之路

    1.初识模块 Python的强大之处在于他有非常丰富和强大的标准库和第三方库,现在简单的学习2个常见的标准库——sys和os. (1)系统的标准库sys # Author:GCL # 系统的标准库sy ...

  2. day02 html body中的标签

    day02 html   一.body中的标签     a标签: <!DOCTYPE html> <html lang="en"> <head> ...

  3. ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单

    前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...

  4. Electron使用与学习--(基本使用与菜单操作)

    对于electron是个新手,下面纯属个人理解.如有错误,欢迎指出.   一.安装 如果你本地按照github上的 # Install the `electron` command globally ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(74)-微信公众平台开发-自定义菜单

    系列目录 引言 1.如果不借用Senparc.Weixin SDK自定义菜单,编码起来,工作量是非常之大 2.但是借助SDK似乎一切都是简单得不要不要的 3.自定义菜单无需要建立数据库表 4.自定义菜 ...

  6. Android菜单项内容大全

    一.介绍: 菜单是许多应用中常见的用户界面组件. Android3.0版本以前,Android设备会提供一个专用"菜单"按钮呈现常用的一些用户操作, Android3.0版本以后, ...

  7. 张高兴的 UWP 开发笔记:汉堡菜单进阶

    不同于Windows 8应用,Windows 10引入了"汉堡菜单"这一导航模式.说具体点,就拿官方的天气应用来说,左上角三条横杠的图标外加一个SplitView控件组成的这一导航 ...

  8. ionic第二坑——ionic 上拉菜单(ActionSheet)安卓样式坑

    闲话不说,先上图: 这是IOS上的显示效果,代码如下: HTML部分: <body ng-app="starter" ng-controller="actionsh ...

  9. Xamarin.Android之ActionBar与菜单

    一.选项卡 如今很多应用都会使用碎片以便在同一个活动中能够显示多个不同的视图.在Android 3.0 以上的版本中,我们已经可以使用ActionBar提供的Tab来实现这种效果,而不需要我们自己去实 ...

  10. 基于 SailingEase WinForm Framework 开发客户端程序(3:实现菜单/工具栏按钮的解耦及状态控制)

    本系列文章将详细阐述客户端应用程序的设计理念,实现方法. 本系列文章以  SailingEase WinForm Framework 为基础进行设计并实现,但其中的设计理念及方法,亦适用于任何类型的客 ...

随机推荐

  1. 洛谷 P3183 [HAOI2016]食物链

    题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3.... ...

  2. codevs 1487 大批整数排序(水题日常)

     时间限制: 3 s  空间限制: 16000 KB  题目等级 : 黄金 Gold 题目描述 Description !!!CodeVS开发者有话说: codevs自从换了评测机,新评测机的内存计算 ...

  3. Openjudge 2.5 6264:走出迷宫

    总时间限制:  1000ms 内存限制:  65536kB 描述 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单. 假设你已经得到了一个n* ...

  4. 在SQL SERVER 2005中还原数据库时出现错误:system.data.sqlclient.sqlerror 媒体集有 2 个媒体簇 但只提供了 1 个。必须提供所有成员。 (microsoft.sqlserver.smo)

    问题:在SQL SERVER 2005中还原数据库时出现错误:system.data.sqlclient.sqlerror 媒体集有 2 个媒体簇 但只提供了 1 个.必须提供所有成员. (micro ...

  5. SAP云平台,区块链,超级账本和智能合约

    前一篇文章<Hyperledger Fabric on SAP Cloud Platform>,我的同事Aviva已经给大家介绍了基于区块链技术的超级账本(Hyperledger)的一些概 ...

  6. 使用JDK自带的jmap和jhat监控处于运行状态的Java进程

    对于处于运行状态中的Java进程,JDK自带了很多工具,允许Java开发人员监控运行进程中的各种状态,比如该进程内部创建了多少个对象实例,消耗了多少内存,等等. 本文基于JDK1.8而写成. 我下面写 ...

  7. Codeforces Round #316 (Div. 2) B Simple Game 贪心

    贪心,如果m分成的两个区间长度不相等,那么选长的那个区间最接近m的位置,否则选m-1位置,特判一下n等于1的情况 #include<bits/stdc++.h> using namespa ...

  8. webuploader项目中多文件上传实例

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  9. hibernate3缓存(hibernate)

    一级缓存:当应用程序调用Session 的save() .update() .savaeOrUpdate() .get() 或load() ,以及调用查询接口的list() .iterate() 或f ...

  10. ios软件设计中注意点

    1.取消系统自带渲染效果 2.取消屏幕旋转 3.项目中搜索丢失文件