【Flask】Flask数据模型关系

数据模型关系

一对多

如上所示,一个作者关联多个文章,暂时认定,一篇文章只能有一个作者。

作者以及文章的类定义如下所示:

class Author(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(128), unique=True)email = db.Column(db.String(128))
​
class Article(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(50), index=True)description = db.Column(db.Text)

一对多的建立步骤

现在需要在数据库中,将作者和文章的关系关联成一对多的关系,具体操作如下:

  1. 定义外键

    外键(Foreign key) 用来在 B 表存储 A 表的主键值,作为与 A 表的关系字段。

    由于外键只能够存储单一数据,所以外键常在 “多” 的一侧定义,一个作者对应多个文章,因此需要在文章模型中添加作者的关系字段,记录作者的主键值,代码如下:

    class Article(db.Model):...author_id = db.Column(db.Integer, db.ForeignKey('author.id'))

  2. 定义关系属性

    关系属性的定义主要是用来标记该类与那个类建立了关系,常常在 “一” 的一侧进行定义,关系属性能够返回多个记录,也称之为集合关系属性。

    在作者和文章的关系中,就需要在作者一侧定义关系属性,代码如下:

    class Author(db.Model):...articles = db.relationship('Article')

  3. 创建表

    # 我在这里是通过python直接创建表,因此使用了app.app_context()这个方法,这个方法主要是用来引入flask的各种方法,否则操作会产生报错
    with app.app_context():# 将所有的模型文件创建为表db.create_all()# 删除数据库中所有的表db.drop_all()
  4. 建立关系

    建立关系这里指的是,将两张表的数据进行关系,主要有以下两种方式:外键字段赋值、关系属性赋值。

    这里我们先准备几组数据,用来操作实现关系的建立。

    from market import app,db
    from market.models import Author,Article
    ​
    author1 = Author(name='余华',email='yuhua@euansu.cn')
    author2 = Author(name='莫言',email='moyan@euansu.cn')
    author3 = Author(name='史铁生',email='shitiesheng@euansu.cn')
    ​
    article1 = Article(title='活着',description='活着')
    article2 = Article(title='许三观卖血记',description='许三观卖血记')
    article3 = Article(title='我与地坛',description='我与地坛')
    article4 = Article(title='红高粱',description='红高粱')
    article5 = Article(title='蛙',description='蛙')
    ​
    with app.app_context():db.session.add(author1)db.session.add(author2)db.session.add(author3)db.session.add(article1)db.session.add(article2)db.session.add(article3)db.session.add(article4)db.session.add(article5)db.session.commit()

    执行如上操作后,查看数据库,正常插入了数据。

    这里需要注意,关系属性虽然在作者模型中,但并未实际在表中创建字段,接下来通过如下代码对数据表中的数据建立一对多关系:

    # 外键字段赋值
    with app.app_context():                              author = Author.query.filter_by(name='余华').first() article = Article.query.filter_by(title='活着').first()article.author_id = author.iddb.session.commit()

    执行完成后,查看数据库,数据表 author_id 的值为关联作者的主键值。

    # 执行完外键关系赋值后,可以通过如下调用,查询作者余华关联的图书
    with app.app_context():                              author = Author.query.filter_by(name='余华').first() print(author.articles)
    # 操作关系属性
    with app.app_context():                              author = Author.query.filter_by(name='余华').first()article = Article.query.filter_by(title='许三观卖血记').first()author.articles.append(article)# 提交事务,将变更写入到数据库db.session.commit()

    执行完成后,查看数据库,数据表 author_id 的值为关联作者的主键值。

    # 执行完外键关系赋值后,可以通过如下调用,查询作者余华关联的图书
    with app.app_context():                              author = Author.query.filter_by(name='余华').first() print(author.articles)

因此,综上步骤,我们通过Flask建立两个表之间的一对多关系时,需要通过以下三个步骤:

  1. 定义外键,需要在 “多” 侧表的模型中增加外键字段。

  2. 定义关系属性,需要在 “一” 侧表的模型中定义关系属性,该属性并不体现在实际的表中。

  3. 建立关系,通过指定外键字段或操作关系属性,能够建立两个表之间的一对多关系属性。

