• crm-4权限


    1.rbac-优化login函数  

      因为login是业务逻辑 ,而rbac是个组件 ,将rbac在login的代码分离

    ###初始化权限函数分离出去 rbac/service/permission
    from untitled import settings
    
    def init_permission(request, obj):
        permission_query = obj.roles.all().filter(permissions__url__isnull=False).values(
            'permissions__title',
            'permissions__url',
            'permissions__is_menu',
            'permissions__name',
        ).distinct()
    
        permission_dict = {}
        menu_list = []
    
        for i in permission_query:
            permission_dict[i['permissions__name']] = {'url': i['permissions__url']}
            if i['permissions__is_menu']:
                menu_list.append({'title': i['permissions__title'], 'url': i['permissions__url']})
    
        # 将对象列表转换为列表 ! 并将用户权限存入session
        request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
        request.session[settings.MENU_SESSION_KEY] = menu_list
        # 此刻该用户登录成功
        request.session['is_login'] = True
    
    
    ###login函数直接使用
    class login(View):
        def get(self, request):
            return render(request, 'login.html')
    
        def post(self, request):
            name = request.POST.get('username')
            password = request.POST.get('password')
            md5 = hashlib.md5()
            md5.update(password.encode('utf-8'))
            md5_pwd = md5.hexdigest()
            print(md5_pwd, name)
            obj = models.User.objects.filter(name=name, password=md5_pwd).first()
            if not obj:
                return HttpResponse('账号密码错误')
            # 初始化用户权限
            else:
                init_permission(request, obj)
            return redirect(reverse('crm:deplist'))
    View Code

    2.业务-保留搜索条件

      问题: 在第9页修改了某条数据提交后 ,直接跳到了第1页 ,这是因为视图函数返回到了展示页面没有携带页码

      解决方法:  1.点击修改后的页面url要有上个页面的页码(前端)  2.点击提交数据跳转的页面携带当前页面的页码(view函数)

      思想: 关注request,确保每次访问的url都有页码参数 ,因为request每次请求都会变化,所以每次都要加参数

         定义simple_tag函数返回增加了page参数的url ,前端a标签调用函数获得url

           request.GET.urlencode()     是当前url上的参数

    ###/rbac/middlewares/my_define
    @register.simple_tag
    def reverse_url(request, *args, **kwargs):
        # get的参数
        params = request.GET.urlencode()
        # 跳转的url  args[0]是url别名  args[1]是url别名参数
        url = reverse(args[0], args=(args[1],))
    
        return '{}?{}'.format(url, params)
    
    ###前端html中 执行函数
                    {% if request|has_permission:'dep_edit' %}
                        <td>
                            <a href={% reverse_url request 'crm:depedit' obj.pk %}><i class="fa fa-pencil-square-o"
                                                                                      aria-hidden="true">&nbsp&nbsp&nbsp</i></a>
                            <a class="b1" del_id="{{ obj.pk }}" style="color: red"><i class=" fa fa-remove"
                                                                                      aria-hidden="true"></i></a></td>
                    {% endif %}

        修改视图函数中的redirect的值 ,直接拼接上url的参数

          url_name定义为原来reverse的无参数的url

    ##通用工具utils/reverse_url
    from django.urls import reverse
    
    
    def reverse_url(request, url_name, *args, **kwargs):
        url = reverse(url_name)
        params = request.GET.urlencode()
        return '{}?{}'.format(url, params)
    
    
    ##跳转页面修改视图函数dep.py
    def depadd(request):
    ....
                return redirect(reverse('crm:deplist'))
    ...

    3.权限二级菜单

      一级菜单为信息管理

        二级菜单为班级列表与部门列表

      一级菜单为用户管理

        二级菜单为用户列表

      思路: 如果要完成二级菜单 ,我们需要以一级菜单为主导 ,子信息包含二级菜单所有信息 ,根据这个想法我们将取出的权限信息进行分析

      1) 完成models的设计

        新增Menu表用来存储一级菜单 ,和一级菜单的其他信息(样式什么的)

    class Menu(models.Model):
        title = models.CharField('菜单名称', max_length=32)
        icon = models.CharField('样式', max_length=128)
    
        def __str__(self):
            return self.title

        修改Permission表中的is_menu的字段 ,将该字段直接删除 ,信增外键关联Menu表 ,此时所有关联Menu表的权限都是二级菜单 

    class Permisssion(models.Model):
        url = models.CharField('含正则url', max_length=128)
        title = models.CharField('中文权限标题', max_length=32, blank=True, null=True)
        name = models.CharField('url的别名', max_length=32, unique=True)
        # is_menu = models.BooleanField('是否为菜单', default=False)
        menu = models.ForeignKey('Menu', blank=True, null=True)
    
        def __str__(self):
            return self.title

        修改admin中原来的is_menu消失的字段 ,做数据迁移

      2)新增一级菜单数据  --> 并将权限关联一级菜单

        名称:信息管理   样式:fa-eercast

        名称:用户管理   样式:fa-address-book

      3)重新从权限中获取的管家数据permission_query 

        通过角色表的权限外键获取 : 权限的名字  权限的标题  权限的url  权限的外键id是否为空

        通过角色表的权限外键获取到权限表的Menu外键 : 一级菜单的标题  一级菜单的样式

    ##原来数据格式
    permission_query = obj.roles.all().filter(permissions__url__isnull=False).values(
    'permissions__name',
    'permissions__title',
    'permissions__url',
    'permissions__menu_id',
    'permissions__menu__title',
    'permissions__menu__icon',

    ).distinct() # 对列表中重复的字典进行去重


    #
    #生成菜单字典的1示例格式 :一级菜单收缩下拉框, 二级菜单作为子值负责跳转url menu_id:{ menu_title: 信息管理, menu_icon: fa-eercast, children: [ { permissions__title: '班级列表' ,url:'/crm/class/list' }, { permissions__title: '部门管理' ,url:'/crm/dep/list' } ]
    }
    from untitled import settings
    
    
    def init_permission(request, obj):
        # permission_query是该用户的所有权限 ,从角色表出发 ,根据外键的权限表打印出所有的所需要信息
        permission_query = obj.roles.all().filter(permissions__url__isnull=False).values(
            'permissions__name',
            'permissions__title',
            'permissions__url',
            'permissions__menu_id',
            'permissions__menu__title',
            'permissions__menu__icon',
    
        ).distinct()  # 对列表中重复的字典进行去重
    
        permission_dict = {}
        menu_dict = {}
    
        for i in permission_query:
            # 生成权限字典
            permission_dict[i['permissions__name']] = {'url': i['permissions__url']}
    
            # 生成一级菜单字典
            if i['permissions__menu_id'] not in menu_dict:
                menu_dict['permissions__menu_id'] = {
                    'title': i['permissions__menu__title'],
                    'icon': i['pemissions__menu__icon'],
                    'children': [
                        {'title': i['permissions__url'], 'url': i['permissions__url']}
                    ]
                }
            # 如果字典中有一级菜单的key就可以直接追加一个children了
            else:
                menu_dict['permissions__menu_id']['children'].append(
                    {'title': i['permissions__url'], 'url': i['permissions__url']})
    
        # 将对象列表转换为列表 ! 并将用户权限存入session
        request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
        request.session[settings.MENU_SESSION_KEY] = menu_dict
        # 此刻该用户登录成功
        request.session['is_login'] = True
    View Code

      4) inclusion_tag修改支持一级菜单二级菜单显示 ,并新增权重排序字典 ,和非菜单归属(需要新增weight字段与parent字段 )

    @register.inclusion_tag('menu.html')
    def menu(request):
    """拿出当前url
    给所有的一级菜单都hide隐藏
    再循环二级菜单 ,如果当前地址匹配到了二级菜单 ,给二级标签重点标记active ,并把一级菜单取出hide
    修改后的菜单字典传给前端
    """

    # 这个url是当前访问的url
    url = request.path_info
    menu_dict = request.session[settings.MENU_SESSION_KEY]
    permissions_dict = request.session[settings.PERMISSION_SESSION_KEY]

    # 非菜单权限归属重新定义url解决
    for i in permissions_dict.values():
    if re.match('^{}$'.format(i['url']), url) and i['parent']:
    # 这里将url直接替换为费权限归属的parent__url ,因为该url就是用来生成菜单的
    url = i['parent']
    break

    # 根据权重将menu_dict变为有序字典
    sort_dict = OrderedDict()
    temp_lst = sorted(menu_dict, key=lambda x: menu_dict[x]['weight'], reverse=True)
    for i in temp_lst:
    sort_dict[i] = menu_dict[i]

    for i in sort_dict.values():

    # 开始获取将全部的隐藏 ,仅将匹配到的url取消隐藏
    i['class'] = 'hide'
    for child in i['children']:
    if re.match('^{}$'.format(child['url']), url):
    child['class'] = 'active'
    i['class'] = ''
    return {'menu_dict': sort_dict.values()}
     

        

     4.面包屑功能

      1)拿到对应的数据放入权限字典

            permission_dict[i['permissions__name']] = {'url': i['permissions__url'],
                                                       'title': i['permissions__title'],
                                                       'parent': i['permissions__parent__url'],
                                                       'parent_title': i['permissions__parent__title']}

      2)inclusion_tags中定义数据结构 ,将一级菜单和非权限菜单分离 ,放入breadcrum_list列表中

    @register.inclusion_tag('breadcrumb.html')
    def breadcrum(request):
        url = request.path_info
        permission_dict = request.session[settings.PERMISSION_SESSION_KEY]
        # 导航数据
        breadcrum_list = [{'title': '首页', 'url': '/crm/dep/list/', }]
    
        for i in permission_dict.values():
    
            # 二级菜单
            if re.match('^{}$'.format(i['url']), url) and not i['parent']:
                breadcrum_list.append({'title': i['title'],
                                       'url': i['url'], })
                break
            # 非权限菜单
            if re.match('^{}$'.format(i['url']), url) and i['parent']:
                breadcrum_list.append({'title': i['parent_title'], 'url': i['parent'], })
                breadcrum_list.append({'title': i['title'], 'url': i['url'], })
                break
    
        return {'breadcrum_list': breadcrum_list}

      3)html中展示 ,如果是最后一个不用a标签  ,layout模板引用

    ####breadcrumb.html
    <ol class="breadcrumb">
    
        {% for breadcrum in breadcrum_list %}
            {% if forloop.last %}
                <li>{{ breadcrum.title }}</li>
            {% else %}
                <li><a href="{{ breadcrum.url }}">{{ breadcrum.title }}</a></li>
            {% endif %}
        {% endfor %}
    
    </ol>

    ###layout.html
    <div class="right-body">
    <div>
    {% breadcrum request %}
    </div>
    ....

      

    5.使用redis存储session

      1)搭建redis

        docker pull redis

        docker run -p 6379:6379 -v /redis:/data -d redis  --appendonly yes

        docker exec -it 容器ID redis-cli -h 192.168.1.30 -p  6379

      2)django配置

        pip install django-redis-sessions==0.5.6

        settings.py配置  

    SESSION_ENGINE = 'redis_sessions.session'
    SESSION_REDIS_HOST = '192.168.1.30'
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1            #指定存到redis的一个库中,默配置16个库
    SESSION_REDIS_PASSWORD = ''
    SESSION_REDIS_PREFIX = 'session'

      3)验证

        docker exec -it 容器ID redis-cli -h 192.168.1.30 -p  6379

        select 1       #切库 

        keys *        #看到session

        flushdb        #清空后web端退出登录

    
    
    

      

  • 相关阅读:
    (十一)Updating Documents
    (十)Modifying Your Data
    (九)Delete an Index
    (八)Index and Query a Document
    (七)Create an Index
    (六)List All Indices
    (五)Cluster Health
    (四)Exploring Your Cluster
    (三)Installation
    (二)Basic Concepts 基本概念
  • 原文地址:https://www.cnblogs.com/quguanwen/p/11459420.html
Copyright © 2020-2023  润新知