Postgres/SQLAlchemy/Alembic 将数据类型从枚举更改为整数并使用映射值
Postgres/SQLAlchemy/Alembic change datatype from enum to int and map value with using
我一直在使用 SQLAlchemy 和 Alembic 迁移以及后端的 Postgres 数据库。我一直在一些 DB 模型中使用枚举作为数据类型,并且我一直在 SQLAlchemy 中使用枚举类型,并且(因此)也在 Postgres 中使用。在整个持续开发过程中,出于一些较小的原因(包括添加新值时具有更高的灵活性,这将需要立即进行数据库迁移以更改数据类型并更改 alembic 中的那些相当复杂且无论如何,对于其他数据库系统来说,枚举似乎比整数更少table)。因此,我必须创建一个迁移,使用 alembic 迁移将枚举列的数据类型更改为 int。
遗憾的是,我还没有找到任何转换方法,可以让我在整个迁移过程中保留旧值。我一直在使用 IntEnums,它将枚举值映射到 python 中的整数,但 Postgres 不在内部使用此映射,因此在将枚举转换为整数时它没有关于枚举的假定值的信息。从我的角度来看,在应用 alter table 查询时,我必须以某种方式提供枚举名称到整数的显式映射。 Postgres 提供了 using 语句,但我一直无法找到如何使用它来将值从我的枚举值映射到 python 一直在使用的 new/old 整数值。
如果我必须手动为它提供映射,那么如果它应该将旧的(基于枚举的)值映射到新的(基于 int 的)值,那么这样的 using 语句应该是什么样子?
此类枚举的示例:
class SexEnum(enum.IntEnum):
male = 0
female = 1
列(数据库中的旧列):
sex = db.Column(db.Enum(SexEnum))
列(新):
sex = db.Column(db.Integer)
现在的迁移命令:
op.alter_column('users', 'sex',
type_=sa.Integer, postgresql_using='null')
Null 可能必须用其他东西替换。
此外,应该注意的是,如果迁移尽可能与其他数据库系统兼容,那就太好了,这将迫使我使用另一个系统而不是 using 语句,不是吗?
好的,找到了。感谢 Ilja 为 CASE 提供的提示。
基本上用
替换了'null'
'(CASE sex WHEN \'male\'... END)'
无需以另一种方式设置所有这些值即可使迁移生效。我不认为这完全满足我的可移植性要求,只是因为我仍在使用 postgres 的 using 子句。除此之外,简单的 case 语句有效。
我一直在使用 SQLAlchemy 和 Alembic 迁移以及后端的 Postgres 数据库。我一直在一些 DB 模型中使用枚举作为数据类型,并且我一直在 SQLAlchemy 中使用枚举类型,并且(因此)也在 Postgres 中使用。在整个持续开发过程中,出于一些较小的原因(包括添加新值时具有更高的灵活性,这将需要立即进行数据库迁移以更改数据类型并更改 alembic 中的那些相当复杂且无论如何,对于其他数据库系统来说,枚举似乎比整数更少table)。因此,我必须创建一个迁移,使用 alembic 迁移将枚举列的数据类型更改为 int。
遗憾的是,我还没有找到任何转换方法,可以让我在整个迁移过程中保留旧值。我一直在使用 IntEnums,它将枚举值映射到 python 中的整数,但 Postgres 不在内部使用此映射,因此在将枚举转换为整数时它没有关于枚举的假定值的信息。从我的角度来看,在应用 alter table 查询时,我必须以某种方式提供枚举名称到整数的显式映射。 Postgres 提供了 using 语句,但我一直无法找到如何使用它来将值从我的枚举值映射到 python 一直在使用的 new/old 整数值。
如果我必须手动为它提供映射,那么如果它应该将旧的(基于枚举的)值映射到新的(基于 int 的)值,那么这样的 using 语句应该是什么样子?
此类枚举的示例:
class SexEnum(enum.IntEnum):
male = 0
female = 1
列(数据库中的旧列):
sex = db.Column(db.Enum(SexEnum))
列(新):
sex = db.Column(db.Integer)
现在的迁移命令:
op.alter_column('users', 'sex',
type_=sa.Integer, postgresql_using='null')
Null 可能必须用其他东西替换。
此外,应该注意的是,如果迁移尽可能与其他数据库系统兼容,那就太好了,这将迫使我使用另一个系统而不是 using 语句,不是吗?
好的,找到了。感谢 Ilja 为 CASE 提供的提示。
基本上用
替换了'null''(CASE sex WHEN \'male\'... END)'
无需以另一种方式设置所有这些值即可使迁移生效。我不认为这完全满足我的可移植性要求,只是因为我仍在使用 postgres 的 using 子句。除此之外,简单的 case 语句有效。