建立双向关系

我们在 Author 类中定义了集合关系属性 articles ,用以获取某个作者的多个作品。在特殊场景下,也有可能希望在 Article 类中定义一个类似的 author 关系属性,当被调用时,返回关联的 Author 记录,这类返回单个值的关系属性被称为标量关系属性。而两侧都添加关系属性获取对方记录的称之为双向关系

双向关系并不是必须的,只是满足于特殊的场景,可以按照如下方式建立双向关系:

class Author(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(128), unique=True)email = db.Column(db.String(128))articles = db.relationship('Article')
​
class Article(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(50), index=True)description = db.Column(db.Text)author_id = db.Column(db.Integer, db.ForeignKey('author.id'))author = db.relationship('Author')

使用如下 Python 代码查询:

with app.app_context():author = Author.query.filter_by(name='余华').first()article = Article.query.filter_by(title='许三观卖血记').first()print(author.articles)print(article.author)

使用 backref 简化关系定义

backef 参数用来自动为关系另一侧添加关系属性,作为反向引用,赋予的值会作为关系另一侧的关系属性名称。

class Author(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(128), unique=True)email = db.Column(db.String(128))articles = db.relationship('Article', backref='author')
​
class Article(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(50), index=True)description = db.Column(db.Text)author_id = db.Column(db.Integer, db.ForeignKey('author.id'))

再次执行关系属性语句:

with app.app_context():author = Author.query.filter_by(name='余华').first()article = Article.query.filter_by(title='许三观卖血记').first()print(author.articles)print(article.author)

能够正常获取其关系的对象。

使用 backref 非常方便,但通常来说 “显式好过隐式”,所以我们应该尽量使用 back_populates 定义双向关系。

多对一

一对多的关系反过来就是多对一,这两种关系模型分别从不同的视角出发。

在一对多中,我们提交以下两点:

  1. 定义外键,需要在 “多” 侧表的模型中增加外键字段。

  2. 定义关系属性,需要在 “一” 侧表的模型中定义关系属性,该属性并不体现在实际的表中。

因此,多对一的关系代码定义如下:

class Author(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(128), unique=True)email = db.Column(db.String(128))# 定义外键author_id = db.Column(db.Integer, db.ForeignKey('author.id'))# 定义关系属性articles = db.relationship('Article')
​
​
class Article(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(50), index=True)description = db.Column(db.Text)

一对一

一对一关系是在一对多关系的基础上转化而来,只要确保两侧的关联关系唯一即可保证一对多关系转系转化为了一对一关系,在定义时,设置关系属性的 uselistFlase ,此时的一对多关系转化为一对一关系。

class Person(db.Model):id = db.Column(db.Integer, primary_key = True)name = db.Column(db.String(30), unique = True)idcard = db.relationship('IDCard', uselist = False)
​def __repr__(self):return '<Person %r>' % self.name
​
class IDCard(db.Model):id = db.Column(db.Integer, primary_key = True)idcard = db.Column(db.String(30), unique = True)person_id = db.Column(db.Integer, db.ForeignKey('person.id'))person = db.relationship('Person')
​def __repr__(self):return '<IDCard %r>' % self.idcard

这里执行如下操作先写入数据:

with app.app_context():              idcard = IDCard(idcard='123456789')  idcard2 = IDCard(idcard='123456798') person = Person(name='euansu')db.session.add(idcard) db.session.add(idcard2) db.session.add(person) db.session.commit()

建立关系:

# 指定外键id
with app.app_context():                              idcard = IDCard.query.filter_by(idcard='123456789').first() person = Person.query.filter_by(name='euansu').first()idcard.person_id = person.iddb.session.commit()

查看数据库,正常写入:

