flask-sql_alchemy和flask-migrate在 Flask + 数据库 体系里几乎是“标配搭子”,如果把开发 Web 应用比作盖房子,那么 SQLAlchemy 就是施工图纸和建筑材料,而 Flask-Migrate 就是装修进度管理手册。
Flask 与 SQLAlchemy 的“神仙搭档”
1 Flask
在谈SQLAlchemy之前,需要先了解Flask。Flask 是一个用 Python 编写的 微框架(Microframework)。它的核心设计哲学是“保持简单,易于扩展”:
- 轻量: 它只提供 Web 开发的核心功能(路由、请求处理、模板引擎),不强制你使用特定的数据库或账号系统。
- 灵活: 你可以自由选择喜欢的工具(比如用 SQLAlchemy 连数据库,用 WTForms 搞表单)。
- 易上手: 几行代码就能跑起一个 Web 服务器。
2 SQLAlchemy
SQLAlchemy 是一个功能强大的 ORM(对象关系映射) 库。
- 核心功能: 让你用 Python 类来操作数据库,而不是写原生的 SQL 语句。
- 它的职责:
- 映射: 把 Python 的类映射成数据库里的表,把类实例映射成表里的一行数据。
- 抽象: 你不需要关心底层是 MySQL、PostgreSQL 还是 SQLite,SQLAlchemy 会帮你翻译成对应的语法。
- 操作: 增删改查(CRUD)全部通过 Python 方法完成,例如
user.save()或User.query.all()。
3 Flask和SQLAlchemy
在 Flask 中,我们通常使用它的扩展版 Flask-SQLAlchemy这个扩展插件与 SQLAlchemy 深度集成。
Flask-SQLAlchemy = SQLAlchemy + Flask 适配层
它帮开发者解决了:
- 数据库连接生命周期
- app / request 上下文绑定
- session 管理
- 简化配置
它们之间的搭配就像是 “大脑”与“管家” 的关系:
1. 结构上的互补
- Flask (大脑): 负责接收用户的 HTTP 请求(比如:用户点击了“注册”按钮),并决定返回什么页面。
- SQLAlchemy (管家): 负责处理繁琐的数据库交互。大脑告诉它“存一下这个用户信息”,管家就去处理 SQL 语句并和数据库对接。
2. 开发模式:模型驱动
在 Flask 项目中,你不需要去数据库里敲 CREATE TABLE。你会通过 SQLAlchemy 定义一个 Model(模型):
Python
# 这是一个典型的 Flask-SQLAlchemy 模型定义
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True)这样一来,就可以用 Python 对象的方式操作数据库,而不是手写 SQL。
3. 数据流转过程
当一个请求进来时,它们的协作流程如下:
- 路由接收 (Flask): 用户访问
/profile/1。 - 查询数据 (SQLAlchemy): Flask 调用
User.query.get(1)。SQLAlchemy 自动将其翻译成SELECT * FROM user WHERE id = 1。 - 返回结果: SQLAlchemy 返回一个 Python 对象,Flask 将其中的数据塞进 HTML 模板展示给用户。
4 核心配置示例
要把它们配成对,通常只需要三步:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 1. 告诉 Flask 数据库在哪里
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
# 2. 初始化插件
db = SQLAlchemy(app)
# 这是一个典型的 Flask-SQLAlchemy 模型定义
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True)
# 3. 愉快地使用!
@app.route('/')
def index():
users = User.query.all() # 直接调用模型查询
return f"总共有 {len(users)} 个用户"Flask-Migrate: 数据库的“后悔药” (Migration)
虽然 SQLAlchemy 可以帮你创建表(通过 db.create_all()),但它有一个致命弱点:它不会更新表。如果你给 User 类增加了一个 email 字段,db.create_all() 会直接忽略它,除非你删掉数据库重新来。
这就是 Flask-Migrate 出场的时候了,它是是数据库「版本管理 / 迁移工具:
- 核心功能: 基于 Alembic 引擎,Alembic 是 SQLAlchemy 官方的迁移工具,记录数据库结构的所有变更。
- 它的职责:
- 版本控制: 就像 Git 管理代码一样,它管理数据库的 Schema(模式)。
- 平滑升级: 在保留数据库现有数据的情况下,增加字段、修改约束或删除列。
- 回滚: 如果这次改动导致程序崩了,你可以一键“撤销”回到上一个版本。
1 Flask-Migrate运行过程
当你输入那些 flask db 命令时,可以拆解为四个关键阶段。
1. 初始化阶段:建立仓库 (init)
执行命令: flask db init
执行 flask db init 后会在项目中创建数据库迁移相关的文件结构,即在你的项目根目录下创建一个migrations 目录,其中包含:
- versions/ - 存放迁移脚本的目录
- alembic.ini - Alembic 配置文件
- env.py - 迁移环境配置
- script.py.mako - 迁移脚本模板
这些文件会被 Flask-Migrate (基于 Alembic) 用来:跟踪数据库 schema 的变化、生成迁移脚本、管理数据库版本
2. 检测阶段:发现差异 (migrate)
执行命令: flask db migrate -m "说明文字"
这是最核心的一步,它的运行逻辑如下:
- 扫描模型: Flask-Migrate 会去查看你代码里定义的 SQLAlchemy 模型(即那些继承自
db.Model的类)。 - 查看数据库: 检查数据库当前的状态(它会查看数据库中一个叫
alembic_version的特殊表)。 - 计算差值(Diff): 对比两者的结构。比如,你在模型里增加了一个
phone字段,但数据库表里没有。 - 生成脚本: 自动在
migrations/versions/下生成一个 Python 脚本。这个脚本包含两个函数:upgrade(): 描述如何把数据库升级到新版本(例如:op.add_column(...))。downgrade(): 描述如何撤销这次改动(例如:op.drop_column(...))。
3. 执行阶段:物理改动 (upgrade)
执行命令: flask db upgrade
这一步才是真正“动刀子”修改数据库表结构的时候。
- 动作: 读取最新的迁移脚本,执行其中的
upgrade()函数。 - 结果: 数据库表结构被修改。同时,数据库里的
alembic_version表会更新为一个新的哈希值(版本号),确保下次迁移时知道从哪开始。
4. 撤销阶段:时空回溯 (downgrade)
执行命令: flask db downgrade
如果你发现刚才的改动有问题(比如删错了字段),可以使用这个命令。
- 动作: 执行脚本中的
downgrade()函数。 - 结果: 数据库回退到上一个版本。
2 常见问题
1. 模型类没有正确导入
有时候修改了模型,运行 migrate 却提示 “No changes detected”。 这通常是因为:
- 忘记在
app.py或初始化的地方import你的模型类,导致 Flask-Migrate 没能发现它们。 - 没有正确设置
db = SQLAlchemy(app)中的app上下文。
在执行flask db命令前,需要保证所有的模型类被 Python 先加载到内存中。这就是为什么通常建议在model模块的 __init__.py 中导入所有模型,以确保它们在应用启动时就被正确注册。