【问题标题】:sqlalchemy postgresql enum does not create type on db migratesqlalchemy postgresql 枚举不会在 db migrate 上创建类型
【发布时间】:2016-10-17 08:36:04
【问题描述】:

我在 Python3 下使用 Flask 开发了一个网络应用程序。我在 db migrate/upgrade 上遇到了 postgresql 枚举类型的问题。

我在模型中添加了“状态”列:

class Banner(db.Model):
    ...
    status = db.Column(db.Enum('active', 'inactive', 'archive', name='banner_status'))
    ...

python manage.py db migrate 生成的迁移是:

from alembic import op
import sqlalchemy as sa

def upgrade():
    op.add_column('banner', sa.Column('status', sa.Enum('active', 'inactive', 'archive', name='banner_status'), nullable=True))

def downgrade():
    op.drop_column('banner', 'status')

当我执行python manage.py db upgrade 时,我得到一个错误:

...
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) type "banner_status" does not exist
LINE 1: ALTER TABLE banner ADD COLUMN status banner_status

 [SQL: 'ALTER TABLE banner ADD COLUMN status banner_status']

为什么迁移不创建类型“banner_status”?

我做错了什么?

$ pip freeze
alembic==0.8.6
Flask==0.10.1
Flask-Fixtures==0.3.3
Flask-Login==0.3.2
Flask-Migrate==1.8.0
Flask-Script==2.0.5
Flask-SQLAlchemy==2.1
itsdangerous==0.24
Jinja2==2.8
Mako==1.0.4
MarkupSafe==0.23
psycopg2==2.6.1
python-editor==1.0
requests==2.10.0
SQLAlchemy==1.0.13
Werkzeug==0.11.9

【问题讨论】:

标签: flask sqlalchemy flask-sqlalchemy flask-migrate sqlalchemy-migrate


【解决方案1】:

我用那个来解决这个问题。

我更改了迁移代码,迁移代码如下:

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

def upgrade():
    banner_status = postgresql.ENUM('active', 'inactive', 'archive', name='banner_status')
    banner_status.create(op.get_bind())

    op.add_column('banner', sa.Column('status', sa.Enum('active', 'inactive', 'archive', name='banner_status'), nullable=True))

def downgrade():
    op.drop_column('banner', 'status')

    banner_status = postgresql.ENUM('active', 'inactive', 'archive', name='banner_status')
    banner_status.drop(op.get_bind())

现在python manage.py db upgrade\downgrade 已成功执行。

【讨论】:

  • 对于降级,您还可以通过直接执行 SQL 来避免重复(至少对于 postgres):op.execute("DROP TYPE banner_status;")
  • @Geekfish 为什么不在升级和降级方法之外移动postgresql.ENUM('active', 'inactive', 'archive', name='banner_status')?会有什么缺点吗?
  • @Jatimir 我已经有一段时间没有研究过了,但你的建议可能没问题!
  • 您实际上可以将banner_status 作为列类型直接传递,而不是通过sa.Enum(...) 重新定义它
  • 降级时不需要声明所有枚举选项,只需bind = op.get_bind() 然后sa.Enum(name='banner_status').drop(bind, checkfirst=False)
【解决方案2】:

我觉得这种方式比较简单:

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

def upgrade():
    # others_column = ...
    banner_status = postgresql.ENUM('active', 'inactive', 'archive', name='banner_status', create_type=False), nullable=False)

如果需要,还可以将 postgresql.ENUM 添加到您的 downgrade() 函数中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-04
    • 2022-01-09
    • 2021-03-17
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多