# 操作关系属性
with app.app_context():                              idcard = IDCard.query.filter_by(idcard='123456798').first() person = Person.query.filter_by(name='euansu').first()person.idcard.append(idcard)# 提交事务,将变更写入到数据库db.session.commit()

多对多

多对多关系中,需要建立一个关联表,关联表并不存在数据,只用来存储两侧模型外键的对应关系。

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(128), unique=True) grade = db.Column(db.String(20)) teachers = db.relationship('Teacher', secondary=association_table, back_populates='students') 
​
class Teacher(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), unique=True) grade = db.Column(db.String(20))stutents = db.relationship('Student', secondary=association_table, back_populates='teachers') 

创建完模型之后,执行迁移,在数据库中查看到新增的三张表:

flask db migrate
​
flask db upgrade

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

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

相关文章

Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能

文章目录 前言Github项目地址&#xff0c;包含模板文件后期思考补充项目设置编写失误环境visual studio 配置详细的配置看我这篇文章 Nuget 推荐NewtonSoft 成功Bogus 成功Github文档地址随机生成构造器生成构造器接口(推荐) 文件夹设置Nlog 成功&#xff01;Nlog.configNlogHe…

代码学习记录26----贪心算法

随想录日记part26【把这两天没写的补回来】 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.22-24 主要内容&#xff1a;今天开始学习贪心算法&#xff0c;基础知识可以看链接&#xff0c;&#xff1a;接下来是针对题目的讲解&#xff1a;1.分配饼干 &#x…

继承和多态(1)(继承部分)

继承 继承的概念 上文就是继承的概念。 必须记住父类也可以称为基类&#xff0c;超类。 子类也可以称为派生类。 继承的语法 在Java中如果要表示类之间的继承关系&#xff0c;需要借助extends关键字&#xff0c;具体如下&#xff1a; 修饰符 class 子类 extends 父类 {//…

网易web安全工程师进阶版课程

课程介绍 《Web安全工程师&#xff08;进阶&#xff09;》是由“ i春秋学院联合网易安全部”出品&#xff0c;资深讲师团队通过精炼的教学内容、丰富的实际场景及综合项目实战&#xff0c;帮助学员纵向提升技能&#xff0c;横向拓宽视野&#xff0c;牢靠掌握Web安全工程师核心…

pycharm搭建新的解释器及删除处理

目录 1.创建虚拟环境 个人实际操作&#xff1a; 对于“继承全局站点包”&#xff1a; 2.创建一个新项目 3.删除操作 &#xff08;1&#xff09;删除解释器 &#xff08;2&#xff09;删除新建项目 1.创建虚拟环境 Pycharm官方文档说明网址&#xff1a; Configure a virt…

【机器学习】包裹式特征选择之序列前向选择法

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

向开发板上移植ip工具:交叉编译 ip工具

一. 简介 前面几篇文章学习了 CAN设备节点的创建&#xff0c;以及如何使能 CAN驱动。 本文学习向开发板上移植ip工具。 二. 向开发板上移植ip工具&#xff1a;交叉编译 ip工具 注意&#xff1a;在移植 ip 命令的时候必须先对根文件系统做个备份&#xff01;防止操作失误导…

ffmpeg实现媒体流解码

本期主要讲解怎么将MP4媒体流的视频解码为yuv,音频解码为pcm数据;在此之前我们要先了解解复用和复用的概念; 解复用:像mp4是由音频和视频组成的(其他内容流除外);将MP4的流拆分成视频流(h264或h265等)和音频流(AAC或mp3等); 复用:就是将音频和视频打包成MP4或者fl…

Cobalt Strike -- 各种beacon

今天来讲一下cs里面的beacon 其实cs真的功能很强大&#xff0c;自带代理创建&#xff0c;自带beacon通信&#xff01;&#xff01;&#xff01; 一张图&#xff0c;就能说明beacon的工作原理 1.Beacon 每当有一台机器上线之后&#xff0c;我们都会选择sleep时间&#xff0c;…

吴恩达2022机器学习专项课程(一) 3.6 可视化样例

