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…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...
ubuntu中安装conda的后遗症
缘由: 在编译rk3588的sdk时,遇到编译buildroot失败,提示如下: 提示缺失expect,但是实测相关工具是在的,如下显示: 然后查找借助各个ai工具,重新安装相关的工具,依然无解。 解决&am…...
关于疲劳分析的各种方法
疲劳寿命预测方法很多。按疲劳裂纹形成寿命预测的基本假定和控制参数,可分为名义应力法、局部应力一应变法、能量法、场强法等。 1名义应力法 名义应力法是以结构的名义应力为试验和寿命估算的基础,采用雨流法取出一个个相互独立、互不相关的应力循环&…...
循环神经网络(RNN):从理论到翻译
循环神经网络(RNN)是一种专为处理序列数据设计的神经网络,如时间序列、自然语言或语音。与传统的全连接神经网络不同,RNN具有"记忆"功能,通过循环传递信息,使其特别适合需要考虑上下文或顺序的任…...
【异常】极端事件的概率衰减方式(指数幂律衰减)
在日常事件中,极端事件的概率衰减方式并非单一模式,而是取决于具体情境和数据生成机制。以下是科学依据和不同衰减形式的分析: 1. 指数衰减(Exponential Decay) 典型场景:当事件服从高斯分布(正态分布)或指数分布时,极端事件的概率呈指数衰减。 数学形式:概率密度函数…...
