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
2
3
4
from flask import Flask

app = Flask(__name__)
app.run()

为了使用数据库,我们需要先进行一些初始化配置。这些配置通过 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
2
3
4
5
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:pass@localhost/newpg'
db = SQLAlchemy(app)

到这里,Flask 应用就已经可以通过 ORM 操作数据库了。

创建数据表

flask_sqlalchemy 中,每张数据库表对应一个 Python 类,称为“模型类(Model)”。这个类需要继承自 db.Model,而类中的每一个属性就是表中的一个字段,由 db.Column() 来定义。同时,可以通过参数设置字段的各种约束,比如是否为主键、是否唯一、是否可为空、默认值等。例如,定义一个 User 表如下:

1
2
3
class User(db.Model):
id = db.Column(db.Integer, primary_key=True) # 主键,自增
username = db.Column(db.String(80), unique=True, nullable=False) # 用户名,唯一且非空

要将这个模型真正创建为数据库中的表,可以使用:

1
2
with app.app_context():
db.create_all()

这条语句会创建所有继承自 db.Model 的模型类对应的数据表(如果表已经存在则跳过)。在 Flask 中,某些操作(比如访问数据库配置、当前请求对象等)必须在“应用上下文(application context)”中进行。app.app_context() 的作用是临时推入一个当前应用的上下文,使得 Flask 能够知道此时操作的是哪个应用实例。否则,db.create_all() 无法知道使用哪个数据库连接参数,也无法访问 app.config 中的配置信息。

除了使用 ORM 模型,也可以直接通过 SQLAlchemy 的底层 engine 接口运行原生 SQL 来建表。这种方式适合已有完整 SQL 脚本,或需要进行复杂控制的场景。以下是一个建表示例:

1
2
3
4
5
6
7
8
9
10
11
from sqlalchemy import text

with app.app_context():
with db.engine.connect() as conn:
conn.execute(text("""
CREATE TABLE IF NOT EXISTS JOB_INFO (
id SERIAL PRIMARY KEY,
job_name VARCHAR(80) UNIQUE NOT NULL
);
"""))
conn.commit()
  • db.engine 是 SQLAlchemy 的数据库引擎对象;
  • text() 用于包装原生 SQL 字符串,使其能被 SQLAlchemy 安全执行;
  • 原生 SQL 建表后不会自动注册为 ORM 模型类,因此无法用 User.query 等方式进行操作,需手动执行 SQL 查询。

数据表操作

使用 ORM 模型的最大优势在于:可以像操作 Python 对象一样操作数据库,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 插入数据
new_user = User(username='alice')
db.session.add(new_user)
db.session.commit()

# 查询数据
user = User.query.filter_by(username='alice').first()
print(user.id)

# 更新数据
user.username = 'alice_new'
db.session.commit()

# 删除数据
db.session.delete(user)
db.session.commit()

在这里也可以看到,在使用 Flask 操作数据库时,无论是通过 ORM 还是直接写 SQL,本质上都是在进行一场“对话”——我们与数据库之间开启一次连接,在这次连接中执行若干操作,最后一起提交或撤销。这种对话机制在数据库中被称为“事务”。

事务(transaction) 是指一组数据库操作的最小执行单位,要么全部成功提交(commit()),要么全部撤销回滚(rollback()),保持数据一致性。这就好比一次购物结账流程:选了商品(操作数据),还没付款之前(commit 前)随时可以取消或修改(rollback),只有真正付款后(commit)才算完成。

db.session 是 SQLAlchemy 提供的“会话对象”,是与数据库交互的入口之一,专用于操作 ORM 模型类。可以通过它来新增数据(add() / add_all())、修改对象属性、删除对象(delete())、最终统一提交(commit())或回滚(rollback())。

1
2
3
user = User(username='alice')
db.session.add(user)
db.session.commit() # 提交事务

当处理原生 SQL 时,可以使用 db.engine.connect() 获取底层数据库连接,手动执行 SQL 语句:

1
2
3
4
5
from sqlalchemy import text

