### SQLAlchemy 在 Flask 应用中的使用和最佳实践
- [@[TOC](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 层面的关系 模型的导入)
- [**SQLAlchemy 中建立关联**](#SQLAlchemy 在 Flask 应用中的使用和最佳实践 @[TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践) 模型的编写 SQLAlchemy 中建立关联 利用 SQLAlchemy 中的关联进行查询 实现示例 backref与back_populates? backref反向引用 back_populates后填充 层面的关系 数据库层面的关系 SQLAlchemy ORM 层面的关系 模型的导入)
- [**利用 SQLAlchemy 中的关联进行查询**](#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 层面的关系 模型的导入)
- [backref与back_populates?](#SQLAlchemy 在 Flask 应用中的使用和最佳实践 @[TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践) 模型的编写 SQLAlchemy 中建立关联 利用 SQLAlchemy 中的关联进行查询 实现示例 backref与back_populates? backref反向引用 back_populates后填充 层面的关系 数据库层面的关系 SQLAlchemy ORM 层面的关系 模型的导入)
- [**backref反向引用**](#SQLAlchemy 在 Flask 应用中的使用和最佳实践 @[TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践) 模型的编写 SQLAlchemy 中建立关联 利用 SQLAlchemy 中的关联进行查询 实现示例 backref与back_populates? backref反向引用 back_populates后填充 层面的关系 数据库层面的关系 SQLAlchemy ORM 层面的关系 模型的导入)
- [**back_populates后填充**](#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 层面的关系 模型的导入)
- [**数据库层面的关系**](#SQLAlchemy 在 Flask 应用中的使用和最佳实践 @[TOC](SQLAlchemy 在 Flask 应用中的使用和最佳实践) 模型的编写 SQLAlchemy 中建立关联 利用 SQLAlchemy 中的关联进行查询 实现示例 backref与back_populates? backref反向引用 back_populates后填充 层面的关系 数据库层面的关系 SQLAlchemy ORM 层面的关系 模型的导入)
- [**SQLAlchemy ORM 层面的关系**](#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
。模型类代表数据库表,类中的属性代表表中的列。例如:
jsx
from flask_sqlalchemy import SQLAlchemy
db = 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 允许在模型间建立一对多、多对一或多对多的关系。例如,一个店铺拥有多个设备的一对多关系可以这样定义:
jsx
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 中的关联进行查询
有了关联后,您可以轻松地在相关的模型之间进行数据查询。例如,要找到某个特定店铺的所有设备,您可以使用以下代码:
python
store = Store.query.get(some_store_id)
devices = store.devices
实现示例
假设您的模型之间的关系如下所述:
python
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))
您可以这样获取游戏位置:
python
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
:
python
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
模型中:
python
class Device(db.Model):
# ...
store = db.relationship('Store', back_populates='devices')
在 Store
模型中:
python
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
为这种关系提供了一个更为直观和方便的操作接口,但它只存在于代码层面,不直接映射到数据库结构中。 - 这种设计使得应用程序的后端开发更加简洁和直观,同时保持了数据库的完整性和效率。
模型的导入
如果模型创建的顺序不对,可能会报错,例如如下:
jsx
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 应用结构可能如下:
jsx
# run.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = 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
在不同的文件中定义,这种导入顺序尤为重要。
| ✍️ 作者:ZouYu
| 🤳 微信号:19973318795