Django之菜单排序、路径导航、访问子菜单时二级菜单默认展开、权限精确到按钮级别

一.一级菜单排序

实现思路:
在一级菜单表中加一个权重字段,根据这个字段来排序。

 weight = models.IntegerField(default=1)  # 权重 左侧菜单栏根据这个来排序

那么获取用户权限时就要获取一下这个字段:

def permission(request,user_obj):
    # 登录认证
    request.session['is_login'] = True

    # 用户权限认证
    permissions_list = user_obj.roles.values(
        'Permissions__id',
        'Permissions__url',
        'Permissions__title',
        'Permissions__menus__weight',   # 权重
        'Permissions__menus__id',
        'Permissions__menus__title',
        'Permissions__menus__icon',

    ).distinct()
    request.session[settings.PERMISSIONS_KEY] = list(permissions_list)
	
	# 左侧菜单栏权限
    menu_dict = {}
    for menu in permissions_list:
        if menu.get('Permissions__menus__id'):
            if menu.get('Permissions__menus__id') in menu_dict:
                menu_dict[menu.get('Permissions__menus__id')]['children'].append(
                    {'url': menu.get('Permissions__url'),
                     'title': menu.get('Permissions__title'),
                     }
                )
            else:
                menu_dict[menu.get('Permissions__menus__id')] = {
                    'title':menu.get('Permissions__menus__title'),   # 一级菜单
                    'icon':menu.get('Permissions__menus__icon'),     # 一级菜单icon 图标
                    'weight': menu.get('Permissions__menus__weight'), # 权重 用来排序用
                    'children':[
                        {'url':menu.get('Permissions__url'),
                         'title':menu.get('Permissions__title'),
                         }  # 二级菜单
                    ]
                }
    request.session[settings.MENU_KEY] = menu_dict

自定义标签中:

from django import template
from django.conf import settings
from collections import OrderedDict

register = template.Library()

@register.inclusion_tag('menu.html')
def menu(request):
    menu_dict = request.session.get(settings.MENU_KEY)
    current_path = request.path
    order_dict = OrderedDict()  # 有序字典对象
    keys = sorted(menu_dict,key=lambda x:menu_dict[x]['weight'],reverse=True)  #  1 2
    for sorts in keys:
        order_dict[sorts] = menu_dict[sorts]

数据库中财务管理的值比销售管理的值大:
在这里插入图片描述
效果:
在这里插入图片描述

二.保留二级菜单默认展开效果

自定义标签中加下面这段代码:
首先给所有的二级菜单加一个hidden效果全部收起来,如果访问的url匹配到二级菜单的路径就让class值等于空,展开效果。

for key,values in order_dict.items():
    values['class'] = 'hidden'
    for i in values['children']:
        if re.match(i['url'],current_path):
            values['class'] = ''

menu.html文件中:

