Alembic 在 SQLite 中怎么批量修改列约束
在 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 起名字? 因为后续删除或调整约束需要稳定标识;无名约束在反射和回滚时不容易精确匹配。
Python ast.NodeTransformer 修改语法树后怎么补齐位置信息
- 上一篇
- Python ast.NodeTransformer 修改语法树后怎么补齐位置信息
- 下一篇
- Alembic 迁移脚本怎么执行带参数的 SQL
-
- 文章 · python教程 | 12分钟前 | 类型转换 · pyarrow 安全转换 整数溢出 compute.cast CastOptions Arrow类型
- PyArrow compute.cast 溢出时怎么选择安全转换策略
- 139浏览 收藏
-
- 文章 · python教程 | 12分钟前 |
- PyArrow write_dataset 怎么限制每个 Parquet 文件的行数
- 444浏览 收藏
-
- 文章 · python教程 | 13分钟前 | python · Python pyarrow table ChunkedArray combine_chunks
- PyArrow Table 怎么合并多个 ChunkedArray 以便连续读取
- 200浏览 收藏
-
- 文章 · python教程 | 16分钟前 | 事务 · python · sqlalchemy · 数据库迁移 · sqlalchemy TEXT Alembic bindParam 参数化SQL op.get_bind 迁移脚本
- Alembic op.get_bind 怎么在迁移脚本中执行参数化 SQL
- 371浏览 收藏
-
- 文章 · python教程 | 23分钟前 | python · 数据库迁移 · Python sqlalchemy Alembic Operations.execute 参数化SQL
- Alembic 迁移脚本怎么执行带参数的 SQL
- 496浏览 收藏
-
- 文章 · python教程 | 29分钟前 | python · Python ast NodeTransformer fix_missing_locations
- Python ast.NodeTransformer 修改语法树后怎么补齐位置信息
- 389浏览 收藏
-
- 文章 · python教程 | 18小时前 |
- Python bisect 的 key 函数重复开销怎样减少
- 389浏览 收藏
-
- 文章 · python教程 | 19小时前 | Python 空格 tokenize untokenize 源码改写
- Python tokenize.untokenize 为什么不能保证恢复原始空格
- 265浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 977次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 983次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1099次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1070次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 908次使用
-
- mysql大数据表怎么优化分页性能?优化方法分享
- 2023-01-22 413浏览
-
- 一次使用 SQLAlchemy 实现分类以及计数的业务过程
- 2023-01-18 303浏览
-
- sql to sqlalchemy 实例教程
- 2023-02-16 119浏览
-
- Python-SQLALchemy
- 2023-02-24 413浏览
-
- SQLAlchemy入门(一)
- 2023-01-22 184浏览
