解决力度到按钮的级别

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

  方案:添加一个新表,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. iOS面试题 第一天

    今天上午,下午分别面试了两家公司.上午是一家互联网公司,气氛还比较好,是我比较喜欢的.技术这块是直接机试,主要是给了些BUG让我修复,整个过程还算顺利.下午去了一家大型的证券公司.整理技术问题如下: ...

  2. 转过来的Xpath语法

    XPath 是XML的查询语言,和SQL的角色很类似.以下面XML为例,介绍XPath 的语法.   <?xml version="1.0" encoding="I ...

  3. 当然,perl等脚本服务器是一般默认安装了,你入侵了一台主机,总不能先装配 Java 环境然后再开干吧?

    转自:https://www.zhihu.com/question/20173592 当然,perl等脚本服务器是一般默认安装了,你入侵了一台主机,总不能先装配 Java 环境然后再开干吧?

  4. C# 文件操作的工具类

    using System.IO; namespace 文件操作类 { public class FileHelper { /// <summary> /// 判断文件是否存在 /// &l ...

  5. Linux下MongoDB的安装、配置、启动

    下载 MongoDB下载地址为 https://www.mongodb.org/downloads 安装 将文件放到/usr/local/目录下并解压 tar -zxvf mongodb-linux- ...

  6. C# 使用Epplus导出Excel [2]:导出动态列数据

    C# 使用Epplus导出Excel [1]:导出固定列数据 C# 使用Epplus导出Excel [2]:导出动态列数据 C# 使用Epplus导出Excel [3]:合并列连续相同数据 C# 使用 ...

  7. 如何让升级时AppleHDA不再折腾

    ---前提--- 1. 你得用 Clover 引导 (......) 2. 开启 kernelcache (开了也能 inject kext,还能patch kext,速度又快,为啥不开) 3. 你的 ...

  8. vue父组件获取子组件页面的数组 以城市三级联动为例

    父组件调用子组件 <Cselect ref="registerAddress"></Cselect> import Cselect from '../../ ...

  9. HDU - 4802 - GPA (水题)

    题意: 计算GPA,输入一个数字和一个字符串,用 数字×字符串对应的数值 思路: 用map对应数值,要注意的是字符串为P或者N的时候,不计入结果 代码: #include<iostream> ...

  10. MySQL的索引知识

    一.什么是索引. 索引是用来加速查询的技术的选择之一,在通常情况下,造成查询速度差异 的因素就是索引是否使用得当.当我们没有对数据表的某一字段段或者多个 字段添加索引时,实际上执行的全表扫描操作,效率 ...