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

FastAPI遇PydanticSerializationError:无法序列化SQLAlchemy模型求助

FastAPI中SQLAlchemy模型序列化失败问题排查与解决

错误信息

pydantic_core._pydantic_core.PydanticSerializationError: Unable to serialize unknown type: <class 'model.standard_data_model.Standard_Data_Model'>

相关代码

SQLAlchemy模型定义

from sqlalchemy import Column, INT, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
import datetime

class Standard_Data_Model(declarative_base()):
    __tablename__ = 'miun_standard_data'
    id = Column(INT, primary_key=True, autoincrement=True, comment='Primary key id')
    ros_bag_id = Column(INT, nullable=True, comment='Associated raw data set management')
    language_instruction = Column(String(255), nullable=True, comment='Instruction description')
    duration = Column(String(255), nullable=True, comment='Duration')
    morphology = Column(String(255), nullable=True, comment='Morphology')
    robot_type = Column(String(255), nullable=True, comment='Device type')
    effector_type = Column(String(255), nullable=True, comment='Gripping type')
    device_number = Column(String(255), nullable=True, comment='Device number')
    resource_type = Column(String(255), nullable=True, comment='File type')
    file_path = Column(String(255), nullable=True, comment='File path')
    status = Column(String(255), nullable=True, comment='Status')
    task_id = Column(String(255), nullable=True, comment='Task id')
    editor = Column(String(255), nullable=True, comment='Editor id')
    description = Column(String(255), nullable=True, comment='Description of this message')
    tag = Column(String(255), nullable=True, comment='Tag set')
    version_num = Column(String(255), nullable=True, comment='Version number')
    create_time = Column(DateTime, default=datetime.now(), comment='creation time')
    update_time = Column(DateTime, default=None, onupdate=datetime.now(), comment='update time')

    def __init__(self, ros_bag_id, language_instruction, duration, morphology, robot_type,
                 effector_type, device_number, resource_type, file_path, status, task_id,
                 editor, description, tag, version_num, create_time, update_time):
        self.ros_bag_id = ros_bag_id
        self.language_instruction = language_instruction
        self.duration = duration
        self.morphology = morphology
        self.robot_type = robot_type
        self.effector_type = effector_type
        self.device_number = device_number
        self.resource_type = resource_type
        self.file_path = file_path
        self.status = status
        self.task_id = task_id
        self.editor = editor
        self.description = description
        self.tag = tag
        self.version_num = version_num
        self.create_time = create_time
        self.update_time = update_time

修改前的find_by_id方法

def find_by_id(self, id : int) -> Optional[Standard_Data_Model]:
    data = self.session.execute(
        select(Standard_Data_Model).where(Standard_Data_Model.id == id)
    )
    res = data.scalars().first()
    return res

修改后的find_by_id方法

def find_by_id(self, id : int, _filter: str) -> Optional[Standard_Data_Model]:
    if _filter:
        data = self.session.execute(
            select(Standard_Data_Model).where(
                (Standard_Data_Model.id == id) & (Standard_Data_Model.language_instruction == _filter)
            )
        )
    else:
        data = self.session.execute(
            select(Standard_Data_Model).where(Standard_Data_Model.id == id)
        )
    res = data.scalars().first()
    return res

问题原因

错误本质是FastAPI默认使用Pydantic序列化返回值,但Pydantic无法直接处理SQLAlchemy的ORM实例。之前代码能正常运行,说明之前调用find_by_id的路由逻辑中,存在将ORM实例转换为Pydantic模型或字典的步骤;而修改方法后,调用该方法的路由遗漏了这个转换步骤,直接返回了SQLAlchemy的ORM对象,导致序列化失败。

修改后的find_by_id方法本身逻辑无问题,返回的仍然是Standard_Data_Model实例,问题出在方法的调用端,而非方法本身。

解决办法

方法1:创建对应Pydantic模型(推荐)

为SQLAlchemy模型定义对应的Pydantic模型,利用Pydantic的ORM适配能力完成转换:

from pydantic import BaseModel
from datetime import datetime
from typing import Optional

class StandardDataModelSchema(BaseModel):
    id: Optional[int] = None
    ros_bag_id: Optional[int] = None
    language_instruction: Optional[str] = None
    duration: Optional[str] = None
    morphology: Optional[str] = None
    robot_type: Optional[str] = None
    effector_type: Optional[str] = None
    device_number: Optional[str] = None
    resource_type: Optional[str] = None
    file_path: Optional[str] = None
    status: Optional[str] = None
    task_id: Optional[str] = None
    editor: Optional[str] = None
    description: Optional[str] = None
    tag: Optional[str] = None
    version_num: Optional[str] = None
    create_time: Optional[datetime] = None
    update_time: Optional[datetime] = None

    class Config:
        from_attributes = True  # Pydantic v2版本使用,v1版本替换为orm_mode=True

在路由中使用该Pydantic模型转换返回值:

@app.get("/data/{id}")
def get_data(id: int, _filter: Optional[str] = None):
    dal = StandardDataDAL(session)
    data = dal.find_by_id(id, _filter)
    return StandardDataModelSchema.from_orm(data)

方法2:将ORM实例转换为字典返回

直接将SQLAlchemy实例转为字典,跳过Pydantic模型定义(适合简单场景):

from sqlalchemy import inspect

def orm_to_dict(obj):
    # 仅提取模型的字段属性,排除SQLAlchemy内部属性
    return {c.key: getattr(obj, c.key) for c in inspect(obj).mapper.column_attrs}

# 路由中使用
@app.get("/data/{id}")
def get_data(id: int, _filter: Optional[str] = None):
    dal = StandardDataDAL(session)
    data = dal.find_by_id(id, _filter)
    return orm_to_dict(data) if data else None

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 22:10:02