71.(后端)角色接口携带权限数据——flask两张表之间多对多关系的使用与层级关系的输出

news2024/11/19 3:41:51

1.ORM关系之多对多

1.1 什么时候使用多对多关系

例如,我们我们的项目中,一个用户可以拥有多个角色,同样的,一个角色可以给多个用户。通俗来说,一个用户可以购买多个商品,多个商品可以被一个用户购买

1.2操作流程

  1. 多对多的关系需要通过一张中间表来绑定他们之间的关系
  2. 先把两个需要做多对多的模型定义出来
  3. 使用Table定义一个中间表,中间表一般包含两个模型的外键字段就可以啦,并且让他们两个来作为一个“复合主键”
  4. 在两个需要做多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,需要传入一个secondary=中间表对象名

简易版代码可以参考:本人的另一篇专门讲解的博客

2.操作代码

2.1为什么要使用多对多关系

在本数据库结构中,menu是角色的权利,不同的权利赋给不同的用户。所以这里相当于要把menu(记录管理权限)和role(角色)进行多对多的映射

2.2 关联关系的创建

# /flask_shop/models.py
# 此文件用于建立数据库表的模型

# 需要针对数据库的模型
# from enum import unique
from flask_shop import db
# 对数据加密         检查密码
from werkzeug.security import generate_password_hash,check_password_hash
from datetime import datetime

# 创建公用数据库模型
class BaseModel:
    # 记录创建的时间
    create_time = db.Column(db.DateTime,default=datetime.now)
    # 记录修改密码的时间
    update_time = db.Column(db.DateTime, default=datetime.now, onupdate = datetime.now)

# 创建第三张表,用与多对多的映射关系
trm = db.Table('t_role_menu',
    db.Column('rid', db.Integer, db.ForeignKey('t_role.id')),
    db.Column('mid', db.Integer, db.ForeignKey('t_menu.id'))
)
# 建立菜单的数据库
class Menu(db.Model):
    __tablename__ = 't_menu'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(32),unique = True, nullable = False)
    level = db.Column(db.Integer)
    path = db.Column(db.String(32))
    # pid = db.Column(db.Integer)
    pid = db.Column(db.Integer, db.ForeignKey('t_menu.id'))
    # 建立一个自连接的数据,用于做子表
    children = db.relationship('Menu')
    roles = db.relationship('Role', secondary = trm)
    # 由于前端的接收需要给出json数据,不可以直接去获取,所以得单独返回
    def to_dict(self):
        return {
            'id':self.id,
            'name': self.name,
            'level':self.level,
            'path':self.path,
            'pid':self.pid,
            # 子表中的内容需要单独返回,可以做一个递归或者循环
            # 'children': self.get_child_list()
        }
    def get_child_list(self):
        obj_child = self.children
        data = []
        for o in obj_child:
            data.append(o.to_dict)
        return data
# 角色管理
class Role(db.Model):
    __tablename__ = 't_role'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(32), unique=True, nullable = True)
    desc = db.Column(db.String(32))
    # backref反向关联,方便子表查询主表数据
    users = db.relationship('User', backref='role')
    menu = db.relationship('Menu', secondary = trm)

    def to_dict(self):
        return {
            'id':self.id,
            'name': self.name,
            'desc':self.desc
        }

在这里插入图片描述

3.处理报错

Additional arguments should be named _, got ‘secondary’
错误代码

roles = db.Column('Role', secondary = trm)

正确代码

roles = db.relationship('Role', secondary = trm)

4.获取角色管理员权限

4.1方法

角色管理员获取存在子集关系的数据时方法:
略有删减,可以看完整版代码


# 角色管理
class Role(db.Model):
    __tablename__ = 't_role'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(32), unique=True, nullable = True)
    desc = db.Column(db.String(32))
    # backref反向关联,方便子表查询主表数据
    users = db.relationship('User', backref='role')
    menus = db.relationship('Menu', secondary = trm)

    def to_dict(self):
        return {
            'id':self.id,
            'name': self.name,
            'desc':self.desc,
            'menu': self.get_menu_dict()
        }
    
    def get_menu_dict(self):
        menu_list = []
        for m in self.menus:
            # 一共就两级,二级的应该放在一级的当作children输出
            if m.level == 1:
                first_dict = m.to_dict()
                first_dict['children'] = []
                for s in self.menus:
                    # 只有二级才需要加入到children,并判断是否为关联关系
                    if s.level == 2 and s.pid == m.id:
                        first_dict['children'].append(s.to_dict())
                menu_list.append(first_dict)
        return menu_list

4.2Postman测试

在这里插入图片描述

5.完整代码

# /flask_shop/models.py
# 此文件用于建立数据库表的模型

