如何在SqlModel与Alembic中使用Enum类型实现迁移自动生成无需手动修改
SQLModel+Alembic自动生成枚举类型迁移的无手动修改方案
你遇到的报错本质是PostgreSQL中枚举属于自定义数据库类型,默认低版本Alembic生成迁移时仅生成新增字段语句,不会自动提前创建对应的枚举类型,导致执行加列语句时找不到对应类型。以下是三个可直接落地的解决方法:
方案1:配置Alembic钩子自动注入枚举创建语句
该方案无需修改现有模型代码,仅调整Alembic配置文件alembic/env.py,添加自动识别枚举列并注入创建语句的逻辑即可。
修改步骤:
- 在
env.py头部导入依赖:
from alembic.operations import ops from sqlalchemy.dialects.postgresql import ENUM as PGEnum
- 定义迁移指令处理钩子函数:
def auto_create_enums(context, revision, directives): script = directives[0] # 处理升级逻辑 for idx, op in enumerate(script.upgrade_ops.ops): if isinstance(op, ops.AddColumnOp) and isinstance(op.column.type, PGEnum): enum_type = op.column.type # 生成带防重复创建判断的枚举创建语句 create_sql = f"CREATE TYPE IF NOT EXISTS {enum_type.name} AS ENUM {tuple(enum_type.enums)};" # 将创建枚举语句插入到加列语句之前 script.upgrade_ops.ops.insert(idx, ops.Execute(create_sql)) # 可选:降级时自动删除枚举,根据自身需求决定是否开启 # for idx, op in enumerate(script.downgrade_ops.ops): # if isinstance(op, ops.DropColumnOp) and isinstance(op.column.type, PGEnum): # enum_type = op.column.type # drop_sql = f"DROP TYPE IF EXISTS {enum_type.name};" # script.downgrade_ops.ops.append(ops.Execute(drop_sql))
- 找到
run_migrations_online函数中的context.configure配置段,新增钩子函数参数:
context.configure( # 原有其他配置保持不变 process_revision_directives=auto_create_enums, )
配置完成后,后续新增枚举字段时Alembic自动生成的迁移文件就会自动包含创建枚举类型的语句,无需手动修改。
方案2:改用字符串存储+应用层枚举校验
如果不想修改Alembic配置,也可以调整模型实现,把枚举值存为普通字符串,用Pydantic校验保证合法性,彻底规避数据库自定义类型的迁移问题:
import enum from typing import Optional from pydantic import validator from sqlmodel import SQLModel, Field class SongType(enum.Enum): Rock = "Rock" Ballad = "Ballad" class SongBase(SQLModel): name: str artist: str label: str = Field(index=False) song_type: Optional[str] = None year: Optional[int] = None @validator("song_type") def check_song_type(cls, value: Optional[str]) -> Optional[str]: if value is None: return value allowed_values = [item.value for item in SongType] if value not in allowed_values: raise ValueError(f"song_type仅允许为{allowed_values}中的值") return value class Song(SongBase, table=True): id: int = Field(default=None, primary_key=True, nullable=False)
这种方式Alembic生成的迁移就是普通的VARCHAR类型新增语句,完全不需要手动调整,且兼容所有数据库类型,无需担心跨库适配问题。
方案3:升级依赖版本
你当前使用的依赖版本较低,新版Alembic(>=1.10.0)和SQLModel(>=0.0.8)已经原生支持枚举类型的自动迁移生成,直接升级对应依赖即可解决问题,不需要额外配置:
pip install alembic>=1.10.0 sqlmodel>=0.0.8
升级后重新生成迁移文件,就会自动包含枚举创建的相关逻辑。
内容的提问来源于stack exchange,提问作者Trondh
相关产品推荐
相关产品推荐

