动态菜单之 点击非菜单权限, 默认选中子菜单,与展开

这是一个添加用户的,界面。 这个功能不是一个菜单选项。 他在 用户管理-->客户列表 页面中的一个功能。
但是当我点击的时候,  左侧的信息,全部收缩起来了。 我觉得应该时要展开这个一级标签,并且还要有 选中 客户列表的这样一个提示。
so  又有了我问题, 想想解决办法:

思路是这样子的:

  - 登录,做权限和菜单的初始化。
    - 获取菜单信息

{
    1: {'title': '用户管理',
        'icon': 'fa-envira',
        'children': [{'id': 1, 'title': '客户列表', 'url': '/customer/list/'}]
        },
    2: {'title': '信息管理',
        'icon': 'fa-black-tie',
        'children': [{'id': 7, 'title': '账单列表', 'url': '/payment/list/'}]
        }
}

    - 获取权限信息( 进行更改之后的数据结构 )

[
    {'id': 1, 'url': '/customer/list/', 'paren_id': None},               # 客户列表: 可以作为子菜单的
    {'id': 2, 'url': '/customer/add/', 'paren_id': 1},                   # 添加客户: 不可
    {'id': 3,  'url': '/customer/edit/(?P<cid>\d+)/', 'paren_id': 1},   # 编辑客户: 不可 
    {'id': 4, 'url': '/customer/del/(?P<cid>\d+)/', 'paren_id': 1},
    {'id': 5, 'url': '/customer/import/', 'paren_id': 1},
    {'id': 6, 'url': '/customer/tpl/', 'paren_id': 1},
    {'id': 7, 'url': '/payment/list/', 'paren_id': None},                # 账单列表: 可以作为子菜单的
    {'id': 8, 'url': '/payment/add/', 'paren_id': 7},
    {'id': 9, 'url': '/payment/edit/(?P<pid>\d+)/', 'paren_id': 7},
    {'id': 10, 'url': '/payment/del/(?P<pid>\d+)/', 'paren_id': 7}
]

(解释:我们在循环这个,权限信息列表的时候。 使用当前访问的url  和  列表字典中的 url 进行匹配。 如果他的 parent_id 为null。那么这个  'id': 1 就是需要显示被选中的子菜单。 如果他的 parent_id 不为null,那么这个 'paren_id': 1 关联的 "id":1 的这条权限,就是需要显示被选中的子菜单。   这个 id 或者 parent_id 是需要传给inclusion_tag进行使用的。)( 因为做了所属关系,所以这里 不管是 id 还是 parent_id 都是  子菜单的主键 id)

  - 再次进行访问。
    - 中间件中进行权限的校验(根据权限信息 进行校验)
      获取id 或 parent_id (应该呗选中的,可以做菜单的 权限id)。 然后传递给 inclusion_tag

  - 模板中使用 inclusion_tag 生成动态菜单 (根据菜单信息,进行动态生成)
    这里在做 显示被选中的菜单的时候, 就不能再只去判断,url 是否匹配。 而是要判断,于当前url 相匹配的,他的id,  与权限列表中id或parent_id 相等的那个。    权限子菜单,要被选中。

1. 当点击某个不能成为权限的菜单时,指定一个可以成为菜单的权限。让其默认的选中以及展开。( so 我们需要,为这个权限做一个归属。)
还是依然对,数据库进行 开刀:

class Permission(models.Model):
    """
    权限表  一级菜单的表
    """
    title = models.CharField(verbose_name='标题', max_length=32)
    url = models.CharField(verbose_name='含正则的URL', max_length=128)
    menu = models.ForeignKey(verbose_name="所属菜单", to="Menu", null=True, blank=True, on_delete=models.CASCADE)
    parent_Permission = models.ForeignKey(verbose_name="关联权限", help_text="对于非菜单权限,需要确定当前权限归属于哪一个,父权限",
              to="Permission", null=True, blank=True, on_delete=models.CASCADE,related_name="parents")

    def __str__(self):
        return self.title
Permission 表,再次修改,添加自关联字段

so 添加完成后,的这个表。 应该是这个样子的。

2. 对登录的时候, session保存的值进行,一番修改:

