Flask 数据库管理
Flask 数据库管理
概述
在使用 Flask 开发 Web 应用时,数据库的集成和操作是一个绕不开的核心问题。那么,如何在 Flask 中配置和操作数据库?这个博客是一个个人学习概述,从数据库初始化、连接配置到使用 ORM 工具进行数据操作,梳理一下常见流程和注意事项。
数据库初始化
在操作数据库之前,首先要确保我们已经有了一个可用的数据库环境。
这根据所选数据库类型有所不同:
- 对于 SQLite 这类文件型数据库,不需要提前创建数据库文件。只要提供一个文件路径,SQLite 会自动创建数据库文件。
- 而像 MySQL 或 PostgreSQL 这样的服务器型数据库,必须事先在数据库服务器中创建好数据库,Flask 才能连接并操作它。需要注意的是,虽然 Flask 和 SQLAlchemy 可以创建数据库中的表结构或插入数据,但它们无法直接创建数据库本身。
创建数据库的方式通常是直接登录数据库服务端(或使用图形化工具),执行如下 SQL 语句:
1 | CREATE DATABASE newpg; |
这就新建了一个名为 newpg
的数据库。
连接数据库
有了数据库,我们的下一步就是连接它并进行操作。在 Flask 中,我们通常使用 SQLAlchemy 作为 ORM 工具,它可以将 Python 类映射为数据库中的表,并通过操作类的实例来完成增删改查,简化了数据库编程的复杂性。
对于快速开发或结构简单的表(如用户表、配置表),ORM 十分方便。在面对复杂业务逻辑,比如多表关联查询、大数据分页或性能瓶颈时,使用原生 SQL 语句更加高效灵活。SQLAlchemy 同时提供了这两种操作方式的支持。
为更好地集成 SQLAlchemy,Flask 提供了一个官方扩展:Flask-SQLAlchemy
。使用这个扩展,可以更方便地将数据库配置集成进 Flask 应用中。
Flask 本质上是通过创建一个 Flask
类的实例来启动应用的:
1 | from flask import Flask |
为了使用数据库,我们需要先进行一些初始化配置。这些配置通过 app.config
字典进行设置。
最关键的配置项是数据库连接 URI,也就是:
1 | app.config['SQLALCHEMY_DATABASE_URI'] = '数据库连接字符串' |
连接字符串的格式因数据库类型和操作系统环境而异。例如:
数据库类型 | Unix 示例 | Windows 示例 |
---|---|---|
SQLite | sqlite:////tmp/test.db |
sqlite:///C:\\path\\to\\test.db |
PostgreSQL | postgresql://user:pass@localhost/dbname |
同左 |
MySQL | mysql+pymysql://user:pass@localhost/dbname |
同左 |
设置好配置后,我们可以通过 Flask-SQLAlchemy
进行数据库初始化:
1 | from flask_sqlalchemy import SQLAlchemy |
到这里,Flask 应用就已经可以通过 ORM 操作数据库了。
创建数据表
在 flask_sqlalchemy
中,每张数据库表对应一个 Python 类,称为“模型类(Model)”。这个类需要继承自 db.Model
,而类中的每一个属性就是表中的一个字段,由 db.Column()
来定义。同时,可以通过参数设置字段的各种约束,比如是否为主键、是否唯一、是否可为空、默认值等。例如,定义一个 User
表如下:
1 | class User(db.Model): |
要将这个模型真正创建为数据库中的表,可以使用:
1 | with app.app_context(): |
这条语句会创建所有继承自 db.Model
的模型类对应的数据表(如果表已经存在则跳过)。在 Flask 中,某些操作(比如访问数据库配置、当前请求对象等)必须在“应用上下文(application context)”中进行。app.app_context()
的作用是临时推入一个当前应用的上下文,使得 Flask 能够知道此时操作的是哪个应用实例。否则,db.create_all()
无法知道使用哪个数据库连接参数,也无法访问 app.config
中的配置信息。
除了使用 ORM 模型,也可以直接通过 SQLAlchemy 的底层 engine
接口运行原生 SQL 来建表。这种方式适合已有完整 SQL 脚本,或需要进行复杂控制的场景。以下是一个建表示例:
1 | from sqlalchemy import text |
db.engine
是 SQLAlchemy 的数据库引擎对象;text()
用于包装原生 SQL 字符串,使其能被 SQLAlchemy 安全执行;- 原生 SQL 建表后不会自动注册为 ORM 模型类,因此无法用
User.query
等方式进行操作,需手动执行 SQL 查询。
数据表操作
使用 ORM 模型的最大优势在于:可以像操作 Python 对象一样操作数据库,比如:
1 | # 插入数据 |
在这里也可以看到,在使用 Flask 操作数据库时,无论是通过 ORM 还是直接写 SQL,本质上都是在进行一场“对话”——我们与数据库之间开启一次连接,在这次连接中执行若干操作,最后一起提交或撤销。这种对话机制在数据库中被称为“事务”。
事务(transaction) 是指一组数据库操作的最小执行单位,要么全部成功提交(commit()
),要么全部撤销回滚(rollback()
),保持数据一致性。这就好比一次购物结账流程:选了商品(操作数据),还没付款之前(commit 前)随时可以取消或修改(rollback),只有真正付款后(commit)才算完成。
db.session
是 SQLAlchemy 提供的“会话对象”,是与数据库交互的入口之一,专用于操作 ORM 模型类。可以通过它来新增数据(add()
/ add_all()
)、修改对象属性、删除对象(delete()
)、最终统一提交(commit()
)或回滚(rollback()
)。
1 | user = User(username='alice') |
当处理原生 SQL 时,可以使用 db.engine.connect()
获取底层数据库连接,手动执行 SQL 语句:
1 | from sqlalchemy import text |
这和 db.session
本质上也开启了一个事务,同样需要 commit()
才会生效。
数据库迁移(Database Migration)
在实际开发中,随着业务需求的不断演进,我们的数据库模型结构往往也需要相应调整,比如新增字段、修改字段类型或删除表。这种将 ORM 模型的变更同步应用到数据库结构中的过程,就称为数据库迁移(Migration)。
例如,我们在模型类中新增了一个字段:
1 | class User(db.Model): |
这时候如果再次执行 db.create_all()
,数据库是不会自动添加这个新字段的。因为:
create_all()
只会在数据库中创建尚不存在的表;- 它不会检测或更新已有表的字段结构。
这意味着数据库结构和模型代码将“脱节”,最终导致程序运行报错或数据不一致。
为了解决这个问题,Flask 提供了官方推荐的工具:Flask-Migrate,它基于 SQLAlchemy 的 Alembic 工具,能够自动追踪模型变更并生成对应的迁移脚本。
使用 Flask-Migrate 的步骤:
- 在 Flask 应用中初始化迁移支持:
1 | from flask_migrate import Migrate |
- 初始化迁移环境(只需执行一次):
1 | flask db init |
这会生成一个 migrations/
文件夹,用于记录每次结构变更和版本。
- 检测模型变更并生成迁移脚本:
1 | flask db migrate -m "Add email field to User" |
这会自动比较当前数据库结构和模型类的差异,并生成相应 SQL 迁移脚本。-m
参数用于给此次变更命名,就像 Git 的提交信息。
- 执行迁移,更新数据库结构:
1 | flask db upgrade |
该命令会将迁移脚本中的结构变更真正应用到数据库。
可以将 migrations/
文件夹加入 Git 版本控制,这样数据库结构的变更也可以跟随代码同步管理。
Flask CLI 与配置加载机制
在使用上述命令如 flask db migrate
或 flask run
时,Flask CLI 工具需要知道我们的应用是在哪里定义的。也就是说,它要找到那个定义了 Flask(__name__)
实例的文件(例如 app.py
),并加载上下文。
默认情况下,如果我们没有设置环境变量 FLASK_APP
,Flask 会假设我们的主程序名是 app.py
。但更推荐的做法是设置该变量,指明主应用:
1 | export FLASK_APP=app.py # Linux/macOS |
为了避免每次都手动设置环境变量,Flask CLI 会在启动时自动加载项目根目录下的两个文件(如果存在)来设置环境变量:
.env
:通用环境变量,例如数据库地址、密钥等;.flaskenv
:Flask 专用配置,如FLASK_APP
,FLASK_ENV
,FLASK_DEBUG
等。
这些文件的格式非常简单:
1 | FLASK_APP=app.py |
这种自动加载机制是基于 python-dotenv
实现的,Flask >=1.0 已内置该支持。
而如果使用 python app.py
启动应用,.env
和 .flaskenv
是不会自动加载的,除非显式调用:
1 | from dotenv import load_dotenv |
这会加载默认的 .env
文件(或手动指定的路径),并将变量写入 os.environ
,之后就可以通过 os.getenv()
来访问这些配置值。
项目配置管理
在一个成熟的 Flask 项目中,常常需要处理各种配置参数,例如:
- 数据库连接字符串
- 应用密钥
- 文件上传目录
- 运行环境(开发 / 生产)
- 第三方服务密钥(如邮件、Redis)
推荐采用 配置类 + .env
文件 的组合方式:
1 | project/ |
.env
示例内容:
1 | DATABASE_URL=postgresql://user:password@localhost/db |
.env
主要保存的是这些类型的配置,不提交到 Git:
类型 | 示例 |
---|---|
连接信息 | 数据库、Redis、邮箱等 URI |
密钥信息 | 加密密钥、Token 密钥、第三方 API 密钥 |
环境信息 | 开发/生产标志、调试开关 |
运行参数 | 主机、端口、默认语言等 |
config/settings.py
配置类:
1 | import os |
app.py
中加载配置:
1 | from flask import Flask |
这样项目就可以根据环境变量动态切换开发、测试或生产配置,结构清晰、灵活可控。
小结
当我们着手开发一个新的 Flask 项目,并计划引入数据库支持时,整体流程可以分为以下几个关键步骤,下面我们以实际开发视角,一步步串起整个数据库操作链条:
🧱 第一步:创建数据库(数据库初始化)
在开始开发前,我们需要先准备好数据库环境:
- SQLite:不需要提前建库,提供文件路径即可;
- PostgreSQL / MySQL:需要手动创建数据库,例如使用 SQL 命令:
1 | CREATE DATABASE mydb; |
此时我们拥有了数据库实体,但还没有表结构。
⚙️ 第二步:配置数据库连接
我们在 Flask 应用中通过配置项 SQLALCHEMY_DATABASE_URI
连接数据库,并初始化 ORM 工具 SQLAlchemy:
1 | app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:pass@localhost/mydb' |
推荐把这些配置写入 .env
文件,并使用配置类统一管理,这样不同环境之间切换更灵活、敏感信息也更安全。
📐 第三步:设计数据模型并创建数据表
我们通过继承 db.Model
的方式来定义 ORM 数据模型,例如:
1 | class User(db.Model): |
然后使用:
1 | with app.app_context(): |
即可在数据库中创建所有定义的模型表。此时数据库结构正式建立完成。
💡 第四步:读写数据库(事务操作)
我们可以使用 db.session
操作模型对象,执行增删改查,并通过 commit()
提交事务:
1 | new_user = User(username='alice') |
所有操作都基于事务机制,可以回滚、批处理,确保数据一致性。
🔁 第五步:支持数据库迁移
随着开发进行,模型结构不可避免会发生变化,比如新增字段、调整索引等。这时候我们使用 Flask-Migrate 工具自动完成结构更新,而不必手写 SQL:
1 | flask db migrate -m "Add email to User" |
通过这一机制,数据库结构的演进可以与代码版本一起被管理、回退。
🧩 第六步:项目配置结构与 Flask CLI
为了实现跨环境开发部署、统一管理变量和命令,我们引入如下结构:
1 | project/ |
并通过 .flaskenv
或 FLASK_APP
告诉 Flask CLI 主程序位置:
1 | FLASK_APP=app.py |
可以通过 flask run
、flask db
等命令快速操作开发服务与数据库迁移。