问题预览 1.本节课主要讲的是什么&#xff1f; 2.不同的w和b&#xff0c;如何影响线性回归和等高线图&#xff1f; 3.一般用哪种方式&#xff0c;可以找到最佳的w和b&#xff1f; 解读 1.课程内容 设置不同的w和b&#xff0c;观察模型拟合数据&#xff0c;成本函数J的等高线…

nodejs+vue高校洗浴管理系统python-flask-django-php

高校洗浴管理系统采用数据库是MySQL。网站的搭建与开发采用了先进的nodejs进行编写&#xff0c;使用了express框架。该系统从两个对象&#xff1a;由管理员和学生来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对学生管理、浴室信息、浴室预约、预约…

【JavaEE初阶系列】——阻塞队列

目录 &#x1f6a9;阻塞队列的定义 &#x1f6a9;生产者消费者模型 &#x1f388;解耦性 &#x1f388;削峰填谷 &#x1f6a9;阻塞队列的实现 &#x1f4dd;基础的环形队列 &#x1f4dd;阻塞队列的形成 &#x1f4dd; 内存可见性 &#x1f4dd;阻塞队列代码 &#…

【深度学习】pytorch,MNIST手写数字分类

efficientnet_b0的迁移学习 import torch import torch.nn as nn import torch.optim as optim import torchvision.transforms as transforms from torchvision.datasets import MNIST from torch.utils.data import DataLoader from torchvision import models import matplo…

IntelliJ IDE 插件开发 | (七)PSI 入门及实战(实现 MyBatis 插件的跳转功能)

系列文章 IntelliJ IDE 插件开发 |&#xff08;一&#xff09;快速入门IntelliJ IDE 插件开发 |&#xff08;二&#xff09;UI 界面与数据持久化IntelliJ IDE 插件开发 |&#xff08;三&#xff09;消息通知与事件监听IntelliJ IDE 插件开发 |&#xff08;四&#xff09;来查收…

android Fragment 生命周期 方法调用顺序

文章目录 Introlog 及结论代码 Intro 界面设计&#xff1a;点击左侧按钮&#xff0c;会将右侧 青色的RightFragment 替换成 黄色的AnotherRightFragment&#xff0c;而这两个 Fragment 的生命周期方法都会打印日志。 所以只要看执行结果中的日志&#xff0c;就可以知道 Fragme…

【单例测试】Mockito实战

目录 一、项目介绍二、业务代码2.1 导入依赖2.2 entity2.3 Dao2.4 业务代码 三、单元测试3.1 生成Test方法3.2 引入测试类3. 3 测试前准备3.4 测试3.4.1 name和phone参数校验3.4.2 测试数据库访问 3.4.3 数据库反例 总结 前面我们提到了《【单元测试】一文读懂java单元测试》 简…

IDEA Android新建项目基础

title: IDEA Android基础开发 search: 2024-03-16 tags: “#JavaAndroid开发” 一、构建基本项目 在使用 IDEA 进行基础的Android 开发时&#xff0c;我们可以通过IDEA自带的新建项目功能进行Android应用开发基础架构的搭建&#xff0c;可以直接找到 File --> New --> …

基于nodejs+vue学生作业管理系统python-flask-django-php

他们不仅希望页面简单大方&#xff0c;还希望操作方便&#xff0c;可以快速锁定他们需要的线上管理方式。基于这种情况&#xff0c;我们需要这样一个界面简单大方、功能齐全的系统来解决用户问题&#xff0c;满足用户需求。 课题主要分为三大模块&#xff1a;即管理员模块和学生…

上位机图像处理和嵌入式模块部署(qmacvisual轮廓查找)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;图像的处理流程一般都是这样的&#xff0c;即灰度化-》降噪-》边缘检测-》二值化-》开闭运算-》轮廓检测。虽然前面的几个…

LeetCode 面试经典150题 14.最长公共前缀

题目&#xff1a; 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 思路&#xff1a; 代码&#xff1a; class Solution {public String longestCommonPrefix(String[] strs) {if (strs.length 0) {return &…