with db.engine.connect() as conn:
conn.execute(text("DELETE FROM user WHERE id = 1"))
conn.commit()

这和 db.session 本质上也开启了一个事务,同样需要 commit() 才会生效。

数据库迁移(Database Migration)

在实际开发中,随着业务需求的不断演进,我们的数据库模型结构往往也需要相应调整,比如新增字段、修改字段类型或删除表。这种将 ORM 模型的变更同步应用到数据库结构中的过程,就称为数据库迁移(Migration)

例如,我们在模型类中新增了一个字段:

1
2
3
4
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) # 新增字段

这时候如果再次执行 db.create_all(),数据库是不会自动添加这个新字段的。因为:

  • create_all() 只会在数据库中创建尚不存在的表;
  • 它不会检测或更新已有表的字段结构。

这意味着数据库结构和模型代码将“脱节”,最终导致程序运行报错或数据不一致。

为了解决这个问题,Flask 提供了官方推荐的工具:Flask-Migrate,它基于 SQLAlchemy 的 Alembic 工具,能够自动追踪模型变更并生成对应的迁移脚本。

使用 Flask-Migrate 的步骤:

  1. 在 Flask 应用中初始化迁移支持
1
2
3
from flask_migrate import Migrate

migrate = Migrate(app, db)
  1. 初始化迁移环境(只需执行一次)
1
flask db init

这会生成一个 migrations/ 文件夹,用于记录每次结构变更和版本。

  1. 检测模型变更并生成迁移脚本
1
flask db migrate -m "Add email field to User"

这会自动比较当前数据库结构和模型类的差异,并生成相应 SQL 迁移脚本。-m 参数用于给此次变更命名,就像 Git 的提交信息。

  1. 执行迁移,更新数据库结构
1
flask db upgrade

该命令会将迁移脚本中的结构变更真正应用到数据库。

可以将 migrations/ 文件夹加入 Git 版本控制,这样数据库结构的变更也可以跟随代码同步管理。

Flask CLI 与配置加载机制

在使用上述命令如 flask db migrateflask run 时,Flask CLI 工具需要知道我们的应用是在哪里定义的。也就是说,它要找到那个定义了 Flask(__name__) 实例的文件(例如 app.py),并加载上下文。

默认情况下,如果我们没有设置环境变量 FLASK_APP,Flask 会假设我们的主程序名是 app.py。但更推荐的做法是设置该变量,指明主应用:

1
2
export FLASK_APP=app.py   # Linux/macOS
set FLASK_APP=app.py # Windows

为了避免每次都手动设置环境变量,Flask CLI 会在启动时自动加载项目根目录下的两个文件(如果存在)来设置环境变量:

  • .env:通用环境变量,例如数据库地址、密钥等;
  • .flaskenv:Flask 专用配置,如 FLASK_APP, FLASK_ENV, FLASK_DEBUG 等。

这些文件的格式非常简单:

1
2
3
4
FLASK_APP=app.py
FLASK_ENV=development
DATABASE_URL=sqlite:///my.db
SECRET_KEY=s3cr3t

这种自动加载机制是基于 python-dotenv 实现的,Flask >=1.0 已内置该支持。

而如果使用 python app.py 启动应用,.env.flaskenv 是不会自动加载的,除非显式调用:

1
2
3
from dotenv import load_dotenv
load_dotenv()
load_dotenv('.flaskenv')

这会加载默认的 .env 文件(或手动指定的路径),并将变量写入 os.environ,之后就可以通过 os.getenv() 来访问这些配置值。

项目配置管理

在一个成熟的 Flask 项目中,常常需要处理各种配置参数,例如:

  • 数据库连接字符串
  • 应用密钥
  • 文件上传目录
  • 运行环境(开发 / 生产)
  • 第三方服务密钥(如邮件、Redis)

推荐采用 配置类 + .env 文件 的组合方式:

1
2
3
4
5
project/
├── config/
│ └── settings.py # 定义配置类
├── .env # 存储敏感变量(忽略 Git)
├── app.py # 应用入口

