解决力度到按钮的级别

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

  方案:添加一个新表,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. ActiveMQ消息丢失怎么解决?

    在消息发送过程中消息丢失的话该怎么解决(包括网络原因): 解决思路: 可以把消息唯一ID,存到表里面,当消息接受端可以获取到这个ID,就给服务端一个回复IF,消息发送出去,没有回复,THEN一直循环发 ...

  2. 原创 :xftp SFTP子系统申请已拒绝 请确保SSH链接的SFTP子系统设置有效

    在出现这个错误时候 如果你的远程连接没有问题 那么就执行下面的命令 service sshd restart 搞定!

  3. UVA 10003 cuting sticks 切木棍 (区间dp)

    区间dp,切割dp[i][j]的花费和切法无关(无后效性) dp[i][j]表示区间i,j的花费,于是只要枚举切割方法就行了,区间就划分成更小的区间了.O(n^3) 四边形不等式尚待学习 #inclu ...

  4. CF 1119F Niyaz and Small Degrees

    打VP的时候由于CXR和XRY切题太快了导致我只能去写后面的题了 然而VP的时候大概还有一小时时想出了\(O(n^2\log n)\)的暴力,然后过了二十分钟才想到删点的优化 结果细节很多当然是写不出 ...

  5. Maven归纳

      一.常用功能 1.Maven的中央仓库 https://mvnrepository.com/ 2.添加jar包依赖 1.首先点击pom.xml,然后点击弹出页面中的Dependencies选项,接 ...

  6. CAD交互绘制批注(网页版)

    js中实现代码说明: 动态拖放时的绘制事件: function DynWorldDrawComment( pCustomEntity, pWorldDraw, curPt) { // 得到绘制参数. ...

  7. shell脚本,创建50个文件,删除50个文件。

    [root@localhost ~]# cat create50.sh #!/bin/bash #创建50个文件 ` do touch student$i done echo "创建50个文 ...

  8. (64)zabbix正则表达式应用

    概述 在前面的<zabbix low-level discovery>一文中有filter一项,用于从结果中筛选出你想要的结果,比如我们在filter中填入^ext|^reiserfs则表 ...

  9. Python操作12306抢票脚本

    有一段时间没有使用Python了,前几天经朋友提起一篇关于用Python实现抢火车票的文章,百度了实现抢火车票的技术细节,网上却有不少资料,也不是新鲜的东西.在了解了一些技术手段,阅读了一些大神的博文 ...

  10. python数据类型、字符编码、文件处理-练习

    练习-字符串 # 写代码,有如下变量,请按照要求实现每个功能 (共6分,每小题各0.5分) name = " aleX" # ) 移除 name 变量对应的值两边的空格,并输出处理 ...