使用 SQLAlchemy 在 Python 中更改枚举时创建迁移
·
这最初发布在我自己的博客这里
最近在工作中,我花了一些时间在一个脚手架项目上,我们将用于我们将要构建的 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'
- 使用代码填充新迁移以创建更改,请注意,您需要为现有选项和新选项添加值,以确保保留新迁移文件中已存在的修订和 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)
进入全屏模式 退出全屏模式
希望这对某人有用。
更多推荐
所有评论(0)