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

Pydantic v2自定义响应模型出现Could not resolve reference错误的解决

Pydantic v2 + FastAPI 自定义类型导致Schema解析错误的解决方法

问题场景

在pydantic==1.10.9中,以下代码可正常生成FastAPI的/docs文档,但升级到pydantic==2.3.0后出现Resolver错误,提示无法解析components引用。将自定义的Hour类型改为int则恢复正常,问题与自定义类型的Schema生成逻辑相关。

示例代码

import pydantic
from fastapi import FastAPI


class Hour(int):
    def __new__(cls, *args, **kwargs):
        h = super().__new__(cls, *args, **kwargs)
        assert 0 <= h < 24, f"Invalid hour: {h}"
        return h


class PydanticConfig:
    arbitrary_types_allowed = True


@pydantic.dataclasses.dataclass(frozen=True, config=PydanticConfig)
class Time:
    hour: Hour


app = FastAPI()


@app.get("/", response_model=Time)
def read_root():
    return Time(13)

错误信息

Errors
 
Resolver error at responses.200.content.application/json.schema.$ref
Could not resolve reference: Evaluation failed on token: "components"
Resolver error at responses.200.content.application/json.schema.$ref
Could not resolve reference: Evaluation failed on token: "components"

解决方法

Pydantic v2对自定义类型的Schema生成逻辑做了调整,需要给自定义类型显式指定JSON Schema规则,以下是三种可行方案:

方案1:使用Annotated绑定序列化与Schema规则(推荐)

通过Annotated给Hour类型绑定序列化逻辑和JSON Schema约束,让Pydantic能正确识别类型的Schema:

import pydantic
from fastapi import FastAPI
from pydantic import PlainSerializer, WithJsonSchema
from typing import Annotated


class Hour(int):
    def __new__(cls, *args, **kwargs):
        h = super().__new__(cls, *args, **kwargs)
        assert 0 <= h < 24, f"Invalid hour: {h}"
        return h


# 给Hour类型绑定JSON Schema与序列化规则
HourSchema = Annotated[
    Hour,
    PlainSerializer(lambda x: int(x), return_type=int),
    WithJsonSchema({"type": "integer", "minimum": 0, "maximum": 23})
]


class PydanticConfig:
    arbitrary_types_allowed = True


@pydantic.dataclasses.dataclass(frozen=True, config=PydanticConfig)
class Time:
    hour: HourSchema  # 使用绑定规则后的类型


app = FastAPI()


@app.get("/", response_model=Time)
def read_root():
    return Time(13)

方案2:给自定义类型添加Schema生成方法

直接在Hour类中实现Pydantic v2要求的__get_pydantic_json_schema__方法,让类型自身提供正确的Schema:

import pydantic
from fastapi import FastAPI
from pydantic.json_schema import GenerateJsonSchema


class Hour(int):
    def __new__(cls, *args, **kwargs):
        h = super().__new__(cls, *args, **kwargs)
        assert 0 <= h < 24, f"Invalid hour: {h}"
        return h

    @classmethod
    def __get_pydantic_json_schema__(cls, schema_generator: GenerateJsonSchema, field_schema):
        # 复用int类型的Schema模板,添加自定义范围约束
        int_schema = schema_generator.generate_schema(int)
        int_schema.update({
            "minimum": 0,
            "maximum": 23
        })
        return int_schema


class PydanticConfig:
    arbitrary_types_allowed = True


@pydantic.dataclasses.dataclass(frozen=True, config=PydanticConfig)
class Time:
    hour: Hour


app = FastAPI()


@app.get("/", response_model=Time)
def read_root():
    return Time(13)

方案3:改用Pydantic BaseModel替代dataclass

如果可以调整数据结构定义方式,改用BaseModel配合字段验证器,也能正常生成Schema:

from fastapi import FastAPI
from pydantic import BaseModel, field_validator


class Hour(int):
    def __new__(cls, *args, **kwargs):
        h = super().__new__(cls, *args, **kwargs)
        assert 0 <= h < 24, f"Invalid hour: {h}"
        return h


class Time(BaseModel):
    hour: Hour

    @field_validator('hour')
    def check_hour_range(cls, v):
        assert 0 <= v < 24, f"Invalid hour: {v}"
        return v


app = FastAPI()


@app.get("/", response_model=Time)
def read_root():
    return Time(hour=13)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 09:12:56