一、动态显示二级菜单

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

1、修改权限表结构

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

    客户管理:

      客户列表

    账单管理:

      账单列表

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

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)

2、注入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

3、从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}

4、渲染页面,修改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效果就靠你的前端技术了!

二、补充知识点

1、DATABASES的使用

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

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
}
}

2、ForeignKey的参数db_constraint解释

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

  Django的ForeignKey也为我们想好了这两种情况:

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

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

  注意:当然你可能会想到能否将ForeignKey改为一个IntegerField,通过定义IntegerField字段的值来与另一个表建立联系,这种方法也没错,但是这样就不能使用ORM语法查询,也就享受不到ORM查询的方便,为开发造成了困难,所以不推荐这样做!

Django - 权限(3)- 动态显示二级菜单的更多相关文章

  1. django中动态生成二级菜单

    一.动态显示二级菜单 1.修改权限表结构 (1)分析需求,要求左侧菜单如下显示: 客户管理: 客户列表 账单管理: 账单列表 (2)修改rbac下的models.py,修改后代码如下: from dj ...

  2. Django权限控制进阶

    一.一级菜单的排序 我们用字典存放菜单信息,而字典是无序的,当一级菜单过多时可能会出现乱序情况,因此需要给一级菜单排序 1.给一级菜单表的model中加一个weight权重的字段 ,权重越大越靠前 w ...

  3. Django - 权限(4)- queryset、二级菜单的默认显示、动态显示按钮权限

    一.queryset Queryset是django中构建的一种数据结构,ORM查询集往往是queryset数据类型,我们来进一步了解一下queryset的特点. 1.可切片 使用Python 的切片 ...

  4. Django - 权限(2)- 动态显示单级权限菜单

    一.权限组件 1.上篇随笔中,我们只是设计好了权限控制的表结构,有三个模型,五张表,两个多对多关系,并且简单实现了对用户的权限控制,我们会发现那样写有一个问题,就是权限控制写死在了项目中,并且没有实现 ...

  5. django自定义rbac权限组件(二级菜单)

    一.目录结构 二.表结构设计 model.py from django.db import models # Create your models here. class Menu(models.Mo ...

  6. django权限之二级菜单

    遗漏知识点 1.构建表结构时,谁被关联谁就是主表,在层级删除的时候,删除子表的时候,主表不会被删除,反之删除主表的话,字表也会被删除, 使用related_name=None   反向查询,起名用的 ...

  7. 巨蟒django之权限7:动态生成一级&&二级菜单

    内容回顾: . 权限的控制 . 表结构设计 存权限的信息 用户表 - name 用户名 - pwd 密码 - roles 多对多 角色表 - name - permissions 多对多 权限表 - ...

  8. Django - 权限(5)- 非菜单权限对应的一级菜单展开、面包屑导航

    一.非菜单权限对应的一级菜单展开 需求:客户列表和账单列表页面中都有添加按钮,当点击添加客户(或编辑客户.删除客户)时,客户列表所属的一级菜单展开,当点击添加账单(或编辑账单.删除账单)时,账单列表所 ...

  9. django中的构造字典(二级菜单,评论树,购物车)

    1.构造父子结构: 1.1需求样式 客户列表 customer_list /customer/list/ -----> 添加客户 customer_add /customer/add/ ---- ...

随机推荐

  1. git rebase小计(转)

    git rebase,顾名思义,就是重新定义(re)起点(base)的作用,即重新定义分支的版本库状态.要搞清楚这个东西,要先看看版本库状态切换的两种情况: 我们知道,在某个分支上,我们可以通过git ...

  2. 使用root直接安装python3.5.2

    操作系统:Centos7.4 不使用pyenv管理器直接进行编译安装3.5.2版本. 下载tgz的包,如果没有安装wget,请yum -y install wget 解压python包: 将解压后的包 ...

  3. 【java并发编程艺术学习】(五)第二章 java并发机制的底层实现原理 学习记录(三) 原子操作的实现原理学习

    章节介绍 主要包括 术语定义.处理器如何实现原子操作.Java如何实现原子操作: 原子(atomic)本意是 不能再进一步分割的最小粒子,“原子操作” 意为 不可被中断的一个或一系列操作. 术语定义 ...

  4. LaTeX技巧203:如何实现等号对齐_LaTeX_Fun_新浪博客

    LaTeX技巧203:如何实现等号对齐_LaTeX_Fun_新浪博客 我们在进行公式的输入排版的时候,通常希望公式比较齐整,所以需要一些等号对齐,或者左对齐,关于公式的左对齐前文已经介绍了方法.htt ...

  5. HTTP之首部

    http报文包括起始行.首部和主体.     HTTP请求/响应起始行 请求组成: 方法 + 请求URL + HTTP版本 响应组成: HTTP版本 + 数字状态码 + 描述状态的原因短语    HT ...

  6. 关于request的几个字段值

    domain: localhost host: localhost:9000 url: /wechat/mynews action: WechatController.myNews path: /we ...

  7. Learning Python 005 字符串和编码

    Python 字符串和编码 介绍 计算机是美国人发明的,最早只有127个字母被编码到计算机,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122. 处理中文一个字节显然 ...

  8. Hadoop添加节点datanode(生产环境)

    Hadoop添加节点datanode 博客分类: hadoop HadoopSSHJDKXML工作  1.部署hadoop    和普通的datanode一样.安装jdk,ssh  2.修改host  ...

  9. NIPT需要多大的数据量(reads number)?

    NIPT需要多大的数据量(reads number)? 调研 2014 Noninvasive prenatal diagnosis of common aneuploidies by semicon ...

  10. Struts2学习第五课 通过和ServletAPI耦合的方式获取WEB资源

    与Servlet耦合的访问方式 直接访问Servlet API将使Action与环境Servlet环境耦合在一起,测试时需要有Servlet容器,不便对Action的单元测试. 直接获取HttpSer ...