.env 示例内容:

1
2
3
DATABASE_URL=postgresql://user:password@localhost/db
SECRET_KEY=supersecret
FLASK_CONFIG=DevConfig

.env 主要保存的是这些类型的配置,不提交到 Git:

类型 示例
连接信息 数据库、Redis、邮箱等 URI
密钥信息 加密密钥、Token 密钥、第三方 API 密钥
环境信息 开发/生产标志、调试开关
运行参数 主机、端口、默认语言等

config/settings.py 配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os

class Config:
SECRET_KEY = os.getenv("SECRET_KEY", "default-secret")
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL")
UPLOAD_FOLDER = os.getenv("UPLOAD_FOLDER", "./uploads")
DEBUG = False

class DevConfig(Config):
DEBUG = True
ENV = 'development'

class ProdConfig(Config):
ENV = 'production'

class TestConfig(Config):
TESTING = True

app.py 中加载配置:

1
2
3
4
5
6
7
8
9
10
11
12
from flask import Flask
from dotenv import load_dotenv
import os
from config import settings

load_dotenv() # 加载 .env 文件

config_name = os.getenv("FLASK_CONFIG", "DevConfig")
config_class = getattr(settings, config_name)

app = Flask(__name__)
app.config.from_object(config_class)

这样项目就可以根据环境变量动态切换开发、测试或生产配置,结构清晰、灵活可控。

小结

当我们着手开发一个新的 Flask 项目,并计划引入数据库支持时,整体流程可以分为以下几个关键步骤,下面我们以实际开发视角,一步步串起整个数据库操作链条:

🧱 第一步:创建数据库(数据库初始化)

在开始开发前,我们需要先准备好数据库环境:

  • SQLite:不需要提前建库,提供文件路径即可;
  • PostgreSQL / MySQL:需要手动创建数据库,例如使用 SQL 命令:
1
CREATE DATABASE mydb;

此时我们拥有了数据库实体,但还没有表结构。


⚙️ 第二步:配置数据库连接

我们在 Flask 应用中通过配置项 SQLALCHEMY_DATABASE_URI 连接数据库,并初始化 ORM 工具 SQLAlchemy:

1
2
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:pass@localhost/mydb'
db = SQLAlchemy(app)

推荐把这些配置写入 .env 文件,并使用配置类统一管理,这样不同环境之间切换更灵活、敏感信息也更安全。


📐 第三步:设计数据模型并创建数据表

我们通过继承 db.Model 的方式来定义 ORM 数据模型,例如:

1
2
3
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)

然后使用:

1
2
with app.app_context():
db.create_all()

即可在数据库中创建所有定义的模型表。此时数据库结构正式建立完成。


💡 第四步:读写数据库(事务操作)

我们可以使用 db.session 操作模型对象,执行增删改查,并通过 commit() 提交事务:

1
2
3
new_user = User(username='alice')
db.session.add(new_user)
db.session.commit()

所有操作都基于事务机制,可以回滚、批处理,确保数据一致性。


🔁 第五步:支持数据库迁移

随着开发进行,模型结构不可避免会发生变化,比如新增字段、调整索引等。这时候我们使用 Flask-Migrate 工具自动完成结构更新,而不必手写 SQL:

1
2
flask db migrate -m "Add email to User"
flask db upgrade

通过这一机制,数据库结构的演进可以与代码版本一起被管理、回退。


🧩 第六步:项目配置结构与 Flask CLI

为了实现跨环境开发部署、统一管理变量和命令,我们引入如下结构:

1
2
3
4
project/
├── config/settings.py # 配置类(开发、生产、测试)
├── .env # 敏感环境变量(密钥、数据库地址)
├── app.py # 应用主入口

并通过 .flaskenvFLASK_APP 告诉 Flask CLI 主程序位置:

1
2
FLASK_APP=app.py
FLASK_ENV=development

可以通过 flask runflask db 等命令快速操作开发服务与数据库迁移。