那个令人头疼的 Alembic NotNullViolation 错误(以及如何应对)
Source: Dev.to
发生了什么?
想象一下,你有一个名为 organizations 的表,里面存放着宝贵的数据。你决定添加一个名为 plan 的新列。
如果把它设为 NOT NULL,每一行都必须有值。但表里已经有数据了,PostgreSQL 会拒绝这次更改:
向已有数据的表添加 NOT NULL 列而不提供默认值,基本上就像让人填写一份事先没有发给他们的调查问卷。他们不知道该怎么回答,于是就慌了。
快速解决方案:添加默认值
op.add_column(
'organizations',
sa.Column('plan', sa.String(), nullable=False, server_default='free')
)
- 已有行会自动得到值
'free'。 - 迁移完成后,如果你愿意,可以移除默认值。
更可控的做法:先可为空,再填充值
# 1. 将列添加为可为空
op.add_column(
'organizations',
sa.Column('plan', sa.String(), nullable=True)
)
UPDATE organizations SET plan = 'free' WHERE plan IS NULL;
# 3. 将列改为 NOT NULL
op.alter_column('organizations', 'plan', nullable=False)
- 这样可以在强制 NOT NULL 约束之前,对每行应用自定义逻辑。
迁移前的手动准备
- 手动更新表(例如使用
UPDATE语句)。 - 运行将列添加为 NOT NULL 的 Alembic 迁移。
旧行已经准备好,PostgreSQL 就不会再抛出错误。
向已有行的表中添加 NOT NULL 列,就像在拥挤的派对上增设新规则:如果你不提供方案,必然会有人不满。务必考虑已有数据——给 PostgreSQL 设置默认值、更新旧行,或两者兼顾。
Alembic 错误看起来很吓人,但其实它们只是数据库在说:
“嘿,我太爱你的数据了,不能让它坏掉。我们一起把事情做好吧。”