# 需要针对数据库的模型
# from enum import unique
from flask_shop import db
# 对数据加密         检查密码
from werkzeug.security import generate_password_hash,check_password_hash
from datetime import datetime

# 创建公用数据库模型
class BaseModel:
    # 记录创建的时间
    create_time = db.Column(db.DateTime,default=datetime.now)
    # 记录修改密码的时间
    update_time = db.Column(db.DateTime, default=datetime.now, onupdate = datetime.now)


# 需要继承数据库中的模型
class User(db.Model,BaseModel):
    __tablename__ = 't_user'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(32), unique=True, nullable=False)
    pwd = db.Column(db.String(128))
    nick_name = db.Column(db.String(32))
    phone = db.Column(db.String(11))
    email = db.Column(db.String(32))

    # 建立用户与角色的关系(多对一)
    rid = db.Column(db.Integer, db.ForeignKey('t_role.id'))
    
    # 定义两个装饰器,用于访问密码时使用
    @property
    def password(self):
        return self.pwd
    
    # 用户存储时使用,存的是加密过后的数据,若要访问,得通过property装饰器
    # 用户先输入密码,传入到t_pwd,通过函数的加密返回给self.pwd;用户需要访问时,找到property
    # self.pwd,是数据库中的密码(加密过后);t_pwd是用户输入的密码(真实密码)
    @password.setter
    def password(self,t_pwd):
        self.pwd = generate_password_hash(t_pwd)
    
    # 用户二次访问之后,需要把加密过后的密码转成真实密码,与用户输入的密码进行比对
    def check_password(self,t_pwd):
        return check_password_hash(self.pwd,t_pwd)

    def to_dict(self):
        return {
            'id':self.id,
            'name': self.name,
            'nick_name':self.nick_name,
            'phone':self.phone,
            'email':self.email,
            # 此时的role是根据下面backref的role定义的,获取到他的名称
            # 防止角色为空
            'role_name': self.role.name if self.role else ''
        }


# 创建第三张表,用与多对多的映射关系
trm = db.Table('t_role_menu',
    db.Column('rid', db.Integer, db.ForeignKey('t_role.id')),
    db.Column('mid', db.Integer, db.ForeignKey('t_menu.id'))
)

# 建立菜单的数据库
class Menu(db.Model):
    __tablename__ = 't_menu'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(32),unique = True, nullable = False)
    level = db.Column(db.Integer)
    path = db.Column(db.String(32))
    # pid = db.Column(db.Integer)
    pid = db.Column(db.Integer, db.ForeignKey('t_menu.id'))
    # 建立一个自连接的数据,用于做子表
    children = db.relationship('Menu')
    roles = db.relationship('Role', secondary = trm)


    # 由于前端的接收需要给出json数据,不可以直接去获取,所以得单独返回
    def to_dict(self):
        return {
            'id':self.id,
            'name': self.name,
            'level':self.level,
            'path':self.path,
            'pid':self.pid,
            # 子表中的内容需要单独返回,可以做一个递归或者循环
            # 'children': self.get_child_list()
        }
    def get_child_list(self):
        obj_child = self.children
        data = []
        for o in obj_child:
            data.append(o.to_dict())
        return data


# 角色管理
class Role(db.Model):
    __tablename__ = 't_role'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(32), unique=True, nullable = True)
    desc = db.Column(db.String(32))
    # backref反向关联,方便子表查询主表数据
    users = db.relationship('User', backref='role')
    menus = db.relationship('Menu', secondary = trm)

    def to_dict(self):
        return {
            'id':self.id,
            'name': self.name,
            'desc':self.desc,
            'menu': self.get_menu_dict()
        }
    
    def get_menu_dict(self):
        menu_list = []
        for m in self.menus:
            # 一共就两级,二级的应该放在一级的当作children输出
            if m.level == 1:
                first_dict = m.to_dict()
                first_dict['children'] = []
                for s in self.menus:
                    # 只有二级才需要加入到children,并判断是否为关联关系
                    if s.level == 2 and s.pid == m.id:
                        first_dict['children'].append(s.to_dict())
                menu_list.append(first_dict)
        return menu_list

6. 完整测试结果

