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…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
工厂方法模式和抽象工厂方法模式的battle
1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...
