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

使用ModelSerializer时如何保证API规格正确?

问题:用model_serializer序列化列表为字典后API规格不正确

我用Pydantic的model_serializer把列表序列化为字典(感谢Plagon),但生成的API规格不正确。以下是实现代码及当前错误的API spec,请问如何确保API规格正确?

实现代码

from uuid import UUID, uuid4

from fastapi import FastAPI
from pydantic import BaseModel, Field, model_serializer


class Item(BaseModel):
    uid: UUID = Field(default_factory=uuid4)
    number: int = Field(default_factory=lambda: 4)  # https://xkcd.com/221/

class ResponseModel(BaseModel):
    items: list[Item]

    @model_serializer
    def serialize_model(self):
        return {str(item.uid): item.model_dump() for item in self.items}


app = FastAPI()


@app.get("/items/", response_model=ResponseModel)
def read_item():
    return ResponseModel(items=[Item() for _ in range(2)])

错误的API spec

{
  "openapi": "3.1.0",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/items/": {
      "get": {
        "summary": "Read Item",
        "operationId": "read_item_items__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Item": {
        "properties": {
          "uid": {
            "type": "string",
            "format": "uuid",
            "title": "Uid"
          },
          "number": {
            "type": "integer",
            "title": "Number"
          }
        },
        "type": "object",
        "title": "Item"
      },
      "ResponseModel": {
        "properties": {
          "items": { // <- 此处错误,因为它不知道items现在是一个dict了。
            "items": {
              "$ref": "#/components/schemas/Item"
            },
            "type": "array",  
            "title": "Items"
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "ResponseModel"
      }
    }
  }
}

解决方案

问题原因

FastAPI的API规格基于Pydantic模型的字段类型生成,你的ResponseModel中items字段定义为list[Item],即便通过model_serializer将其序列化为字典,生成的schema仍会保留数组类型,导致与实际输出不匹配。

可行方案

方案1:修改模型字段类型,添加列表转字典的构造方法

直接将ResponseModel的items字段定义为dict[str, Item],并添加类方法适配列表输入,这样生成的schema会正确反映输出结构:

from uuid import UUID, uuid4

from fastapi import FastAPI
from pydantic import BaseModel, Field


class Item(BaseModel):
    uid: UUID = Field(default_factory=uuid4)
    number: int = Field(default_factory=lambda: 4)  # https://xkcd.com/221/

class ResponseModel(BaseModel):
    items: dict[str, Item]

    @classmethod
    def from_item_list(cls, items: list[Item]):
        return cls(items={str(item.uid): item for item in items})


app = FastAPI()


@app.get("/items/", response_model=ResponseModel)
def read_item():
    return ResponseModel.from_item_list([Item() for _ in range(2)])

方案2:直接返回字典,指定响应模型类型

如果不需要保留ResponseModel,可直接在路由中构造字典,并通过response_model参数指定输出类型:

from uuid import UUID, uuid4

from fastapi import FastAPI
from pydantic import BaseModel, Field


class Item(BaseModel):
    uid: UUID = Field(default_factory=uuid4)
    number: int = Field(default_factory=lambda: 4)  # https://xkcd.com/221/


app = FastAPI()


@app.get("/items/", response_model=dict[str, Item])
def read_item():
    items = [Item() for _ in range(2)]
    return {str(item.uid): item for item in items}

验证效果

修改后生成的API spec中,items字段会被正确定义为字典类型:

"items": {
  "type": "object",
  "additionalProperties": {
    "$ref": "#/components/schemas/Item"
  },
  "title": "Items"
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:53:15