How to use an existing sqlalchemy Enum in an Alembic migration (Postgres)

懵懂的女人 提交于 2021-01-27 13:00:53

问题


At some point in the past I've run an alembic migration which creates a users table like...

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"), nullable=False),
        ...
    )
    ...

...which automatically creates the enum named usertype with the values "Foo", "Bar", "Baz".

Now, I want to make some other table which also references that same enum. e.g.,

def upgrade():
    ...
    op.create_table('foobar',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        ...
        sa.Column('user_type', sa.Enum(< ???????? >), nullable=False),
        ...
    )

What is the syntax to reference the existing enum?

I can't seem to find an answer in the docs: https://docs.sqlalchemy.org/en/13/core/type_basics.html#sqlalchemy.types.Enum


回答1:


I'd advise against that, as there is a difference between the model definition and the migration files. Keep in mind that if the enum ever changes, then Alembic needs to, firstly, detect that the enum has changed, and, secondly, know what the old values were. Otherwise, the only possible way to deal with it is to change the column type to something like VARCHAR and then back to ENUM, but that is a much more expensive and painful operation than just adding or removing one potential value.


Suppose we have the following enum:

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

For postgres specifically, you can use sqlalchemy.dialects.postgres.ENUM and pass it an existing enum:

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

But flask-migrate (which uses alembic) then writes out the values in the migration plan: sa.Column('gender', sa.Enum('DOG', 'CAT', 'HAMSTER')). It does this for the reason stated above.


If you really want to this, for example because you know the values will never change, you can use sa.Enum(*Animal._member_names_), since Animal._member_names_ = ['DOG', 'CAT', 'HAMSTER'].




回答2:


Couldn't find much information on how to fix this error but here is what you need to do.

after you autogenerated the migration just add create_type=False, to the enum field in the migration file.

sa.Column('user_type', sa.Enum(< ???????? >, create_type=False), nullable=False),


来源:https://stackoverflow.com/questions/63461381/how-to-use-an-existing-sqlalchemy-enum-in-an-alembic-migration-postgres

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!