{
“status”: 200,
“data”: [
{
“id”: 1,
“name”: “荣耀管理员”,
“desc”: “拥有神操作的管理员”,
“menu”: [
{
“id”: 5,
“name”: “订单管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: []
},
{
“id”: 2,
“name”: “用户管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: [
{
“id”: 21,
“name”: “用户列表”,
“level”: 2,
“path”: “/user_list”,
“pid”: 2
}
]
},
{
“id”: 3,
“name”: “权限管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: [
{
“id”: 31,
“name”: “角色列表”,
“level”: 2,
“path”: “/role_list”,
“pid”: 3
},
{
“id”: 32,
“name”: “权限列表”,
“level”: 2,
“path”: “/menu_list”,
“pid”: 3
}
]
},
{
“id”: 4,
“name”: “商品管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: []
},
{
“id”: 6,
“name”: “数据管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: []
}
]
},
{
“id”: 2,
“name”: “钻石管理员”,
“desc”: “拥有不俗的手速的管理员”,
“menu”: [
{
“id”: 2,
“name”: “用户管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: [
{
“id”: 21,
“name”: “用户列表”,
“level”: 2,
“path”: “/user_list”,
“pid”: 2
}
]
},
{
“id”: 3,
“name”: “权限管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: [
{
“id”: 31,
“name”: “角色列表”,
“level”: 2,
“path”: “/role_list”,
“pid”: 3
}
]
},
{
“id”: 4,
“name”: “商品管理”,
“level”: 1,
“path”: null,
“pid”: 1,
“children”: []
}
]
},
{
“id”: 3,
“name”: “铂金管理员”,
“desc”: “正常手速”,
“menu”: []
},
{
“id”: 4,
“name”: “黄金管理员”,
“desc”: “一般手速”,
“menu”: []
}
],
“msg”: “获取角色列表成功”
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【FPGA】Verilog编程实现SDRAM读写(一) ----- 初始SDRAM

文章目录一. 存储器及SDRAM分类1. 存储器分类2. 半导体存储器分类3. SDRAM分类二. 什么是SDRAM?1. SDRAM基本概念2. SDRAM存储阵列3. SDRAM基本存储单元4. BANK概念5. SDRAM容量计算6. SDRAM功能框图7. SDRAM信号引脚8. SDRAM操作命令8.1 禁止命令( INHI…

mysql做查询时,第一次很慢,第二三次就会很快?

前言 sql语句第一次查询慢的原因不仅仅是因为执行计划没有被缓存这么简单,有时候你会发现sql语句重用了执行计划,但是第一次查询时还是很慢. 最主要的原因是第一次查询的时候,mysql会将查询出的部分数据和索引从磁盘加载到内存作为缓存,而第二三此查询的时候就直接从内存缓存…

Spring - 手把手分析 IoC 容器创建过程

概述 这里我们以 Spring 5.2.8.RELEASE 版本为例,看一下 IoC 容器 的创建过程。同时我们使用 java-based 的方式实例化 IoC 容器,即使用 AnnotationConfigApplicationContext Configuration 的方式配置容器需要的组件。 ApplicationContext ctx new …

【云IDE初体验】与君相逢恨晚,真正的轻量级开发工具

云IDE产品介绍 云IDE使用教程 免费使用地址:点击【云IDE】,即可开始创建工作空间啦~ 云IDE1.云IDE介绍2. 使用流程3. 体验总结作为一名大学生,学习的地点很关键,尤其是我们计算机系,更是离不开电脑,去图书馆…

调度线程池 ScheduledThreadPoolExecutor 的正确使用姿势

前言 项目中经常会遇到一些非分布式的调度任务,需要在未来的某个时刻周期性执行。实现这样的功能,我们有多种方式可以选择: Timer类, jdk1.3 引入,不推荐 它所有任务都是串行执行的,同一时间只能有一个任…

【C语言】移位操作符 位操作符 - 对二进制位进行精准操作【+面试题目】_[初阶篇]

快速导航 【前言】 1.移位操作符 1.1左移操作符(<<) 1.2右移操作符(>>) 2.位操作符 2.1 & 按位与 2.2 | (按位或) 2.3 ^ (按位异或) 3.面试题目 3.1 交换两个变量&#xff08;不创建临时变量&#xff09; 3.2统计二进制中1的个数 3.2.1 方法一&#xff1a;…

复合事件归因分析

1 复合事件 1.1 概述 1.2 类型 1.2.1 先决条件事件&#xff08;preconditioned events&#xff09; 1.2.2 多变量事件&#xff08;multivariate CEs&#xff09; eg.高温干旱 1.2.3 时间复合事件&#xff08;temporally CEs&#xff09; eg.旱涝急转 1.2.4 空间复合事件…

电子电路设计基本概念100问(二)【学习目标:原理图、PCB、阻抗设计、电子设计基本原则、基本原器件等】

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

【每天学习一点新知识】网络安全--拒绝服务攻击

目录 1、SYN泛洪攻击 SYN泛洪攻击原理 攻击过程 防御机制 2、Smurf攻击 Smurf攻击原理 间接攻击 放大攻击 防御机制 3、DDoS DDoS原理 直接DDoS攻击 间接DDoS攻击 防御机制 1、SYN泛洪攻击 SYN泛洪攻击原理 终端访问Web服务器之前需要和服务器之间建立TCP连接。W…

万字长文解析Scaled YOLOv4模型(YOLO变体模型)

一&#xff0c;Scaled YOLOv4 摘要1&#xff0c;介绍2&#xff0c;相关工作 2.1&#xff0c;模型缩放 3&#xff0c;模型缩放原则 3.1&#xff0c;模型缩放的常规原则3.2&#xff0c;为低端设备缩放的tiny模型3.3&#xff0c;为高端设备缩放的Large模型 4&#xff0c;Scaled-YO…

大学毕业后,我就送了2个月外卖,哭了一整晚

先简单介绍一下自己&#xff0c;我来自湛江&#xff0c;大学学的的物流管理专业&#xff0c;现在就职于一家互联网公司&#xff0c;从事软件测试工作。 我来自湛江的一个偏远农村&#xff0c;家里兄弟姐妹多&#xff0c;父母无力负担我的学费&#xff0c;很多时候学费都是靠姐…

红黑树 - c++

文章目录&#xff1a;红黑树的介绍红黑树节点定义红黑树的插入操作红黑树的删除红黑树的验证红黑树 vs AVL树红黑树的介绍 红黑树(Red-Black-Tree)&#xff0c;通常写为 R-B Tree。它是一种特殊的二叉搜索树。红黑树的每个节点上都有一个存储位来标识节点的颜色&#xff0c;可…

积木报表—JimuReport v1.5.4版本发布,免费的可视化Web报表工具

项目介绍 一款免费的低代码可视化报表&#xff0c;像搭建积木一样在线拖拽设计&#xff01;低代码开发必备&#xff0c;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; 秉承“简单、易用、专业”的产品理念&#xff0c;极大的降低报表开发难度、缩…

【css伪类选择器及透明度——附项目图片及代码】

不知不觉&#xff0c;又鸽了好长时间了&#xff0c;非常抱歉&#xff0c;没办法&#xff0c;毕竟开学了&#xff0c;今天课少&#xff0c;抽出了两个小时写了一篇css的&#xff0c;每天不是被催更&#xff0c;就是在催更的路上。放心&#xff0c;小陈陈有时间一定会给大家分享好…

SVM 支持向量机

SVM 支持向量机SVM 原理最优化问题线性不可分sklearn 调用 SVM核函数SVM 原理 前置知识&#xff1a;用迭代策略来划分样本&#xff0c;请猛击《神经元的计算》。 SVM 也是用一条迭代的直线来划分不同数据之间的边界&#xff1a; .- 是一条直线&#xff08;线性函数&#xff09…

数据结构c语言版第二版(严蔚敏)第五章笔记

目录 树和二叉树的定义 树的定义 树的基本术语 二叉树的定义 二叉树的性质和存储结构 二叉树的性质 二叉树的存储结构 顺序存储结构 链式存储结构 遍历二叉树和线索二叉树 遍历二叉树 先序遍历 中序遍历 后序遍历 前序遍历的递归算法 中序遍历的递归算法 后序…

SARScape中用sentinel-1数据做SBAS-InSAR完整流程(2/2)

书接上回&#xff1a;SARScape中用sentinel-1数据做SBAS-InSAR完整流程&#xff08;1/2&#xff09; SARScape中用sentinel-1数据做SBAS-InSAR完整流程&#xff08;2/2&#xff09;7 反演第一步Inversion&#xff1a;First Step7.1 导入设置7.2 optional file7.3 parameters参数…

齐博x1用户登录接口

用户的登录主要涉及到小程序登录、APP的帐号密码登录、APP的微信开发平台帐号登录。 相应的地址是&#xff1a;http://qb.net/index.php/index/wxapp.login/index.html 涉及到的方法如下 上面的地址&#xff0c;默认是小程序的登录与注册。 http://qb.net/index.php/index/wxa…

matlab/simulink电力电子仿真傅里叶变换模块(fourier)测幅值相角的设置与使用

matlab/simulink电力电子仿真傅里叶变换模块&#xff08;fourier&#xff09;测幅值相角的设置与使用 今天要说的是一个可以测量信号的幅值和相角的模块&#xff0c;fourier&#xff0c;长下面这样&#xff1a; 有时候我们需要求某个信号的幅值或者相位&#xff0c;或求两个…

用文字描述给黑白照上色,这个免费网站火了!网友:比其他同类都好用

金磊 Alex 发自 凹非寺量子位 | 公众号 QbitAI这是清朝末代皇后婉容广为流传的一张老照片&#xff1a;如果让照片变成彩色的&#xff0c;会是什么样子&#xff1f;竟然没有什么违和感&#xff0c;百年前的老照片似乎在此刻变得鲜活了起来。而这张图上色的背后&#xff0c;并没有…