簡體   English   中英

如何在 Alembic 遷移 (Postgres) 中使用現有的 sqlalchemy 枚舉

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

在過去的某個時候,我運行了一個 alembic 遷移,它創建了一個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"), nullable=False),
        ...
    )
    ...

...它會自動創建名為usertype的枚舉,其值為"Foo", "Bar", "Baz"

現在,我想制作一些其他表,它也引用了相同的枚舉。 例如,

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

引用現有枚舉的語法是什么?

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

Postgres 有兩個部分可以實現這一點。

  1. 指定create_type=False
  2. 使用sqlalchemy.dialects.postgresql.Enum (不是sqlalchemy.Enum

例如:

from sqlalchemy.dialects import postgresql

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

我建議不要這樣做,因為 model 定義和遷移文件之間存在差異。 請記住,如果枚舉發生了變化,那么 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', 'CAT', 'HAMSTER']

找不到有關如何修復此錯誤的太多信息,但這是您需要做的。

自動生成遷移后,只需將 create_type=False, 添加到遷移文件中的枚舉字段。

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

您可能需要傳遞枚舉 object 而不是其名稱作為字符串。

    entity = Column(
        postgresql.ENUM(
            SocialType,
            create_type=False,
            checkfirst=True,
            inherit_schema=True,
        )
    )

checkfirst=Truecreate_type=False不會被 alembic 檢測到。 所以需要手動添加。 最后,alembic 遷移應該看起來像

sa.Column('entity', postgresql.ENUM('github', 'twitter', name='socialtype', schema='dashboard', inherit_schema=True, create_type=False, checkfirst=True), nullable=True),

有關此問題的簡單、有效且與后端無關的解決方案,請在另一個線程中查看我的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM