Django之一级菜单

Posted kindvampire

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django之一级菜单相关的知识,希望对你有一定的参考价值。

1.model设计

技术图片
from django.db import models            
class Permission(models.Model):
    url = models.CharField(max_length=64, verbose_name=权限)
    title = models.CharField(max_length=32, verbose_name=标题)  # 备注这个url是做什么的
    icon = models.CharField(max_length=64, null=True, verbose_name=图标) # 存放菜单前面的图标
    is_menu = models.BooleanField(default=False) # 用来判断(此url)是否是菜单
            
    def __str__(self):
        return self.title
            
    class Meta:
        verbose_name_plural = 权限管理
            
            
class Role(models.Model):
    name = models.CharField(max_length=32, verbose_name=角色)
    permissions = models.ManyToManyField(Permission, verbose_name=角色拥有的权限, blank=True)
            
    def __str__(self):
        return self.name
            
    class Meta:
        verbose_name_plural = 角色管理
            
            
class User(models.Model):
    username = models.CharField(max_length=32, verbose_name=用户名,unique=True)
    password = models.CharField(max_length=32, verbose_name=密码)
    roles = models.ManyToManyField(Role, verbose_name=用户的角色, blank=True)
            
    def __str__(self):
        return self.username
            
    class Meta:
        verbose_name_plural = 用户管理
View Code

2. views.py文件 登录函数中登陆成功后获取当前用户的权限的所有信息(url,title,icon,is_menu)

如:

技术图片
per = obj.roles.all().filter(permissions__url__isnull=False).values(permissions__url,
                                                                    permissions__title,
                                                                    permissions__icon,
                                                                    permissions__is_menu,
                                                                    ).distinct()
print(per)

## 打印per的数据
QuerySet[{
             permissions__url: /customer/list/,
             permissions__title: 客户列表,
             permissions__icon: fa-connectdevelop,
             permissions__is_menu: True},
         {
             permissions__url: /customer/add/,
             permissions__title: 添加客户,
             permissions__icon: None,
             permissions__is_menu: False},
         {
             permissions__url: /customer/edit/(?P<cid>d+)/,
             permissions__title: 编辑客户,
             permissions__icon: None,
             permissions__is_menu: False},
         {
             permissions__url: /customer/del/(?P<cid>d+)/,
             permissions__title: 删除客户,
             permissions__icon: None,
             permissions__is_menu: False},
         {
             permissions__url: /payment/list/,
             permissions__title: 账单列表,
             permissions__icon: fa-code-fork,
             permissions__is_menu: True},
         {
             permissions__url: /payment/add/,
             permissions__title: 添加账单,
             permissions__icon: None,
             permissions__is_menu: False},
         {
             permissions__url: /payment/edit/(?P<pid>d+)/,
             permissions__title: 编辑账单,
             permissions__icon: None,
             permissions__is_menu: False},
         {
             permissions__url: /payment/del/(?P<pid>d+)/,
             permissions__title: 删除账单,
             permissions__icon: None,
             permissions__is_menu: False
         }]
View Code

3、从上述中的数据中挑出菜单列表

技术图片
# 菜单列表
            menu = []
    
            # 权限列表
            permission = []
    
            for i in per:
                permission.append({
                    url: i.get(permissions__url)
                })
                if i.get(permissions__is_menu): # 如果permissions__is_menu为True就是菜单,放到菜单列表中
                    menu.append({
                        url: i.get(permissions__url),
                        title: i.get(permissions__title),
                        icon: i.get(permissions__icon)
                    })
View Code

4. 为了使两个列表(session中作为值)在session中对应的键的名字可以由用户改变,在名字中设置两个常量

settings.py文件:

技术图片
# 存放权限的session的key
PERMISSION_SESSION_KEY = permission

# 存放菜单的session的key
MENU_SESSION_KEY = menu
View Code

5. 将两个列表放到session中

登录函数,第三步后面

技术图片
from django.conf import settings
request.session[settings.PERMISSION_SESSION_KEY] = permission
request.session[settings.MENU_SESSION_KEY] = menu
View Code

6. 权限验证的中间件中获取session中的PERMISSION_SESSION_KEY进行权限验证

技术图片
permission = request.session.get(settings.PERMISSION_SESSION_KEY)
# 权限验证(url,中间件中获取的当前url地址如:通过request.path_info获取)
for i in permission:
    if re.match(r^{}$.format(i[url]), url):
    return
View Code

7. incluesion_tags(模板中调用函数)

目的:用于前端菜单的展示而编写的函数
函数作用:为菜单添加样式,然后通过装饰器交给特定的模板,
具体如下:

my_tags.py文件

技术图片
# -*- coding: utf-8 -*-
# __author__ = "maple"
            
from django import template
from django.conf import settings
import re
register = template.Library()
@register.inclusion_tag(menu_tag.html) # 讲给这个模板进行渲染
def menu(request):
    url = request.path_info  # 获取当前url地址
    menu_list = request.session[settings.MENU_SESSION_KEY]  # 获取session中的菜单url地址

    # 添加激活的样式
    for i in menu_list:
        if re.match(f^{i["url"]}$,url): # 判断,如果当前页面地址栏中的url地址是菜单中的地址
            i[class] = active         # 就给菜单中的地址加上active类选择器。
            break    
            return {menu_list:menu_list}          
            
    #此时,menu_list列表中的数据为:(前端页面当前停留在客户列表菜单上)
    [{
    url: /customer/list/,
    title: 客户列表,
    icon: fa-connectdevelop,
    class: active},
    {
    url: /payment/list/,
    title: 账单列表,
    icon: fa-code-fork
    }]
View Code

8. menu_tag.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>
View Code

9.将incluesion_tags应用到前端html页面中

技术图片
<div class="left-menu">
<div class="menu-body">
{% load my_tags %} # my_tags为存放menu函数的文件名,
{% menu request %} # request为第七步中的menu函数的参数
</div>
</div>
View Code

注意:tags文件都放在templatetags目录中,目录名字不能变,位置随意。

目录分布

技术图片

 

 技术图片

以上是关于Django之一级菜单的主要内容,如果未能解决你的问题,请参考以下文章

Django表示错误:选择一个有效的选择。这种选择不是可用的选择之一

如何在片段中填充列表视图?

如何在 Django Summernote 中显示编程片段的代码块?

二级菜单优化功能

Django 3 - 如何创建许多页面然后在菜单上显示它们?

Django 3.0.8 'bootstrap' 不是注册标签库。必须是以下之一: