python - 使用 Alembic 更改枚举字段

标签 python postgresql sqlalchemy alembic

当使用早于 9.1 的 PostgreSQL 版本(为枚举添加 ALTER TYPE)时,如何在 alembic 迁移中将元素添加到 Enum 字段? This SO question解释了直接过程,但我不太确定如何最好地使用alembic进行翻译。

这就是我所拥有的:

new_type = sa.Enum('nonexistent_executable', 'output_limit_exceeded',
                   'signal', 'success', 'timed_out', name='status')
old_type = sa.Enum('nonexistent_executable', 'signal', 'success', 'timed_out',
                   name='status')
tcr = sa.sql.table('testcaseresult',
                   sa.Column('status', new_type, nullable=False))


def upgrade():
    op.alter_column('testcaseresult', u'status', type_=new_type,
                    existing_type=old_type)


def downgrade():
    op.execute(tcr.update().where(tcr.c.status==u'output_limit_exceeded')
               .values(status='timed_out'))
    op.alter_column('testcaseresult', u'status', type_=old_type,
                    existing_type=new_type)

不幸的是,上面的内容只在升级时产生 ALTER TABLE testcaseresult ALTER COLUMN status TYPE status,基本上什么都不做。

最佳答案

我决定尝试关注 postgres approach尽可能直接并提出以下迁移。

from alembic import op
import sqlalchemy as sa

old_options = ('nonexistent_executable', 'signal', 'success', 'timed_out')
new_options = sorted(old_options + ('output_limit_exceeded',))

old_type = sa.Enum(*old_options, name='status')
new_type = sa.Enum(*new_options, name='status')
tmp_type = sa.Enum(*new_options, name='_status')

tcr = sa.sql.table('testcaseresult',
                   sa.Column('status', new_type, nullable=False))


def upgrade():
    # Create a tempoary "_status" type, convert and drop the "old" type
    tmp_type.create(op.get_bind(), checkfirst=False)
    op.execute('ALTER TABLE testcaseresult ALTER COLUMN status TYPE _status'
               ' USING status::text::_status')
    old_type.drop(op.get_bind(), checkfirst=False)
    # Create and convert to the "new" status type
    new_type.create(op.get_bind(), checkfirst=False)
    op.execute('ALTER TABLE testcaseresult ALTER COLUMN status TYPE status'
               ' USING status::text::status')
    tmp_type.drop(op.get_bind(), checkfirst=False)


def downgrade():
    # Convert 'output_limit_exceeded' status into 'timed_out'
    op.execute(tcr.update().where(tcr.c.status==u'output_limit_exceeded')
               .values(status='timed_out'))
    # Create a tempoary "_status" type, convert and drop the "new" type
    tmp_type.create(op.get_bind(), checkfirst=False)
    op.execute('ALTER TABLE testcaseresult ALTER COLUMN status TYPE _status'
               ' USING status::text::_status')
    new_type.drop(op.get_bind(), checkfirst=False)
    # Create and convert to the "old" status type
    old_type.create(op.get_bind(), checkfirst=False)
    op.execute('ALTER TABLE testcaseresult ALTER COLUMN status TYPE status'
               ' USING status::text::status')
    tmp_type.drop(op.get_bind(), checkfirst=False)

似乎 alembic 在其 alter_table 方法中没有直接支持 USING 语句。

关于python - 使用 Alembic 更改枚举字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14845203/

相关文章:

python - 从 Selenium IDE 到 Python - 没有这样的元素

python - Tornado 'Hello World' 错误

python - 在 Flask-Celery 中收到类型为 ""的未注册任务

postgresql - 将 PostgreSQL 9.6.5 升级到 10.1 时性能大幅下降

python - 如何按字母在前的字符串列排序?

Python Flask 捕获多个完整性错误 = 如果用户或电子邮件引发完整性错误,则会出现不同的错误消息

python - 用于文章的超长文本的 SQLalchemy 类型

python - 从 pypcapfile 中的 TCP header 获取 ByteArray

postgresql - 如何在 Mac OS X 上运行两个 PostgreSQL 副本?

用于更新 postgres 数据库的 bash 脚本