def init_permission(current_user, request):
    '''  二级菜单,实现
    :param current_user: 当前请求 用户对象
    :param request:  当前请求 数据
    :return:
    '''
    # 2. 权限 初始化
    # 根据当前用户信息,获取当前用户所拥有的所有的权限(queryset对象 是不能直接放入,session中的)
    permission_queryset = current_user.roles.filter(permissions__isnull=False) 
        .values("permissions__id", "permissions__url", "permissions__title", "permissions__pid_id",
                "permissions__menu_id", "permissions__menu__icon", "permissions__menu__title", ).distinct()

    # 获取权限 和 菜单信息。  权限放在权限列表,菜单放在菜单列表
    menu_dict = {}
    permission_list = []  # 这里就不再是一个 单纯的列表! 而是套嵌字典的列表
    for item in permission_queryset:
        url_dict = {
            "id": item.get("permissions__id"),
            "url": item.get("permissions__url"),
            "paren_id": item.get("permissions__pid_id")
        }
        permission_list.append(url_dict)

        menu_id = item.get("permissions__menu_id")
        if not menu_id:
            continue

        node = {"id": item.get("permissions__id"), "title": item.get("permissions__title"),
                "url": item.get("permissions__url")}
        if menu_id in menu_dict:
            menu_dict[menu_id]["children"].append(node)
        else:
            menu_dict[menu_id] = {
                "title": item.get("permissions__menu__title"),
                "icon": item.get("permissions__menu__icon"),
                "children": [node]
            }
    request.session[settings.PERMISSIONS_SESSION_KEY] = permission_list
    request.session[settings.MENU_SESSION_KEY] = menu_dict
对init_permission 初始化权限列表,和 菜单字典时。做一点修改

3. 然后是,中间件部分的,处理:
  这里 我们需要读取出,当前访问的url (通过 request.path_info)。 然后与权限列表中的所有url 进行匹配。
匹配成功之后。这一步很重要:我们需要一个参数( 一个应该被选中的id 或 parent_id),传递给 inclusion_tag。 如何传递呢?
    request.current_selected_permission = item.get("paren_id") or item.get("id")
  在匹配成功之后,进行这一步操作。 在 request 对象中,添加一个属性current_selected_permission 他的值是 tem.get("paren_id") or item.get("id")
  这个 参数的作用就是,判断。那一个子菜单应该默认被选中 或者 被展开。 or 的语法 不做多余解释。

4. 最后就是 自定义的 模板语法了:

@register.inclusion_tag("rbac/multi_menu.html")
def multi_menu(request):
    '''
    创建二级菜单
    :return:
    '''
    current_selected_permission = request.current_selected_permission
    path_info = request.path_info
    menu_dict = request.session.get(settings.MENU_SESSION_KEY)

    key_list = sorted(menu_dict)  # 对字典的key 进行排序
    ordered_dict = OrderedDict()  # 创建一个空的 有序字典
    for key in key_list:   # 循环有序字典列表
        val = menu_dict[key]  # 得到每一个字典
        val["class"] = "hide"  # 添加一个 class:hide 键值. 控制标签的显示隐藏
        for per in val["children"]:  # 循环 当前字典(菜单) 下的 子菜单
            if per.get("id") == current_selected_permission:
                per["class"] = "active"   # 匹配成功 为当前子菜单添加  class:active 类属性(表示被选中的)
                val["class"] = ""  # 当前一级菜单的 class:""  跟改为空, 覆盖掉hide(不隐藏)
        ordered_dict[key] = val  # 最终将设置好的每一个字典。 添加到有序字典当中

    return {"ordered_dict": ordered_dict, "path_info": path_info}
改动之后的, rbac_tags

这里做个什么改动呢:
  就只有一点, 将原来判断, 当前访问的 url 与 每一个子菜单的url 进行匹配的操作。
    改成了  per.get("id") == current_selected_permission   当前访问的url 的 id 或他的 parent_id 与 保存的 应该展开显示的 子菜单url的 主键id。进行匹配。
  匹配成功的这条子菜单权限 url 自己添加 class="active" 并且他的父级 删除掉 hide  "class" = ""。

原文地址:https://www.cnblogs.com/chengege/p/10702055.html