rbac组件之动态一级菜单栏实现


上一个版本,前端页面的左侧菜单栏在HTML中写死了,左侧菜单栏需要根据业务的不同而展示不同的菜单栏!!!

 那么在当前的例子中,哪些可以成为菜单栏呢?

"""
客户管理
    客户列表:/customer/list/
    添加客户:/customer/add/
    删除客户:/customer/list/(?P\d+)/
    修改客户:/customer/edit/(?P\d+)/
    批量导入:/customer/import/
    下载模板:/customer/tpl/
账单管理
    账单列表:/payment/list/
    添加账单:/payment/add/
    删除账单:/payment/del/(?P\d+)/
    修改账单:/payment/edit/<?P\d+/
"""

"""
客户列表和账单列表两个可以成为菜单
"""

根据上一个版本的表结构也可以在所有URL中找出可以做菜单的URL,但是会很麻烦,那么此时可以在Permission权限表中,加入一个字段来标识来此URL是否可以做菜单

class Permission(models.Model):
    """权限表"""
    title = models.CharField(
        verbose_name="权限名称",
        max_length=32,
    )
    url = models.CharField(
        verbose_name="含正则URL",
        max_length=128,
    )
    is_menu = models.BooleanField(
        verbose_name="是否可以做菜单",
        default=False,
    )
    icon = models.CharField(
        verbose_name="图标",
        max_length=64,
blank=True,
) def __str__(self): return self.title

菜单栏的图标,使用的是fontawesome,图标的形态不同,仅仅是class属性fa后面的代码不同,如:fa-address-book" aria-hidden="true">

权限初始化的时候,在session中再加入一条数据信息,即当前用户的菜单栏信息即可

from django.conf import settings


def init_permission(current_user, request):
    permission_queryset = current_user.roles.filter(
        permissions__isnull=False,
    ).values(
        "permissions__id",
        "permissions__url",
        "permissions__title",
        "permissions__is_menu",
        "permissions__icon",
    ).distinct()
    permission_list = []
    menu_list = []
    for item in permission_queryset:
        permission_list.append(item["permissions__url"])
        if item["permissions__is_menu"]:
            temp = {
                "url": item["permissions__url"],
                "title": item["permissions__title"],
                "icon": item["permissions__icon"],
            }
            menu_list.append(temp)
    request.session[settings.PERMISSION_SESSION_KEY] = permission_list
    request.session[settings.MENU_LIST] = menu_list


"""
permission_list = [
    '/customer/list/', 
    '/customer/add/', 
    '/customer/list/(?P\\d+)/', 
    '/customer/edit/(?P\\d+)/', 
    '/customer/import/', 
    '/customer/tpl/', 
    '/payment/list/', 
    '/payment/add/', 
    '/payment/del/(?P\\d+)/', 
    '/payment/edit/<?P\\d+/'
]
menu_list = [
    {'url': '/customer/list/', 'title': '客户列表', 'icon': 'fa-address-book'}, 
    {'url': '/payment/list/', 'title': '账单列表', 'icon': 'fa-money'}
]
"""

此时,在session中存在两条数据信息,一条是权限,一条是菜单,权限已经完成了,当前问题是如何把菜单数据给渲染到前端页面呢?如果是在每一个需要用到菜单栏的HTML去编写代码,那么会很繁琐,虽然相同页面可以继承一个母版,但是不符合rbac组件的

编写原则,即拿即用。

那么可以将左侧菜单栏写成一个inclusion_tag,前端哪里需要直接调用即可,无需编写其余代码

rbac/templatetags/rbac.py

from django.template import Library
from django.conf import settings
import re

register = Library()


@register.inclusion_tag("rbac/menu.html")
def menu(request):
    menu_list = request.session.get(settings.MENU_LIST)
    for item in menu_list:
        url = "^%s$" % item["url"]
        if re.match(url, request.path_info):
            item["class"] = "active"
    return {"menu_list": menu_list}

rbac/templates/rbac/menu.html

<div class="static-menu">
    {% for menu in menu_list %}
        <a href="{{ menu.url }}" class="{{ menu.class }}">
            <span class="icon-wrap">
                <i class="fa {{ menu.icon }}">i>
            span>
            {{ menu.title }}
        a>
    {% endfor %}
div>

前端调用

{# 指的是templatetags/rbac.py #}
{% load rbac %}

{# 需要用到一个参数request,所以调用时需要给其传参(inclusion_tag最多只能有两个参数) #}
{% menu request %}

 rbac组件结构

 总结:

"""
1 在Permission权限表加上is_menu字段,即可方便实现菜单栏的效果
2 在Permission权限表加上icon字段,方便菜单栏图标的渲染
3 在权限初始化中,根据is_menu的值(字段类型为布尔值)来判断是否可以做菜单,然后把可以做菜单的URL提取到另一个列表存储,该列表中数据是一个个字典,每个字典都有该菜单的URL、title、icon数据信息
4 为了前端的简单调用,rbac组件写了一个inclusion_tag,前端哪里需要直接调用该inclusion_tag即可
"""

 rbac动态一级菜单源码链接

链接:https://pan.baidu.com/s/11CNodIt3XE_LCPeTjB5pRw
提取码:abab