Django - 权限(5)- 非菜单权限对应的一级菜单展开、面包屑导航

时间:2021-12-26 19:34:44

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

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

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>