sqlalchemy postgresql枚举不会在db migrate上创建类型

Mea*_*bot 25 sqlalchemy sqlalchemy-migrate flask flask-sqlalchemy flask-migrate

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

我在模型中添加了一个"状态"列:

class Banner(db.Model):
    ...
    status = db.Column(db.Enum('active', 'inactive', 'archive', name='banner_status'))
    ...
Run Code Online (Sandbox Code Playgroud)

生成的迁移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')
Run Code Online (Sandbox Code Playgroud)

当我这样做时,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']
Run Code Online (Sandbox Code Playgroud)

为什么迁移不会创建类型"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
Run Code Online (Sandbox Code Playgroud)

Mea*_*bot 53

我用这个决定了这个问题.

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

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())
Run Code Online (Sandbox Code Playgroud)

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

  • 对于降级,您还可以通过直接执行SQL来避免重复(至少对于postgres):`op.execute("DROP TYPE banner_status;")` (9认同)
  • 实际上,您可以直接将“banner_status”作为列类型传递,而不是通过“sa.Enum(...)”重新定义它 (3认同)
  • @Geekfish为什么不将 `postgresql.ENUM('active', 'inactive', 'archive', name='banner_status')` 移到升级和降级方法之外?会有什么缺点吗? (2认同)
  • 您不需要在降级时声明所有枚举选项,只需 `bind = op.get_bind()` 然后 `sa.Enum(name='banner_status').drop(bind, checkfirst=False)` (2认同)