这最初发布在我自己的博客这里

最近在工作中,我花了一些时间在一个脚手架项目上,我们将用于我们将要构建的 API 项目。

出于多种原因,我们决定使用 Python 作为我们的后端语言,使用 Flask 作为我们的 API 框架。我最喜欢 Flask 的一件事是它非常独立,让你构建你想要的东西,几乎是你想要的东西。

我一直在研究的功能之一是审核日志。出于数据完整性的目的,我们决定在代码本身和数据库中都为event type值使用枚举字段。像许多 Flask 应用程序一样,我们使用 SQLAlchemy 作为 ORM 和 Flask-Migrate 来自动创建 Alembic 迁移。使用字段类型设置为枚举等于代码中使用的枚举的 SQLAlchemy 模型,我曾期望 Flask-Migrate 在我们向 EventType 枚举类添加值时自动创建新迁移,但事实并非如此.

经过一番搜索,我发现这是 Alembic 的一个已知问题,必须手动创建枚举更改的迁移。我在下面手动创建了一个示例迁移以及一些步骤,因此您可以了解如何在 Flask 中处理从枚举中添加或删除值。请注意,此迁移是专门为与 PostgreSQL 一起工作而编写的,因为这是我们使用的数据库引擎。

1.对相关模型中的Enum进行修改

2.创建一个空的迁移文件

flask db revision -m 'Add Logout_Success to AuditEvent'

  1. 使用代码填充新迁移以创建更改,请注意,您需要为现有选项和新选项添加值,以确保保留新迁移文件中已存在的修订和 down_revision 编号
"""
Add Logout_Success to AuditEvent

Revision ID: 08720b8a9d11
Revises: 810eac468f83
Create Date: 2020-03-25 12:19:09.432635

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '08720b8a9d11'
down_revision = '810eac468f83'
branch_labels = None
depends_on = None

# Enum 'type' for PostgreSQL
enum_name = 'auditevent'
# Set temporary enum 'type' for PostgreSQL
tmp_enum_name = 'tmp_' + enum_name

# Options for Enum
old_options = ('LOGIN_SUCCESS', 'LOGIN_FAIL')
new_options = sorted(old_options + ('LOGOUT_SUCCESS',))

# Create enum fields
old_type = sa.Enum(*old_options, name=enum_name)
new_type = sa.Enum(*new_options, name=enum_name)

def upgrade():
    # Rename current enum type to tmp_
    op.execute('ALTER TYPE ' + enum_name + ' RENAME TO ' + tmp_enum_name)
    # Create new enum type in db
    new_type.create(op.get_bind())
    # Update column to use new enum type
    op.execute('ALTER TABLE audit ALTER COLUMN event_type TYPE ' + enum_name + ' USING event_type::text::' + enum_name)
    # Drop old enum type
    op.execute('DROP TYPE ' + tmp_enum_name)


def downgrade():
    # Instantiate db query
    audit = sa.sql.table('audit', sa.Column('event_type', new_type, nullable=False))
    # Convert LOGOUT_SUCCESS to LOGIN_SUCCESS (this is just a sample so may not make sense)
    op.execute(audit.update().where(audit.c.event_type == u'LOGOUT_SUCCESS').values(event_type='LOGIN_SUCCESS'))
    # Rename enum type to tmp_
    op.execute('ALTER TYPE ' + enum_name + ' RENAME TO ' + tmp_enum_name)
    # Create enum type using old values
    old_type.create(op.get_bind())
    # Set enum type as type for event_type column
    op.execute('ALTER TABLE audit ALTER COLUMN event_type TYPE ' + enum_name + ' USING event_type::text::' + enum_name)
    # Drop temp enum type
    op.execute('DROP TYPE ' + tmp_enum_name)

进入全屏模式 退出全屏模式

希望这对某人有用。

Logo

PostgreSQL社区为您提供最前沿的新闻资讯和知识内容

更多推荐