You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLAlchemy与Pydantic处理名称值不同的枚举时的问题解决

解决PostgreSQL与Pydantic枚举类型的双向映射问题

1. 修复向数据库映射的问题

当前核心问题是PostgreSQL无法适配Pydantic模型中的Status枚举实例,因为数据库只接受整数类型。可以通过以下两种方式快速修复:

方法1:保存时手动提取枚举值

在将模型数据传入数据库操作前,主动把枚举对象转换为对应的整数值:

# 假设已有MyTable实例
obj = MyTable(status=Status.active)
# 转换为数据库可接受的格式
db_payload = obj.dict()
db_payload["status"] = obj.status.value
# 执行数据库插入/更新操作

方法2:通过Pydantic配置自动序列化枚举

修改MyTable模型的Config类,添加枚举编码器,让模型在序列化时自动将枚举转为对应整数值:

from pydantic import BaseModel, validator
from enum import Enum

class Status(Enum):
    inactive = 0
    active = 1 

class MyTable(BaseModel):
    status: Status

    class Config:
        validate_assignment = True
        # 配置枚举自动序列化为数值
        json_encoders = {
            Status: lambda enum_obj: enum_obj.value
        }

    @validator('status', pre=True)
    def validate_status(cls, value) -> Status:
        # 同时支持整数和字符串输入的转换
        if isinstance(value, int):
            return Status(value)
        elif isinstance(value, str):
            # 兼容大小写不敏感的字符串输入
            return Status[value.lower()]
        raise ValueError(f"无效的status值: {value}")

之后调用obj.dict()得到的字典中,status会自动变为整数,直接传入数据库操作即可。


2. 更优的处理方式(保留枚举可读名称)

如果希望同时兼顾数据库存储效率(存整数)、代码可读性(用枚举名称),以及双向自动映射的便捷性,可以根据使用的工具选择方案:

方案1:结合SQLAlchemy自定义类型(适用于ORM场景)

自定义SQLAlchemy类型实现枚举与整数的自动转换,让ORM层直接处理映射逻辑:

from sqlalchemy import TypeDecorator, Integer, Column
from sqlalchemy.ext.declarative import declarative_base
from enum import Enum
from pydantic import BaseModel

# 定义枚举
class Status(Enum):
    inactive = 0
    active = 1 

# 自定义SQLAlchemy类型
class StatusType(TypeDecorator):
    impl = Integer
    cache_ok = True

    # 写入数据库时,将枚举转为整数
    def process_bind_param(self, value, dialect):
        return value.value if isinstance(value, Status) else value

    # 从数据库读取时,将整数转为枚举
    def process_result_value(self, value, dialect):
        return Status(value) if value is not None else None

# ORM模型
Base = declarative_base()
class MyTableORM(Base):
    __tablename__ = "my_table"
    id = Column(Integer, primary_key=True)
    status = Column(StatusType)

# Pydantic模型
class MyTable(BaseModel):
    status: Status

    class Config:
        orm_mode = True
        validate_assignment = True

    @validator('status', pre=True)
    def validate_status(cls, value) -> Status:
        if isinstance(value, str):
            return Status[value.lower()]
        return Status(value)

这种方式下,查询数据库时ORM会自动把整数转为Status枚举,保存时自动把枚举转为整数,Pydantic模型也支持字符串/整数输入,同时你可以通过status.name获取可读的枚举名称(比如Status.active.name得到"active")。

方案2:使用Pydantic v2的SmartEnum(简化枚举处理)

如果使用Pydantic v2,可以用SmartEnum替代原生Enum,它内置了双向转换的支持,无需额外验证器:

from pydantic import BaseModel, SmartEnum

class Status(SmartEnum):
    inactive = 0
    active = 1 

class MyTable(BaseModel):
    status: Status

    class Config:
        validate_assignment = True
        # 序列化时输出整数(存入数据库用),若要输出可读名称可改为lambda v: v.name
        json_encoders = {
            Status: lambda v: v.value
        }

SmartEnum自动支持从整数、枚举名称字符串解析为枚举实例,同时你可以通过status.name获取可读名称,序列化时按配置输出整数或名称。


内容的提问来源于stack exchange,提问作者Raquel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:46:00