Django - 权限(3)- 动态显示二级菜单

1、动态显示二级菜单

  上篇随笔中,咱们实现了动态显示一级菜单,如今考虑这样一种状况,用户的菜单权限比较多,这个时候所有并列展示在左侧菜单就不合适了,因此,如今有这样一个需求,即把用户的菜单权限分类,划分红二级菜单,动态显示在左侧菜单,解决方案以下:html

一、修改权限表结构

  (1)分析需求,要求左侧菜单以下显示:前端

    客户管理:mysql

      客户列表sql

    帐单管理:数据库

      帐单列表django

  (2)修改rbac下的models.py,修改后代码以下:session

from django.db import models

class User(models.Model):
    """
    用户表
    """
    name = models.CharField(verbose_name='用户名', max_length=32)
    password = models.CharField(verbose_name='密码', max_length=32)
    roles = models.ManyToManyField(verbose_name='拥有的全部角色', to='Role')
    def __str__(self):
        return self.name

class Role(models.Model):
    """
    角色表
    """
    title = models.CharField(verbose_name='角色名称', max_length=32)
    permissions = models.ManyToManyField(verbose_name='拥有的全部权限', to='Permission')
    def __str__(self):
        return self.title

class Permission(models.Model): # 创建与菜单类的关联,去掉is_menu和icon
    """
    权限表
    """
    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)
    def __str__(self):
        return self.title


class Menu(models.Model):   # 新增一个菜单表
    title = models.CharField(max_length=32, verbose_name='菜单')
    icon = models.CharField(max_length=32, verbose_name='图标', null=True, blank=True)

二、注入session(重点是构建数据结构),setsession.py中代码修改以下:

def initial_session(user_obj, request):
    """
    将当前登陆人的全部权限url列表和本身构建的全部菜单权限字典注入session
    :param user_obj: 当前登陆用户对象
    :param request: 请求对象HttpRequest
    """
    # 查询当前登陆人的全部权限列表
    ret = Role.objects.filter(user=user_obj).values('permissions__url',
                                                    'permissions__title',
                                            'permissions__menu__title',
                                                    'permissions__menu__icon',
                                                    'permissions__menu__id').distinct()
    permission_list = []
    permission_menu_dict = {}
    for item in ret:
        # 获取用户权限列表用于中间件中权限校验
        permission_list.append(item['permissions__url'])
        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"],
                        }
                    ],
                }
            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
    # 将当前登陆人的菜单权限字典注入session中
    request.session['permission_menu_dict'] = permission_menu_dict

三、从session中取出菜单权限信息,修改my_tags.py文件,代码以下:

from django.template import Library
register =Library()

@register.inclusion_tag("menu.html")
def get_menu_styles(request):
    permission_menu_dict = request.session.get("permission_menu_dict")
    return {"permission_menu_dict": permission_menu_dict}

四、渲染页面,修改menu.html文件,代码以下:

<div class="multi-menu">
    {% for item in permission_menu_dict.values %}
        <div class="item">
            <div class="title">
                <i class="{{ item.menu_icon }}"></i>{{ item.menu_title }}
            </div>
            <div class="body">
                {% for foo in item.children %}
                    <a href="{{ foo.url }}">{{ foo.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>

到此,二级菜单已经渲染到页面中了,样式或者其余js效果就靠你的前端技术了!数据结构

2、补充知识点

一、DATABASES的使用

  咱们知道django项目使用数据库要在settings.py中经过设置DATABASES给项目配置数据库引擎,咱们以前都是给项目设置成MySQL或者django默认的sqlite3数据库,你们知道一个项目能够有多个应用,而且事实也是如此的,每一个项目下也会本身的模型类,按照以前的作法,在定义了数据库引擎以后作数据库迁移,那么每一个app下的数据库都使用settings中指定的数据库了,可是你可能会有这样的需求,就是不一样的应用使用不一样的数据库,该如何作呢?没错,也是设置DATABASES,方式以下:app

DATABASES = {
    'default': {   # 下面没有指定的都使用default下的数据库引擎
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'app01':{    # app01使用mysql数据库引擎
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'bms',   # 要链接的数据库,链接前须要建立好
        'USER': 'root',  # 链接数据库的用户名
        'PASSWORD': '',  # 链接数据库的密码
        'HOST': '127.0.0.1',  # 链接主机,默认本机
        'PORT': 3306   #  端口 默认3306
    }
}

二、ForeignKey的参数db_constraint解释学习

  在学习数据库时,咱们经过定义外键使两个表创建链接和约束,但有时咱们须要只创建链接,不创建约束,也就是经过在表中创建另外一个表的id,不设置foreignkey约束。

  Django的ForeignKey也为咱们想好了这两种状况:

    (1)db_constraint = True 表示两个表之间既创建了链接又有约束,并支持ORM语法查询;

    (2)db_constraint = False 表示两个表之间只创建了链接,没有创建约束,并支持ORM语法查询;

  注意:固然你可能会想到可否将ForeignKey改成一个IntegerField,经过定义IntegerField字段的值来与另外一个表创建联系,这种方法也没错,可是这样就不能使用ORM语法查询,也就享受不到ORM查询的方便,为开发形成了困难,因此不推荐这样作!

相关文章
相关标签/搜索