zoukankan      html  css  js  c++  java
  • day02-菜单处理

    解决力度到按钮的级别

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

      方案:添加一个新表,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=32,verbose_name='用户名')
        pwd=models.CharField(max_length=32,verbose_name='密码')
        email=models.CharField(max_length=32,verbose_name='邮箱')
        roles=models.ManyToManyField(to='Role')
        def __str__(self):
            return self.name
    
    class Role(models.Model):
        name=models.CharField(max_length=32,verbose_name='角色名')
        permissions=models.ManyToManyField(to='Permission',blank=True)
        def __str__(self):
            return self.name
    
    class PermissionGroup(models.Model):
        name=models.CharField(max_length=32)
        def __str__(self):
            return self.name
    
    class Permission(models.Model):
        name=models.CharField(max_length=32,verbose_name='权限名')
        url=models.CharField(max_length=200,verbose_name='网址',default=None)
        code=models.CharField(max_length=32,default='select')
        permissiongroup=models.ForeignKey(to=PermissionGroup,default=1)
        def __str__(self):
            return self.name

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

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

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

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

    {1: {'code': ['select'], 'url': ['/user/select/']},
     2: {'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):
            #1 获取白名单
            permission_valid_url=settings.PERMISSION_VALID_URL
            for url in permission_valid_url:
                if re.match(url,request.path_info):
                    return None
    
            #2 获取权限
            permission_dict = request.session.get(settings.PERMISSION_SESSION_KEY)
    
            if not permission_dict:
                return HttpResponse('未能读取到该用户的信息')
            #3 对用户请求的url进行匹配
            '''
            {2: {'url': ['/order/select/'], 'code': ['select']}, 1: {'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: 0;
            }
            .pg-header{
                height: 48px;
                background-color: chocolate;
            }
        </style>
    </head>
    <body>
        <div class="pg-header">表头</div>
        <div>
            <div style=" 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=" 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=32)
    
    class UserInfo(models.Model):
        name=models.CharField(max_length=32,verbose_name='用户名')
        pwd=models.CharField(max_length=32,verbose_name='密码')
        email=models.CharField(max_length=32,verbose_name='邮箱')
        roles=models.ManyToManyField(to='Role')
        def __str__(self):
            return self.name
    
    class Role(models.Model):
        name=models.CharField(max_length=32,verbose_name='角色名')
        permissions=models.ManyToManyField(to='Permission',blank=True)
        def __str__(self):
            return self.name
    
    class PermissionGroup(models.Model):
        name=models.CharField(max_length=32)
        menu=models.ForeignKey(to='Menu',default=1)
        def __str__(self):
            return self.name
    
    class Permission(models.Model):
        name=models.CharField(max_length=32,verbose_name='权限名')
        url=models.CharField(max_length=200,verbose_name='网址',default=None)
        code=models.CharField(max_length=32,default='select')
        permissiongroup=models.ForeignKey(to=PermissionGroup,default=1)
        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': 2,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '添加订单',
      'pidi': 2,
      'url': '/order/add/'},
     {'code': 'edit',
      'id': 3,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '编辑订单',
      'pidi': 2,
      'url': '/order/edit/(\d+)'},
     {'code': 'delete',
      'id': 4,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '删除订单',
      'pidi': 2,
      'url': '/order/delete/(\d+)'},
     {'code': 'select',
      'id': 5,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '查询订单',
      'pidi': None,
      'url': '/order/select/'},
     {'code': 'add',
      'id': 6,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '添加用户',
      'pidi': 9,
      'url': '/user/add/'},
     {'code': 'delete',
      'id': 7,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '删除用户',
      'pidi': 9,
      'url': '/user/delete/(\d+)'},
     {'code': 'edit',
      'id': 8,
      'menu_id': 1,
      'menu_name': '用户管理',
      'name': '编辑用户',
      'pidi': 9,
      'url': '/user/edit/(\d+)'},
     {'code': 'select',
      'id': 9,
      'menu_id': 1,
      '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 = {
               1: {'id': 1, 'title': '用户列表', 'pid': None, 'url': '/users/', 'menu_id': 1, 'menu_title': '用户管理', "active": True},
               5: {'id': 5, 'title': '订单列表', 'pid': None, 'url': '/orders/', 'menu_id': 2, 'menu_title': '订单管理',"active": False},
               12: {'id': 12, 'title': '角色列表', 'pid': None, 'url': '/roles/', 'menu_id': 1, 'menu_title': '用户管理',"active": False},
               20: {'id': 20, 'title': '送货列表', 'pid': None, 'url': '/deliver/', 'menu_id': 2, '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 = {
              1: {
                  'title': '用户管理',
                  'active': True,
                  'children': [
                      {'title': '用户列表', 'url': '/users/', 'active': True},
                      {'title': '订单列表', 'url': '/roles/', 'active': False },
                  ]
              },
              2: {
                  '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})
  • 相关阅读:
    Sentinel Dashboard(基于1.8.1)流控规则持久化到Nacos——涉及部分Sentinel Dashboard源码改造
    测试平台MeterSphere源码入门
    Java:利用BigDecimal类巧妙处理Double类型精度丢失
    SpringBoot整合任务调度框架Quartz及持久化配置
    任务调度框架Quartz快速入门!
    Kafka超详细学习笔记【概念理解,安装配置】
    Windows环境下Zookeeper安装配置
    SpringData JPA利用Specification多条件查询
    SpringBoot事件监听机制及观察者模式/发布订阅模式
    详解Java中的IO输入输出流!
  • 原文地址:https://www.cnblogs.com/654321cc/p/8324494.html
Copyright © 2011-2022 走看看