You need to enable JavaScript to run this app. 如何在FastAPI响应中包含非pydantic类型的自定义类
优惠活动
大模型
产品
解决方案
定价
更多

如何在FastAPI响应中包含非pydantic类型的自定义类

解决方案

你遇到的报错本质是Pydantic默认不知道如何序列化没有继承BaseModel的自定义Foo类,不需要修改Foo的继承关系,通过以下两种鸭子类型的适配方案即可实现需求:

方案1:可修改Foo类源码时直接添加Pydantic识别的魔法方法

Pydantic V2会识别类上的__get_pydantic_core_schema__静态方法,只要实现该方法定义序列化逻辑,不需要继承BaseModel即可被Pydantic正常处理。
完整可运行代码如下:

from fastapi import FastAPI
from pydantic import BaseModel
from pydantic_core import core_schema

app = FastAPI()


class Foo:
    """Foo holds data and can't inherit from `pydantic.BaseModel`."""
    def __init__(self, x: int):
        self.x = x
    
    @staticmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        # 定义Foo实例的序列化逻辑
        def serialize_foo(foo_instance: Foo):
            return {"x": foo_instance.x}
        return core_schema.any_schema(
            serialization=core_schema.plain_serializer_function_ser_func(serialize_foo)
        )


class Response(BaseModel):
    foo: Foo
    model_config = {
        "arbitrary_types_allowed": True
    }


@app.get("/", response_model=Response)
def root():
    return Response(foo=Foo(1))


if __name__ == '__main__':
    import uvicorn
    uvicorn.run("main:app")

方案2:无法修改Foo类源码时自定义适配类型

如果Foo来自第三方库无法修改源码,可以通过自定义注解类型实现适配,完全不侵入原有Foo类的代码:

from typing import Annotated
from fastapi import FastAPI
from pydantic import BaseModel, GetCoreSchemaHandler
from pydantic_core import core_schema

app = FastAPI()


class Foo:
    """Foo holds data and can't inherit from `pydantic.BaseModel`."""
    def __init__(self, x: int):
        self.x = x

# 自定义序列化逻辑
def serialize_foo(foo_instance: Foo):
    return {"x": foo_instance.x}

# 自定义适配注解
class _FooPydanticAnnotation:
    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler: GetCoreSchemaHandler):
        return core_schema.any_schema(
            serialization=core_schema.plain_serializer_function_ser_func(serialize_foo)
        )

FooType = Annotated[Foo, _FooPydanticAnnotation]

class Response(BaseModel):
    foo: FooType
    model_config = {
        "arbitrary_types_allowed": True
    }


@app.get("/", response_model=Response)
def root():
    return Response(foo=Foo(1))


if __name__ == '__main__':
    import uvicorn
    uvicorn.run("main:app")

Pydantic V1 兼容方案

如果你使用的是Pydantic V1,不需要额外加魔法方法,直接在响应模型的配置中添加任意类型允许和自定义序列化规则即可:

class Response(BaseModel):
    foo: Foo
    class Config:
        arbitrary_types_allowed = True
        json_encoders = {
            Foo: lambda x: {"x": x.x}
        }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 07:15:03