Django - 权限(5)- 非菜单权限对应的一级菜单展开、面包屑导航
一、非菜单权限对应的一级菜单展开
需求:客户列表和账单列表页面中都有添加按钮,当点击添加客户(或编辑客户、删除客户)时,客户列表所属的一级菜单展开,当点击添加账单(或编辑账单、删除账单)时,账单列表所属的一级菜单展开。
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>