SQLAlchemy 在 Flask 应用中的使用和最佳实践
SQLAlchemy 在 Flask 应用中的使用和最佳实践
- @[TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践)
- 模型的编写
- **SQLAlchemy 中建立关联**
- **利用 SQLAlchemy 中的关联进行查询**
- **实现示例**
- backref与back_populates?
- **backref反向引用**
- **back_populates后填充**
- ****层面的关系****
- **数据库层面的关系**
- **SQLAlchemy ORM 层面的关系**
- 模型的导入
SQLAlchemy 在 Flask 应用中的使用和最佳实践
- @[TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践)
- 模型的编写
- **SQLAlchemy 中建立关联**
- **利用 SQLAlchemy 中的关联进行查询**
- **实现示例**
- backref与back_populates?
- **backref反向引用**
- **back_populates后填充**
- ****层面的关系****
- **数据库层面的关系**
- **SQLAlchemy ORM 层面的关系**
- 模型的导入
在构建 Python web 应用时,处理数据库是一个不可避免的任务。SQLAlchemy 作为一个强大的 SQL 工具包和对象关系映射(ORM)系统,为 Python 应用提供了高效处理数据库的能力。特别是在 Flask 这类框架中,SQLAlchemy 提供了一个直观的方式来定义数据模型和执行数据库操作。
模型的编写
在 SQLAlchemy 中,一个数据模型通常是通过定义一个类来创建的,这个类继承自 db.Model
。模型类代表数据库表,类中的属性代表表中的列。例如:
from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()class User(db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(80), unique=True, nullable=False)email = db.Column(db.String(120), unique=True, nullable=False)
在这个例子中,User
类代表一个用户表,其中包含 ID、用户名和电子邮件地址。
SQLAlchemy 中建立关联
SQLAlchemy 允许在模型间建立一对多、多对一或多对多的关系。例如,一个店铺拥有多个设备的一对多关系可以这样定义:
class Store(db.Model):id = db.Column(db.Integer, primary_key=True)devices = db.relationship('Device', backref='store')class Device(db.Model):id = db.Column(db.Integer, primary_key=True)store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
利用 SQLAlchemy 中的关联进行查询
有了关联后,您可以轻松地在相关的模型之间进行数据查询。例如,要找到某个特定店铺的所有设备,您可以使用以下代码:
store = Store.query.get(some_store_id)
devices = store.devices
实现示例
假设您的模型之间的关系如下所述:
class GameRecord(db.Model):# ...device_id = db.Column(db.Integer, db.ForeignKey('device.id'))device = db.relationship('Device', backref='game_records')class Device(db.Model):# ...store_id = db.Column(db.Integer, db.ForeignKey('store.id'))store = db.relationship('Store', backref='devices')class Store(db.Model):# ...address = db.Column(db.String(200))
您可以这样获取游戏位置:
game_record = GameRecord.query.get(some_id)
game_location = game_record.device.store.address
backref与back_populates?
在 SQLAlchemy 中,backref
和 back_populates
都是用来定义模型间双向关系的选项,但它们在使用上略有不同。理解这两个选项的区别有助于更好地组织和维护数据库模型的关系。
backref反向引用
backref
是一种在定义关系时快捷创建反向引用的方式。- 当您在一个模型(如
GameRecord
)中定义了一个关系(比如到User
),并使用了backref
,SQLAlchemy 会自动在另一个模型(User
)中创建一个反向关系。 - 这意味着您无需在两个模型中都定义关系,SQLAlchemy 会为您处理这部分。
例如,在 GameRecord
模型中定义 user
关系时使用 backref
:
class GameRecord(db.Model):# ...user = db.relationship('User', backref='game_records')
这将自动在 User
模型中创建一个 game_records
属性,可以通过它访问与该用户相关联的所有 GameRecord
实例。
back_populates后填充
back_populates
用于在两个模型间明确地创建双向关系。- 与
backref
不同,使用back_populates
需要在关联的两个模型中都明确地声明关系。 - 这提供了更多的灵活性和清晰度,尤其是在复杂的关系中。
例如,设备(Device
)和店铺(Store
)的关系可以使用 back_populates
定义:
在 Device
模型中:
class Device(db.Model):# ...store = db.relationship('Store', back_populates='devices')
在 Store
模型中:
class Store(db.Model):# ...devices = db.relationship('Device', back_populates='store')
这样,Device
的每个实例都有一个 store
属性指向它所属的 Store
,同时每个 Store
实例都有一个 devices
属性指向所有属于该店铺的 Device
实例。
总而言之:
- 使用
backref
更为简便,但可能在某些情况下不够明确。 - 使用
back_populates
提供了更明确的关系定义,特别是在复杂的模型关系中。 - 选择使用哪一个取决于具体的应用场景和个人编码风格。在大多数情况下,
backref
足以满足需求,并且可以减少代码量。
层面的关系
在 SQLAlchemy 中使用 db.relationship
建立的一对多关系(如您示例中的 devices = db.relationship('Device', backref='store', lazy=True)
)在数据库层面是不直接体现的。这个关系存在于 SQLAlchemy ORM(对象关系映射)层面,用于在应用程序中方便地处理和查询数据库记录,但它不会直接映射为数据库表中的某个字段或结构。
数据库层面的关系
- 在数据库层面,一对多关系通常是通过外键实现的。例如,在
Device
表中,会有一个字段(如store_id
),作为外键指向Store
表的主键。 - 这种关系确保了数据的完整性和关联性,但它本身并不提供直接的查询机制。
SQLAlchemy ORM 层面的关系
db.relationship
是 SQLAlchemy 提供的高级抽象,允许您在两个模型类之间建立关联关系。- 这使得您可以用类似于操作普通 Python 对象的方式来处理数据库记录。例如,通过
store.devices
访问一个特定店铺的所有设备,或者通过device.store
访问某个设备所属的店铺。 backref
参数在反向关系中添加了一个类似的便利属性,这样就可以从Device
实例轻松访问其关联的Store
实例。
总而言之:
- 数据库层面的一对多关系是通过外键字段实现的。
- SQLAlchemy ORM 层面的
db.relationship
为这种关系提供了一个更为直观和方便的操作接口,但它只存在于代码层面,不直接映射到数据库结构中。 - 这种设计使得应用程序的后端开发更加简洁和直观,同时保持了数据库的完整性和效率。
模型的导入
如果模型创建的顺序不对,可能会报错,例如如下:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'device.store_id' could not find table 'store' with which to generate a foreign key to target column 'id'
问题出现在创建数据库表时,SQLAlchemy 无法找到 device
表中 store_id
字段引用的 store
表。错误信息 sqlalchemy.exc.NoReferencedTableError
表明在尝试创建外键关系时,SQLAlchemy 无法找到被引用的表或列。
如果你确保你的表名都没有问题,你可能需要考虑你的模型定义的顺序又或者你是否正确导入了模型
例如,假设您的 Flask 应用的入口点是 run.py
,您应该检查其中的导入语句和应用初始化代码。一个典型的 Flask 应用结构可能如下:
# run.pyfrom flask import Flask
from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '您的数据库连接'
db = SQLAlchemy(app)# 确保在 db.create_all() 调用之前导入所有模型
from models.store import Store
from models.device import Device
# ... 其他模型的导入 ...@app.route('/')
def index():return "Welcome to the app!"if __name__ == '__main__':db.create_all() # 在应用上下文中创建所有数据库表app.run(debug=True)
在这个示例中,Store
模型在 Device
模型之前导入,因为 Device
依赖于 Store
(store_id
字段是外键,指向 Store
表的主键)。如果 Store
和 Device
在不同的文件中定义,这种导入顺序尤为重要。
相关文章:

