一、非菜单权限对应的一级菜单展开

  需求:客户列表和账单列表页面中都有添加按钮,当点击添加客户(或编辑客户、删除客户)时,客户列表所属的一级菜单展开,当点击添加账单(或编辑账单、删除账单)时,账单列表所属的一级菜单展开。

1、permission表新增一个pid字段,表示非菜单权限的父级菜单权限id,permission模型类如下:

class Permission(models.Model):
    """
    权限表
    """
    url = models.CharField(verbose_name='含正则的URL', max_length=32)
    title = models.CharField(verbose_name='标题', max_length=32)
    menu = models.ForeignKey(verbose_name='标题', to="Menu", on_delete=models.CASCADE, null=True)
    name = models.CharField(verbose_name='url别名', max_length=32, default="")
    pid = models.ForeignKey("self", on_delete=models.CASCADE, null=True, verbose_name='父权限')

    def __str__(self):
        return self.title

2、修改权限列表数据结构,注入session,setsession.py中代码如下:

def initial_session(user_obj, request):
    """
    将当前登录人的所有权限url列表和
    自己构建的所有菜单权限字典和
    权限表name字段列表注入session
    :param user_obj: 当前登录用户对象
    :param request: 请求对象HttpRequest
    """
    # 查询当前登录人的所有权限列表
    ret = Role.objects.filter(user=user_obj).values('permissions__url',
                                                    'permissions__title',
                                                    'permissions__name',
                                                    'permissions__pk',
                                                    'permissions__pid',
                                            'permissions__menu__title',
                                                'permissions__menu__icon',
                                                'permissions__menu__id').distinct()
    permission_list = []
    permission_names = []
    permission_menu_dict = {}
    for item in ret:
        # 获取用户权限列表用于中间件中权限校验,改变数据结构
        permission_list.append({
            'url':item['permissions__url'],
            'id':item['permissions__pk'],
            'pid':item['permissions__pid'],
            'title':item['permissions__title']
        })
        # 获取权限表name字段用于动态显示权限按钮
        permission_names.append(item['permissions__name'])

        menu_pk = item['permissions__menu__id']
        if menu_pk:
            if menu_pk not in permission_menu_dict:
                permission_menu_dict[menu_pk] = {
                    "menu_title": item["permissions__menu__title"],
                    "menu_icon": item["permissions__menu__icon"],
                    "children": [
                        {
                            "title": item["permissions__title"],
                            "url": item["permissions__url"],
                 "pk": item["permissions__pk"]
                        }
                    ],
                }
            else:
                permission_menu_dict[menu_pk]["children"].append({
                    "title": item["permissions__title"],
                    "url": item["permissions__url"],
                })
    print('权限列表', permission_list)
    print('菜单权限', permission_menu_dict)
    # 将当前登录人的权限列表注入session中
    request.session['permission_list'] = permission_list
    # 将权限表name字段列表注入session中
    request.session['permission_names'] = permission_names
    # 将当前登录人的菜单权限字典注入session中
    request.session['permission_menu_dict'] = permission_menu_dict

3、因修改了权限列表的数据结构,所以中间件校验权限也需要修改,中间件middlewares.py代码如下:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect, HttpResponse
import re
class PermissionMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        # 设置白名单放行
        for reg in ["/login/", "/admin/*"]:
            ret = re.search(reg, request.path)
            if ret:
                return None

        # 检验是否登录
        user_id = request.session.get('user_id')
        if not user_id:
            return redirect('/login/')

        # 检验权限
        permission_list = request.session.get('permission_list')
        for item in permission_list:
            reg = '^%s$' % item["url"]
            ret = re.search(reg, request.path)
            if ret:
                show_id = item["pid"] or item["id"]
                request.show_id = show_id  # 给request对象添加一个属性
                return None
        return HttpResponse('无权访问')

4、修改my_tags.py文件,代码如下:

@register.inclusion_tag("menu.html")
def get_menu_styles(request):
    permission_menu_dict = request.session.get("permission_menu_dict")
    print("permission_menu_dict", permission_menu_dict)

    for val in permission_menu_dict.values():
        for item in val["children"]:
            val["class"] = "hide"
            # /customer/
            # /customer/edit/3
            if request.show_id == item["pk"]:
                val["class"] = ""

    return {"permission_menu_dict": permission_menu_dict}

总结:之前菜单权限和非菜单权限之间没有关系,通过在权限表中添加pid字段,建立菜单权限和非菜单权限之间的关系,来控制访问某一非菜单权限时,其对应的菜单权限展开。

二、面包屑导航

  需求:实现面包屑导航

1、修改中间件,middlewares.py中代码如下:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect, HttpResponse
import re
class PermissionMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        # 设置白名单放行
        for reg in ["/login/", "/admin/*"]:
            ret = re.search(reg, request.path)
            if ret:
                return None

        # 检验是否登录
        user_id = request.session.get('user_id')
        if not user_id:
            return redirect('/login/')

        # 检验权限
        permission_list = request.session.get('permission_list')

        # 路径导航列表
        request.breadcrumb = [
            {
                "title": "首页",
                "url": "/"
            },
        ]
        for item in permission_list:
            reg = '^%s$' % item["url"]
            ret = re.search(reg, request.path)
            if ret:
                show_id = item["pid"] or item["id"]
                request.show_id = show_id  # 给request对象添加一个属性

                # 确定面包屑列表
                if item["pid"]:
                    ppermission = Permission.objects.filter(pk=item["pid"])
                                          .first()
                    request.breadcrumb.extend(
                        [{  # 父权限字典
                            "title": ppermission.title,
                            "url": ppermission.url
                        },
                        {  # 子权限字典
                            "title": item["title"],
                            "url": request.path
                        }]
                    )
                else:
                    request.breadcrumb.append(
                        {
                            "title": item["title"],
                            "url": item["url"]
                        }
                    )
                    
                return None

        return HttpResponse('无权访问')

2、公共模板页面base.html中面包屑导航位置的代码如下:

<div>
    <ol class="breadcrumb no-radius no-margin">
       {% for item in request.breadcrumb %}
           <li><a href="{{ item.url }}">{{ item.title }}</a></li>
       {% endfor %}
    </ol>
</div>