flask 定义数据库关系(多对多)
多对多
我们使用学生和老师来演示多对多关系:每个学生有多个老师,每个老师有多个学生。多对多关系示意图如下:
在实例程序中,Student类表示学生,Teacher类表示老师。在这两个模型之间建立多对多关系后,我们需要在Student类中添加一个集合关系属性teachers,调用它可以获取某个学生的多个老师,而不同的学生可以和同一个老师建立关系。
在一对一关系中,我们可以在“多”这一侧添加外键指向“一”这一侧,外键只能存储一个记录,但是在多个关系中,每一个记录都可以与关系另一侧的多个记录建立关系,关系两侧的模型都需要存储一组外键。在SQLAlchemy中,要想表示多对多关系,除了关系两侧的模型外,我们还需要创建一个关联表(association table)。关联表不存储数据,只用来存储关系两侧模型的外键对应关系。
app.py :建立多对多关系
association_table = db.Table('association',
db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
db.Column('teacher_id', db.Integer, db.ForeignKey('teacher.id'))
) class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(70), unique = True)
grade = db.Column(db.String(20))
teachers = db.relationship('Teacher',
secondary = association_table,
back_populates = 'students') # collection
def __repr__(self):
return '<Student %r>' % self.name class Teacher(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(70), unique = True)
office = db.Column(db.String(20))
#back_populates, 定义双向关系
# back_populates参数的值需要设为关系另一侧的关系属性名
students = db.relationship('Student',
secondary = association_table,
back_populates = 'teachers') # collection
关联表使用db.Table类定义,传入的第一个参数是关联表的名称。我们在关联表中定义了两个外键字段:teacher_id字段存储Teacher类的主键,student_id存储Student类的主键。借助关联表这个中间人存储的外键对,我们可以把对对多关系分化成两个一对多关系,如下所示:
当我们需要查询某个学生记录的多个老师时,我们先通过学生和关联表的一对多关系查找多有包含该学生的关联表记录,然后后就可以从这些记录中再进一步获取每个关联表记录包含的老师记录。以上图的随机数据为例,假设学生记录的id为1,那么通过查找关联表中student_id字段为1的记录,就可以获取到对应的teacher_id值(分别为3和4),通过外键值就可以在teacher表里获取id为3和4的记录,最终,我们就获取到id为1的学生记录相关联的所有老师记录。
我们在Student类中定义一个teachers关系属性用来获取老师集合。在多对多关系中定义关系函数,除了第一个参数是关系另一侧的模型名称外,我们还需要添加一个secondary参数,把这个值设为关联的名称。
为了便于实现真正的多对多关系,我们需要建立双向关系。建立双向关系后,多对多关系会变得更加直观。在Student类上的teachers集合属性会返回所有关联的老师记录,而在Teacher类上的students集合属性会返回所有相关的学生记录
除了在声明关系时有所不同个,多对多关系模式在操作关系时和其他关系模式基本相同。调用关系属性student.teachers时,SQLAlchemy会直接返回关系另一侧的Teacher对象,而不是关联表记录,反之亦同。和其他关系模式中的结合关系属性一样,我们可以将关系属性teachers和students像列表一样操作。比如,当你需要为某一个学生添加老师时,对关系属性使用append()方法即可。如果你想要接触关系,那么可以使用remove()方法。
关联表有SQLAlchemy接管,它会帮我们管理这个表:我们只需要像往常一样通过操作关系属性来建立或解除关系,SQLAlchemy会自动在关联表中创建或删除对应的关联表记录,而不用手动操作关联表。
同样的,在多对多关系中我们也只需要在关系的一侧操作关系。当为学生A的teachers添加老师B后,调用老师B的students属性时返回的学生记录也会包含学生A,反之亦同。
>>> s1 = Student(name = 'xiaxiaoxu')
>>> t1 = Teacher(name = 'xufengchai')
>>> s2 = Student(name = 'xiayuze')
>>> t2 = Teacher(naem = 'xulei')
>>> t2 = Teacher(name = 'xulei')
>>> s1
<Student 'xiaxiaoxu'>
>>> s2
<Student 'xiayuze'>
>>> t1
<Teacher 'xufengchai'>
>>> t2
<Teacher 'xulei'>
>>> db.session.add(s1)
>>> db.session.add(s2)
>>> db.session.add(t1)
>>> db.session.add(t2)
>>> db.session.commit()
>>> s1.teachers
[]
>>> s1.teacher_id =1
>>> s2.teacher_id =2
>>> t1.student_id = 1
>>> t2.student_id = 2
>>> s1.teachers
[]
>>> db.session.commit()
>>> s1.teachers.append(t1)
>>> s1.teachers.append(t2)
>>> s1.teachers
[<Teacher u'xufengchai'>, <Teacher u'xulei'>]
>>> t1.students.append(s1)
>>> t1.students.append(s2)
>>> t1.students
[<Student u'xiaxiaoxu'>, <Student u'xiaxiaoxu'>, <Student u'xiayuze'>]
flask 定义数据库关系(多对多)的更多相关文章
- flask 定义数据库关系(一对多)
定义关系 在关系型数据库中,我们可以通过关系让不同表之间的字段建立联系.一般来说,定义关系需要两步,分别是创建外键和定义关系属性.在更复杂的多对多关系中,我们还需要定义关联表来管理关系.下面我们学习用 ...
- flask 定义数据库关系(一对一)
一对一 我们将使用国家和首都来演示一对一关系:每个国家只有一个首都.反过来,一个城市也只能作为一个国家的首都.一对一关系如下: 在示例程序中,Country类表示国家,Capital类表示首都.建立一 ...
- flask 定义数据关系(多对一)
多对一 一对多关系反过来就是多对一关系,这两种关系模式分别从不同的视角出发.一个作者拥有多篇文章,反过来就是多篇文章属于同一个作者.为了便于区分,我们使用居民和城市来演示多对一关系:多个居民住在同一个 ...
- day 69 orm操作之表关系,多对多,多对一(wusir总结官网的API)
对象 关系 模型 wusir博客地址orm官网API总结 django官网orm-API orm概要: ORM 跨表查询 class Book(models.Model): title = mod ...
- Flask之数据库设置
4 数据库 知识点 Flask-SQLALchemy安装 连接数据库 使用数据库 数据库迁移 邮件扩展 4.1 数据库的设置 Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在 ...
- 开始VS 2012 中LightSwitch系列的第2部分:感受关爱——定义数据关系
[原文发表地址] Beginning LightSwitch in VS 2012 Part 2: Feel the Love - Defining Data Relationships [原文发表 ...
- 库增删该查,表增删该查,记录增删该查,表与表关系(多对多,多对一,一对一),mysql用户管理
库增删该查 增加库 create database db1 create database db1 charset="gbk 查看库 show databases 查看所有库 show cr ...
- C++中重定义的问题——问题的实质是声明和定义的关系以及分离式编译的原理
这里的问题实质是我们在头文件中直接定义全局变量或者函数,却分别在主函数和对应的cpp文件中包含了两次,于是在编译的时候这个变量或者函数被定义了两次,问题就出现了,因此,我们应该形成一种编码风格,即: ...
- BI之SSAS完整实战教程6 -- 设计维度、细化维度上:创建维度定义特性关系
前面我们使用过数据源向导.数据源视图向导.Cube向导来创建相应的对象. 本篇我们将学习使用维度向导来创建维度. 通过前面几个向导的学习,我们归纳一下共同点,主要分成两步 1. 使用某种对象类型的向导 ...
随机推荐
- java jdk 打开出错 Failed to load the JNI shared library
``` Failed to load the JNI shared library 解决方法 换了JDK 32位x86的 打开32位 eclipse 2017 oxygen 出现这个问题,修改 配置文 ...
- swiper4自动轮播切换手动触碰后停止踩坑——属性disableOnInteraction
swiper4轮播设置autoplay自动切换后,即默认设置: <script> var mySwiper = new Swiper('.swiper-container', { auto ...
- CentOS7安装Java还是无法使用javac
centos7.4 安装java之后,还是无法使用javac命令.报错提示: [root@ip---- centos]# javac bash: javac: command not found 解决 ...
- 织梦channelartlist标签当前栏目高亮
channelartlist标签完美支持currentstyle属性,实现自动加载当前栏目CSS样式,可以用来标识当前栏目位置的CSS,解决方法如下: 打开文件include\taglib\chann ...
- 告别GOPATH,快速使用 go mod(Golang包管理工具)
https://studygolang.com/articles/17508?fr=sidebar 文中的wserver为module名,route为本地的包名,go.mod所在的目录名不一定非要和m ...
- python学习笔记(五)
面向对象方法 元组的二义性:不明确参数代表的含义 circle=(2,4,6) def distance_from_origin(x,y): return "返回x,y坐标" de ...
- tiny png
golang package main import ( "encoding/base64" "fmt" "os" "net/ht ...
- Window应急响应(五):ARP病毒
0x00 前言 ARP病毒并不是某一种病毒的名称,而是对利用arp协议的漏洞进行传播的一类病毒的总称,目前在局域网中较为常见.发作的时候会向全网发送伪造的ARP数据包,严重干扰全网的正常运行,其危害甚 ...
- git使用git-credential-winstore保存https访问密码
使用 https 方式 clone 一个 git 仓库,每次pull 或者 push 的时候都需要输入用户名和密码. 访问远程Git仓库可以用 SSH 方式和 https 方式,https 每次访问时 ...
- 使用ionic2开发一个二维码扫描功能
界面添加一个按钮: <button ion-button block color="secondary" class="Scan-button" (cli ...