SQLAlchemy 在 Flask 应用中的使用和最佳实践
SQLAlchemy 在 Flask 应用中的使用和最佳实践 [TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践) 模型的编写**SQLAlchemy 中建立关联****利用 SQLAlchemy 中的关联进行查询****实现示例** backref与back_populates?**backref反向引用****back_populates后填充** …...

FineReport -问题学习图表设计图表类型-单元格扩展父子格-报表预览
1,问:为什么本地每次预览都要填帐号密码?答:模板认证关闭一下及可 2.单元格扩展与父子格----左父格-扩展方向-箭头往那个方向就往那个方向 1)数据集参数 在定义数据集时,通过使用if函数判断参数的值是否为空,若为空就不过滤参数,若不为空就进行参数过滤。SELECT * FROM…...

微信小程序广告banner、滚动屏怎么做?
使用滑块视图容器swiper和swiper-item可以制作滚动屏,代码如下: wxml: <swiper indicator-dots indicator-color"rgba(255,255,255,0.5)" indicator-active-color"white" autoplay interval"3000"><swiper-ite…...

Network(一)计算机网络介绍
一 计算机网络 1 概述 什么是计算机网络? 硬件方面:通过线缆将网络设备和计算机连接起来 软件方面:操作系统,应用软件,应用程序通过通信线路互连 实现资源共享、信息传递、增加可靠性、提高系统处理能力 2 网络与云计算 3 计算机网…...

