FastAPI 如何用 dataclasses 声明请求体与 response_model 响应模型?
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
如果你手上已经有一批 Python 标准库dataclass,不想先改写成 Pydantic 模型就要在 FastAPI 里用起来,这篇文章给出完整路径:用标准库dataclasses直接声明请求体,用response_model参数声明 dataclass 响应模型,并用 HTTP 请求、/docs界面和/openapi.json三种方式核对结果。该能力自 FastAPI0.67.0起可用,底层由 Pydantic 完成标准dataclass到 Pydantic dataclass 的转换,因此同样支持数据校验、序列化和文档生成(见 Using Dataclasses)。
用标准库 dataclass 声明请求体
把代码保存为main.py,Item就是一个普通@dataclass,没有任何 Pydantic 导入:
from dataclasses import dataclass from fastapi import FastAPI @dataclass class Item: name: str price: float description: str | None = None tax: float | None = None app = FastAPI() @app.post("/items/") async def create_item(item: Item): return item完整示例见 tutorial001_py310.py。在main.py所在目录运行(命令来自 First Steps):
uv run fastapi dev启动后服务地址为http://127.0.0.1:8000。发送一条合法请求:
curl -X POST http://127.0.0.1:8000/items/ \ -H "Content-Type: application/json" \ -d '{"name": "Foo", "price": 3}'仓库测试 test_tutorial001.py 断言该请求返回200,响应为:
{"name": "Foo", "price": 3, "description": null, "tax": null}再验证校验是否生效:把price传成字符串"invalid price",同一个测试断言返回422,响应体(文档示例)为:
{ "detail": [ { "type": "float_parsing", "loc": ["body", "price"], "msg": "Input should be a valid number, unable to parse string as a number", "input": "invalid price" } ] }loc指向body下的price字段,说明标准库 dataclass 请求体走的是和 Pydantic 模型同样的校验流程。
用 response_model 声明 dataclass 响应模型
response_model参数可以直接接收 dataclass 类,dataclass 会被自动转换成 Pydantic dataclass,其 schema 会出现在/docs的 API 文档界面中。示例(见 tutorial002_py310.py):
from dataclasses import dataclass, field from fastapi import FastAPI @dataclass class Item: name: str price: float tags: list[str] = field(default_factory=list) description: str | None = None tax: float | None = None app = FastAPI() @app.get("/items/next", response_model=Item) async def read_next_item(): return { "name": "Island In The Moon", "price": 12.99, "description": "A place to be playin' and havin' fun", "tags": ["breater"], }两个要点:
- 路径操作函数返回的是普通字典,
response_model负责按Item结构序列化和过滤响应; field(default_factory=list)来自标准库dataclasses,用于可变默认值(如列表),这是标准库 dataclass 的常规写法。
验证方式(仓库测试 test_tutorial002.py 中的断言):
GET http://127.0.0.1:8000/items/next返回200,响应为{"name": "Island In The Moon", "price": 12.99, "description": "A place to be playin' and havin' fun", "tags": ["breater"], "tax": null}——注意未提供的tax字段会补为null。GET http://127.0.0.1:8000/openapi.json,确认/items/next的200响应 schema 指向#/components/schemas/Item,且Item的required为["name", "price"],tags被识别为字符串数组。- 打开
http://127.0.0.1:8000/docs,在 Swagger UI 中可以看到Item的 schema。
嵌套结构:dataclass 组合列表,必要时换用 pydantic.dataclasses
dataclass 可以和其他标准类型注解组合成嵌套结构:response_model可以是Author,Author内含list[Item],请求体也可以是list[Item](见 tutorial003_py310.py):
from dataclasses import field # (1) from fastapi import FastAPI from pydantic.dataclasses import dataclass # (2) @dataclass class Item: name: str description: str | None = None @dataclass class Author: name: str items: list[Item] = field(default_factory=list) # (3) app = FastAPI() @app.post("/authors/{author_id}/items/", response_model=Author) # (4) async def create_author_items(author_id: str, items: list[Item]): # (5) return {"name": author_id, "items": items} # (6) @app.get("/authors/", response_model=list[Author]) # (7) def get_authors(): # (8) return [ # (9) { "name": "Breaters", "items": [ { "name": "Island In The Moon", "description": "A place to be playin' and havin' fun", }, {"name": "Holy Buddies"}, ], }, { "name": "System of an Up", "items": [ { "name": "Salt", "description": "The kombucha mushroom people's favorite", }, {"name": "Pad Thai"}, { "name": "Lonely Night", "description": "The mostests lonliest nightiest of allest", }, ], }, ]文档对这段代码的逐条说明:
field仍从标准库dataclasses导入。- 当自动生成的 API 文档出现错误时,把标准
dataclasses换成pydantic.dataclasses,它是 drop-in replacement(可直接替换)。 Author内含一个Itemdataclass 列表。Author作为response_model参数使用。- 请求体用了普通类型注解
list[Item],即 dataclass 也可以配合list等注解作请求体。 - 函数返回的字典里
items是 dataclass 列表,FastAPI 能把它序列化为 JSON。 response_model用了list[Author]这种类型注解。- 该路径操作函数用普通
def而非async def,两者可按需混用。 - 该函数返回的是字典列表而非 dataclass,FastAPI 会用
response_model里的 dataclass 定义去转换响应。
验证方式(仓库测试 test_tutorial003.py 中的断言):
POST http://127.0.0.1:8000/authors/foo/items/,请求体json=[{"name": "Bar"}, {"name": "Baz", "description": "Drop the Baz"}],返回200,响应为{"name": "foo", "items": [{"name": "Bar", "description": null}, {"name": "Baz", "description": "Drop the Baz"}]}——缺省的description被response_model补为null。GET http://127.0.0.1:8000/authors/返回200和两个Author的列表。- 检查
/openapi.json:Author的required为["name"],items是引用Item的数组;POST请求体的 schema 是items指向Item的数组,required为True。
限制与版本
- dataclass 不能覆盖 Pydantic 模型的全部能力,文档明确提示:复杂场景下你可能仍需要使用 Pydantic 模型;
pydantic.dataclasses只是在 API 文档生成出错时的替换方案。 - 该功能自 FastAPI 版本
0.67.0起可用。 - 代码示例使用
str | None这类联合类型写法,与docs_src中*_py310示例文件对应(对应 Python 3.10 风格,仓库测试通过needs_py310标记运行)。
完成上述三步后,如果你的/docs中 schema 正确、/openapi.json中$ref指向对应 dataclass、合法与非法请求分别返回200与422,说明 dataclass 请求体和response_model均已按预期工作。更多 dataclass 与 Pydantic 模型混用的细节,见 Using Dataclasses 文档的 Learn More 一节。
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考