如何在Alembic迁移中使用现有的sqlalchemy枚举Postgres

问题描述

在过去的某个时候,我进行了一次像元迁移,该迁移创建了一个users表,例如...

def upgrade():
    ...
    op.create_table(
        "users",sa.Column("id",sa.Integer(),autoincrement=True,nullable=False),...
        sa.Column("type",sa.Enum("Foo","Bar","Baz",name="usertype"),...
    )
    ...

...这将自动创建名为usertype的枚举,其值为"Foo","Baz"

现在,我要创建其他表,该表也引用相同的枚举。例如,

def upgrade():
    ...
    op.create_table('foobar',sa.Column('id',...
        sa.Column('user_type',sa.Enum(< ???????? >),...
    )

引用现有枚举的语法是什么?

我似乎在文档中找不到答案:https://docs.sqlalchemy.org/en/13/core/type_basics.html#sqlalchemy.types.Enum

解决方法

Ali Kazai 的回答几乎是正确的。此解决方案仅适用于 postgres,因此您需要确保导入特定的 postgres 枚举类型。

# This is not the usual sqlalchemy.Enum !
from sqlalchemy.dialects import postgresql

sa.Column('type',postgresql.ENUM('a','b',name='my_enum',create_type=False),nullable=False),
,

我建议不要这样做,因为模型定义和迁移文件之间存在差异。请记住,如果枚举曾经改变过,那么Alembic首先需要检测到枚举已经改变,其次要知道旧值是什么。否则,处理它的唯一可能方法是将列类型更改为VARCHAR,然后再返回到ENUM,但这比仅添加或删除一个更昂贵且痛苦的操作。潜在价值。


假设我们有以下枚举:

class Animal(enum.Enum):
    DOG = 'DOG'
    CAT = 'CAT'
    HAMSTER = 'HAMSTER'

对于postgres,您可以使用sqlalchemy.dialects.postgres.ENUM并将其传递给现有枚举:

animal = Column(ENUM(Animal),nullable=False)

但是flask-migrate(使用alembic)然后写出迁移计划中的值:sa.Column('gender',sa.Enum('DOG','CAT','HAMSTER'))。出于上述原因这样做。


例如,如果您真的想要这样做,例如因为您知道值永远不会改变,则可以使用sa.Enum(*Animal._member_names_),因为Animal._member_names_ = ['DOG','HAMSTER']

,

找不到有关如何修复此错误的太多信息,但您需要执行此操作。

在您自动生成迁移后,只需将 create_type=False 添加到迁移文件中的枚举字段即可。

sa.Column('user_type',sa.Enum(< ???????? >,