【数据结构】堆(Heap):堆的实现、堆排序、TOP-K问题
目录 堆的概念及结构 编辑 堆的实现 实现堆的接口 堆的初始化 堆的打印 堆的销毁 获取最顶的根数据 交换 堆的插入(插入最后) 向上调整(这次用的是小堆) 堆的删除(删除根) 向下调整(这次用的…...

保护数字前沿:下一代防火墙如何塑造网络安全的未来
下一代防火墙通过提供先进的威胁检测、精细控制和云安全功能,正在重塑网络安全的未来。随着数字环境的不断发展,组织必须采用这些创新解决方案来保护其数字资产并维护安全的数字前沿。 在当今互联的世界中,网络威胁变得越来越复杂,…...

深入理解Java中的String.join方法
在 Java 编程中,字符串操作是非常常见的需求。在 Java 8 中引入了一个方便的字符串连接方法 String.join,它能够简洁而高效地将多个字符串连接起来。本篇博客将深入介绍 String.join 方法的使用和原理。 什么是String.join方法? String.join…...

【MySQL系列】 第三章 · 函数
写在前面 Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正࿰…...

微信小程序wxss定位/选择/查找元素的几种方式
wxss定位、选择、查找元素的几种方式与css类似,下面介绍常用的几种: 选择器样例样例描述.class.intro选择所有拥有 class"intro" 的组件#id#firstname选择拥有 id"firstname" 的组件elementview选择所有 view 组件element, element…...

Canvas—从入门到案例实现
文章目录 Canvas—从入门到案例实现一、设置canvas环境1.1 <canvas>元素1.2 渲染上下文context 二、形状与路径的绘制2.1 形状绘制2.2 路径绘制2.3 绘制一个笑脸 三、使用样式和颜色四、绘制文本五、使用图像5.1 图片源5.2 获取页面内的图片5.3 缩放Scaling5.4 切片Slici…...

飞书开发学习笔记(六)-网页应用免登
飞书开发学习笔记(六)-网页应用免登 一.上一例的问题修正 在上一例中,飞书登录查看网页的界面显示是有误的,看了代码,理论上登录成功之后,应该显示用户名等信息。 最后的res.nickName是用户名,res.i18nName.en_us是英…...

【ROS】Nav2源码下载、编译、运行
【ROS】郭老二博文之:ROS目录 1、源码下载 1.1 源码地址 https://github.com/ros-planning/navigation2 1.2 创建工程目录 ROS2使用目录结果来管理项目,因此在下载前需要创建好目录结构: mkdir -p ~/git/nav2/src1.3 下载 git中默认版本是main。本人的开发环境为Ubun…...

微信小程序 30分钟倒计时功能
ps:凑个数 getTimeDiff(date) {let _this = this;let curTime = new Date(date)_this.countDown(_this.timeFormatConvert(new Date(curTime.setMinutes(curTime.getMinutes() + 30))))},timeFormatConvert(e) {const Y = e.getFullYear(); // 年const M = this.prefixZero(e.…...

JAVA判断指定日期是否在指定的时间段内
参考文献: Java语言判断当前时间在时间范围内_java判断时间区间-CSDN博客 package com.itheima.method2;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date;public class DateTest {public static voi…...

关于晋升与跳槽的一些思考
内部晋升 内部晋升是我优先考虑的,原因有很多。首先这是一个新业务,相对而言容易拿到结果。其次我想体验不同的晋升路径,内部晋升答辩,是挑战也是一次成长的机会,是一次他人帮助自己review的机会。作为从校园出来的校…...

url找不到404的问题,url被拼接
今天遇到一个测试feign调用的功能,如图所示 先说结论 Controller换成RestController 将日志设置为debug模式 被DispatcherServlet FORWARD了 找到路径 对属性设置断点,看下是哪注进来的 我们再去找encodedPath 此处是undertow的源码,但是und…...

如何解决golang开发中遇到的报错:checksum mismatch downloaded
问题描述 如题,项目开发中遇到如下报错(你的报错信息可能与我的有一点区别,如verifying的包名,但是问题本质都是一样的): verifying github.com/algorand/go-codec/codecv1.1.8/go.mod: checksum mismatc…...

4.以docker容器生成镜像推送到阿里云镜像仓库
1.开通阿里云镜像仓库 1.1 登录阿里云,访问容器镜像服务。地址如下: https://cr.console.aliyun.com/cn-shanghai/instances 1.2 个人学习为例,创建个人版实例 1.2.1 点击个人实例 1.2.2 .创建个人实例 1.2.3 创建完成后,设置…...

CSS Form表单布局
效果图 <Tab IsCard"true"><TabItem Text"表单信息-DIV版本"><div class"row"><div class"col"><label for"field1">工程名称:</label><input class"form-control" type&…...

c++ shared_mutex 读写锁使用详解
c 读写锁使用详解 std::shared_mutex c17 头文件 #include <shared_mutex>。用于实现共享和独占访问的互斥锁。提供了一种更加灵活的机制,允许多个线程在共享模式下读取数据,但只允许单个线程在独占模式下写入或修改数据。与 std::mutex 相比&am…...

淘宝商品详情接口,淘宝详情页接口,宝贝详情页接口,商品属性接口,商品信息查询,商品详细信息接口,h5详情,淘宝API接口演示案例
淘宝详情接口API可以帮助简化运营流程,更加专注于产品本身。通过调用API,可以快速获取到商品的标题、图片、价格等信息,省去了手动编写和编辑的繁琐过程。这样就可以更快地上架新品、更新商品信息,提高运营的效率。 taobao.item_…...

python爬取网站数据,作为后端数据
一. 内容简介 python爬取网站数据,作为后端数据 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3代码 链接: 三.主要流程 3.1 通过urllib请求网站 里面用的所有的包 ! pip install lxml ! pip install selenium ! pip install…...

【机器学习】K近邻算法:原理、实例应用(红酒分类预测)
案例简介:有178个红酒样本,每一款红酒含有13项特征参数,如镁、脯氨酸含量,红酒根据这些特征参数被分成3类。要求是任意输入一组红酒的特征参数,模型需预测出该红酒属于哪一类。 1. K近邻算法介绍 1.1 算法原理 原理&a…...

基于安卓android微信小程序的快递取件及上门服务系统
项目介绍 本文从管理员、用户的功能要求出发,快递取件及上门服务中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、快递下单管理、预约管理、管理员管理、系统管理、订单管理,用户客户端;首页、快递下单、预约管理…...

leetCode 92.反转链表 II + 图解
92. 反转链表 II - 力扣(LeetCode) 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left < right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 206. 反转链表 - 力扣(LeetCode&am…...

【MongoDB】索引 – 通配符索引
一、准备工作 这里准备一些数据 db.books.drop();db.books.insert({_id: 1, name: "Java", alias: "java 入门", description: "入门图书" }); db.books.insert({_id: 2, name: "C", alias: "c", description: "C 入…...

python安装pip install报错Could not fetch URL https://pypi.org/simple/pip/...更换镜像源
更换镜像源 一. 现象pycharm使用 pip install xxx安装包时,一直报错: 二. 原因:三. 解决办法:一. 临时使用二. 永久更改三. 永久更改1. Windowswindows环境下Windows(示例win10) 2. Linux or Mac3. Pycharm…...

C++ 算数运算符 学习资料
C 算数运算符 在 C 中,算数运算符用于执行各种数学运算。以下是常用的算数运算符: :加法运算符,用于将两个表达式相加。-:减法运算符,用于从一个表达式中减去另一个表达式。*:乘法运算符&…...

问题 H: 棋盘游戏(二分图变式)
题意:要求找到 不放车就无法达到最大数的点 的个数 题解:1.以行列绘制二分图 2.先算出最大二分匹配数 3.依次遍历所有边 删除该边,并计算二分匹配最大值 (若小于原最大值即为重要点)࿰…...

SQL 主从数据库实时备份
在SQL数据库中,主从复制(Master-Slave Replication)是一种常见的实时备份和高可用性解决方案。这种配置允许将一个数据库服务器(主服务器)的更改同步到一个或多个其他数据库服务器(从服务器)&am…...