<div class="multi-menu">
    {% for menu_k,menu_v in menu_dict.items %}
        <div class="item">
        <div class="title"> {{ menu_v.title }}</div>
            <div class="body {{ menu_v.class }}">
                {% for ermenu in menu_v.children %}
                    <a href="{{ ermenu.url }}">{{ ermenu.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>

三.二级菜单的点击效果

需求:点击的二级菜单想要有选中的效果。
如果访问的url匹配到二级菜单的路径就给所有的二级菜单加一个值class=active。
代码:

for key,values in order_dict.items():
    values['class'] = 'hidden'
    for i in values['children']:
        if re.match(i['url'],current_path):
            values['class'] = ''
            i['class'] = 'active'

menu.html:

<div class="multi-menu">
    {% for menu_k,menu_v in menu_dict.items %}
        <div class="item">
        <div class="title"> {{ menu_v.title }}</div>
            <div class="body {{ menu_v.class }}">
                {% for ermenu in menu_v.children %}
                    <a href="{{ ermenu.url }}" class="{{ ermenu.class }}">{{ ermenu.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>

效果:
在这里插入图片描述

四.二级菜单权限访问时二级菜单默认展开

出现的问题:
点击其他功能项时,左侧菜单栏会收起。
解决思路:
在权限表中加一个字段外键到他自己这张表,如果是二级菜单那么值就是None,如果不是二级菜单就记录当前这个路径属于哪个二级菜单。
在这里插入图片描述
首先先要把parent_id和二级菜单的他自己的id写到session中,方便后续用:

def permission(request,user_obj):
    # 登录认证
    request.session['is_login'] = True

    # 权限认证
    permissions_list = user_obj.roles.values(
        'Permissions__id',
        'Permissions__url',
        'Permissions__title',
        'Permissions__parent_id',       # 用来记录二级菜单的子菜单
        'Permissions__menus__weight',   # 权重
        'Permissions__menus__id',
        'Permissions__menus__title',
        'Permissions__menus__icon',

    ).distinct()
    request.session[settings.PERMISSIONS_KEY] = list(permissions_list)

    menu_dict = {}
    for menu in permissions_list:
        if menu.get('Permissions__menus__id'):
            if menu.get('Permissions__menus__id') in menu_dict:
                menu_dict[menu.get('Permissions__menus__id')]['children'].append(
                    {'url': menu.get('Permissions__url'),
                     'title': menu.get('Permissions__title'),
                     'id': menu.get('Permissions__id'),   # 当前二级菜单的id
                     }
                )
            else:
                menu_dict[menu.get('Permissions__menus__id')] = {
                    'title':menu.get('Permissions__menus__title'),   # 一级菜单
                    'icon':menu.get('Permissions__menus__icon'),     # 一级菜单icon 图标
                    'weight': menu.get('Permissions__menus__weight'),
                    'children':[
                        {'url':menu.get('Permissions__url'),
                         'title':menu.get('Permissions__title'),
                         'id': menu.get('Permissions__id'),     # 当前二级菜单的id
                         }  # 二级菜单
                    ]
                }
    request.session[settings.MENU_KEY] = menu_dict

怎么样获取到二级菜单中的parent_id呢,之前是在中间件做的路径权限认证,可以在这里把获取parent_id进行记录。

 # 获取二级菜单的子菜单
 pid =permission_path.get('Permissions__parent_id')
 if pid:
     # 获取到了就记录这个子菜单的id
     request.current_id = pid
 else:
     # 如果获取不到子菜单的id 那么current_id就等于当前二级菜单的id
     request.current_id = permission_path.get('Permissions__id')

 return None

自定义标签中稍作改动:

for key,values in order_dict.items():
    values['class'] = 'hidden'
    for i in values['children']:
    	# 不再用正则匹配了,这里获取到的是二级菜单的子菜单那么点击的时候也会有下面两个效
    	# 果,如果获取不到parent_id那么就是当前二级菜单的id,也会有下面两个效果,可谓是两全其美
        if request.current_id == i.get('id'):
            values['class'] = ''
            i['class'] = 'active'

五.路径导航-面包屑

需求:
想做下面这种带有路径导航的功能
在这里插入图片描述
实现思路:
先往request里面放一个列表,后续根据点击的路劲往里放不同的url。

request.bread_crumbs = [    # 面包屑
    {'url':reverse('app05:index'),'title':'首页'},
]

第一种实现方法:

# 获取二级菜单的子菜单
pid =permission_path.get('Permissions__parent_id')

# 拿到pid之后,去权限表中查如果id等于parent_id就代表这个路径是二级菜单下的子菜单,后面就获取这个id的url和title
ret = models.Permission.objects.filter(pk=pid).first()
if pid:
    # 获取到了就记录这个子菜单的id
    request.current_id = pid

    # 二级菜单
    request.bread_crumbs.append({
        'url': ret.url,
        'title': ret.title,
    })

    # 二级菜单下的子菜单
    request.bread_crumbs.append({
        'url': None,
        'title': permission_path.get('Permissions__title'),
    })
else:
	# 这里如果获取不到parent_id就代表是二级菜单,往里面加二级菜单的url和title
    request.bread_crumbs.append({
        'url':None,
        'title':permission_path.get('Permissions__title'),
    })
    # 如果获取不到子菜单的id 那么current_id就等于当前二级菜单的id
    request.current_id = permission_path.get('Permissions__id')

第二种实现方法:
第一种实现方法要操作数据库,效率有点低,这里实现另外一种方法:
实现思路:
将权限表中的每一条数据id作为键,剩下的url title等作为值,组成一个新字典,然后根据
获取到的parent_id去查这个新字典的值。
代码:

permissions_list = user_obj.roles.values(
    'Permissions__id',
    'Permissions__url',
    'Permissions__title',
    'Permissions__parent_id',       # 用来记录二级菜单的子菜单
    'Permissions__menus__weight',   # 权重
    'Permissions__menus__id',
    'Permissions__menus__title',
    'Permissions__menus__icon',

).distinct()

# 将permissions_list重新组数据,之前是list类型
# 现在数据格式是:{1:{url:xx,title:xx}}
# 通过permissions_dict[parent_id][url] 来获取子菜单的url和title
permissions_dict = {}
for permissions in permissions_list:
    permissions_dict[permissions.get('Permissions__id')] = permissions

request.session[settings.PERMISSIONS_KEY] = permissions_dict

最终的方式:

# 获取二级菜单的子菜单
pid =permission_path.get('Permissions__parent_id')
ret = models.Permission.objects.filter(pk=pid).first()
if pid:
    # 获取到了就记录这个子菜单的id
    request.current_id = pid

    # 二级菜单
    # 第一种方式:
    # request.bread_crumbs.append({
    #     'url': ret.url,
    #     'title': ret.title,
    # })

    # 第二种方式:
    request.bread_crumbs.append({
        'url': permission_path_dict[str(pid)]['Permissions__url'],
        'title': permission_path_dict[str(pid)]['Permissions__title'],
    })

    # 二级菜单下的子菜单
    request.bread_crumbs.append({
        'url': None,
        'title': permission_path.get('Permissions__title'),
    })
else:
    request.bread_crumbs.append({
        'url':None,
        'title':permission_path.get('Permissions__title'),
    })
    # 如果获取不到子菜单的id 那么current_id就等于当前二级菜单的id
    request.current_id = permission_path.get('Permissions__id')

html中:

 {% for crumb in request.bread_crumbs %}
      {% if crumb.url %}
      <li><a href="{{ crumb.url }}">{{ crumb.title }}</a></li>
          {% else %}
          <li class="active">{{ crumb.title }}</li>
      {% endif %}
  {% endfor %}

六.权限精确到按钮级别

需求:
没有权限的按钮不显示出来。
实现思路:
在权限表中加一个字段url_name用来标识路径别名,将url_name的值取出来放到session中,自定义一个过滤器,如果urls.py中设置的别名在session中就显示,不在则不显示。
代码实现:
数据库中加一个字段:

url_name = models.CharField(max_length=32,unique=True)

获取url_name别名并放到session中:

url_name_list = []
url_name_list.append(menu.get('Permissions__url_name'))
request.session['url_name'] = url_name_list   # 别名

自定义过滤器:

@register.filter
def url_name_filer(name,request):
    # 路径是否在url_name中
    if name in request.session['url_name']:
        return True
    else:
        return False

前端HTML根据返回的结果做判断:

{% extends 'layout.html' %}
{% load mytag %}    # 加载一下自定义标签
{% block content %}
    {% if 'customer_add'|url_name_filer:request %}
        <h1><a href="{% url 'app05:customer_add' %}">添加客户记录</a></h1>
    {% endif %}
    <form action="" method="post">
        {% csrf_token %}
        <table class="table table-bordered table-hover">
            <thead>
            <tr>
                <th>序号</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>邮箱</th>
                <th>公司</th>
                {% if 'customer_del'|url_name_filer:request or 'customer_edit'|url_name_filer:request %}
                <th>操作</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for customer in customer_obj %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ customer.name }}</td>
                    <td>{{ customer.age }}</td>
                    <td>{{ customer.email }}</td>
                    <td>{{ customer.company }}</td>
                 {% if 'customer_del'|url_name_filer:request or 'customer_edit'|url_name_filer:request %}
                        <td>
                            {% if 'customer_edit'|url_name_filer:request %}
                            <a href="{% url 'app05:customer_edit' customer.id %}"><i class="fa fa-edit"></i></a>
                            {% endif %}
                            {% if 'customer_del'|url_name_filer:request %}
                            <a href="{% url 'app05:customer_del' customer.id %}"><i class="fa fa-remove"></i></a>
                            {% endif %}
                        </td>
                {% endif %}
                </tr>
            {% endfor %}
            </tbody>
        </table>
        <button class="btn btn-success">提交</button>
    </form>
{% endblock %}

效果:
什么权限也没有
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39253370/article/details/106383432