Alembic 在 SQLite 中怎么批量修改列约束
来源:17golang原创
时间:2026-11-11 07:46:44 341浏览 收藏
在 SQLite 中用 Alembic 修改列约束,核心不是手写一条不存在的 ALTER COLUMN,而是把变更放进 op.batch_alter_table()。对需要重建的操作,Alembic 会按新结构创建临时表、复制旧数据、替换旧表。这样可以把“改 nullable”和“增加 CHECK”写成可审查的迁移脚本。
官方地址:https://alembic.sqlalchemy.org/
下面只讨论表结构迁移,不把业务数据清洗混进迁移脚本。假设 user_account.email 允许为空,现在要改成必填,并给 age 加上非负约束。
先判断:为什么 SQLite 要用 batch 模式
SQLite 的 ALTER TABLE 主要覆盖重命名表、重命名列、添加列和删除列;修改已有列的约束通常不能直接套用其他数据库的写法。Alembic 的 batch 模式把一组单表操作集中起来,在 SQLite 上采用“新表 + INSERT ... SELECT + 替换”的方式完成迁移。
因此,batch_alter_table 不是单纯的语法糖。它明确告诉迁移工具:这些变化要以表结构为整体处理。默认 recreate="auto" 会在 SQLite 遇到需要重建的操作时启用重建;为了让迁移意图更直观,也可以显式写成 recreate="always"。

用一个 batch 块批量修改列约束
修改已有列时,建议同时写出 existing_type 和 existing_nullable。它们让 Alembic 在反射旧表和生成新表时有明确的旧结构信息,尤其适合类型、默认值和可空性一起变化的场景。
from alembic import op
import sqlalchemy as sa
def upgrade():
# SQLite 需要按新表结构重建,统一承载多个约束变化
with op.batch_alter_table("user_account", recreate="always") as batch_op:
# 先声明旧类型和旧可空性,避免迁移信息不完整
batch_op.alter_column(
"email",
existing_type=sa.String(length=255),
existing_nullable=True,
nullable=False,
)
# CHECK 约束要有稳定名称,后续才能精确删除或调整
batch_op.create_check_constraint(
"ck_user_account_age_nonnegative",
sa.text("age >= 0"),
)
def downgrade():
# 回滚时恢复可空性,并删除同名 CHECK 约束
with op.batch_alter_table("user_account", recreate="always") as batch_op:
batch_op.drop_constraint(
"ck_user_account_age_nonnegative", type_="check"
)
batch_op.alter_column(
"email",
existing_type=sa.String(length=255),
existing_nullable=False,
nullable=True,
)
这里的“批量”指同一个表的多项结构变化被一次 batch 操作处理,不是把多张表塞进一个上下文。迁移前必须确认现有行没有 NULL 邮箱,也没有负年龄;否则新表的约束会让数据复制阶段失败。
类型、默认值和约束名称要写完整
如果同时改类型或服务端默认值,继续补齐 existing_server_default、type_ 等旧值信息。不要只写 nullable=False 就假设 Alembic 能推断所有旧元数据;反射结果、方言和命名约定都会影响重建表的最终定义。
SQLite 反射出的部分约束可能没有名字。需要删除或替换 CHECK、外键时,优先在模型和迁移中建立命名约定,或者在 batch 上提供 naming_convention。没有稳定名称时,drop_constraint() 很难准确定位目标。
from alembic import op
import sqlalchemy as sa
def upgrade():
# 命名约定帮助反射后的无名约束获得可操作的名字
convention = {
"ck": "ck_%(table_name)s_%(constraint_name)s",
}
with op.batch_alter_table(
"user_account",
recreate="always",
naming_convention=convention,
) as batch_op:
# 类型变化时保留旧类型,避免生成的 CREATE TABLE 缺少上下文
batch_op.alter_column(
"age",
existing_type=sa.Integer(),
type_=sa.SmallInteger(),
existing_nullable=True,
)
如果约束表达式依赖旧列名、索引或外键,先把依赖关系列出来,再决定是否拆成多个迁移。不要把数据回填、删除脏数据和结构替换混在同一个示例里,这些属于不同的发布风险。

让 autogenerate 生成 batch 结构
项目使用自动生成时,在 Alembic 的 env.py 配置 render_as_batch=True:
context.configure(
connection=connection,
target_metadata=target_metadata,
# 让自动生成的单表变化使用 batch 代码形态
render_as_batch=True,
)
自动生成的结果仍然需要人工调整,特别是新约束的名称、旧类型和已有数据是否满足目标条件。batch 上下文默认只在 SQLite 需要时执行重建;如果显式使用 recreate="always",其他数据库也会走复制替换路径,不能无条件照搬。
发布前的四项检查
- 数据兼容:新
NOT NULL或 CHECK 是否会拒绝已有行。 - 对象依赖:索引、触发器、视图和外键是否会随表重建正确恢复。
- 锁与空间:复制整表会产生额外 I/O、临时空间和写锁,生产库要安排窗口。
- 回滚路径:
downgrade()是否使用同一个约束名,并能恢复旧的 nullable/type。
记住这个判断:只要修改的是 SQLite 不擅长直接 ALTER 的列约束,就优先用命名清晰的 batch_alter_table,把旧结构、目标结构和数据兼容条件写在迁移代码附近。
常见问题
只改 nullable 也要 recreate 吗? 通常要。SQLite 的列约束变化属于需要新表定义的操作,使用 batch 能让 Alembic 统一处理。
为什么一定要给 CHECK 起名字? 因为后续删除或调整约束需要稳定标识;无名约束在反射和回滚时不容易精确匹配。
-
413 收藏
-
303 收藏
-
119 收藏
-
413 收藏
-
184 收藏
-
139 收藏
-
444 收藏
-
200 收藏
-
文章 · python教程 | 28分钟前 | 事务 · python · sqlalchemy · 数据库迁移 · sqlalchemy TEXT Alembic bindParam 参数化SQL op.get_bind 迁移脚本371 收藏
-
247 收藏
-
496 收藏
-
389 收藏
-
389 收藏
-
456 收藏
-
文章 · python教程 | 19小时前 | python · Python global Symbol nonlocal symtable SymbolTable is_free is_global248 收藏
-
265 收藏
-
464 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习