请求体 Request Body 与 Pydantic 入门
本教程共 50 篇 · 第 10 篇 · 更新于 2026-08-12 · 约 7 分钟阅读
本节目标:学会用 Pydantic 的 BaseModel 定义数据结构,通过 @app.post 接收客户端发来的 JSON 请求体,并理解 FastAPI 如何自动完成校验、转换和文档生成。
前面我们学过路径参数和查询参数。它们都写在网址里,适合传递少量、简单的数据。可当你要提交一整条商品信息、一份注册表单时,靠网址就不现实了。
这时候就要用到「请求体」。请求体是客户端发给服务器的主体数据,通常是一段 JSON。FastAPI 借助 Pydantic 来处理它,整个过程几乎是自动的。
10-1 请求体是什么
请求体是客户端发送给接口的数据。相对地,响应体是接口返回给客户端的数据。
大部分接口都要返回响应体,但客户端并不总需要发请求体。比如打开一个页面,往往只用路径或查询参数就够了。一旦要「提交数据」,就要用请求体。
发送请求体时,应当使用 POST(最常见)、PUT、DELETE 或 PATCH。用 GET 带请求体虽然技术上可行,但不符合规范,Swagger 文档也不会显示它,所以不要这么干。
NoteJSON 是请求体最常用的格式。它长得像 Python 的字典:用花括号包裹,键和字符串用双引号。FastAPI 默认就把请求体当成 JSON 来解析。
10-2 Pydantic 是什么
Pydantic 是 FastAPI 的核心依赖,负责数据校验和转换。它的思路很直观:用 Python 的类型注解描述数据结构,剩下的校验、报错、转类型都交给它。
在 FastAPI 里,Pydantic 主要做四件事:
- 校验客户端发来的 JSON 是否符合要求。
- 把数据转换成你声明的类型(比如字符串变浮点数)。
- 把模型结构自动写进 API 文档。
- 让你在编辑器里获得属性补全和类型提示。
你不需要自己写一堆判断逻辑。只要声明一次类型,Pydantic 就把脏活累活全包了。
10-3 用 BaseModel 定义模型
定义请求体,先要从 pydantic 导入 BaseModel,再写一个继承它的类。类里的每个属性,就是请求体里的一个字段。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
这个 Item 模型描述了一个商品:name 是名称,price 是价格,description 和 tax 是可选的。
字段是否必填,只看有没有默认值。写了默认值(比如 = None)就是可选的;没写默认值就是必填的。所以 name 和 price 必填,description 和 tax 可以不传。
下面这段 JSON 都是合法的请求体:
{
"name": "Foo",
"description": "一份可选的描述",
"price": 45.2,
"tax": 3.5
}
即使省掉可选字段,只留必填项,同样能通过校验:
{
"name": "Foo",
"price": 45.2
}
Tip我们用了
str | None这种写法,这是 Python 3.10 起的联合类型语法。它等同于旧写法Optional[str],但更简洁。本教程统一使用新写法。
10-4 用 @app.post 接收请求体
把模型作为参数写进路径操作函数,FastAPI 就知道要去请求体里取数据。注意参数类型要写你定义的模型名 Item。
上面那段代码里,item: Item 这个声明就是关键。FastAPI 看到参数类型是 Pydantic 模型,就会自动把它当请求体处理。
启动服务用的是 FastAPI 自带的命令行工具:
fastapi dev main.py
等价地,你也可以用 Uvicorn 启动:
uvicorn main:app --reload
打开浏览器访问 http://127.0.0.1:8000/docs,你会看到一个交互式文档页面。在 /items/ 这个接口里,能直接看到 Item 的结构,还能点「Try it out」填数据测试。
10-5 字段类型即校验
只靠那一行类型声明,FastAPI 就替你做了下面这些事:
- 把请求体按 JSON 读进来。
- 把数据转换成声明的类型(比如把字符串
"45.2"转成浮点数)。 - 校验数据是否合法。
- 不合法时,返回清晰的报错,精确指出哪个字段出了错。
- 把校验后的数据放进
item参数,你还能获得编辑器补全。 - 自动生成 JSON Schema,并融进 OpenAPI 文档。
举个例子,如果客户端把 price 传成字符串 "abc",FastAPI 会直接拒绝,并返回类似这样的错误:
{
"detail": [
{
"type": "float_parsing",
"loc": ["body", "price"],
"msg": "Input should be a valid number",
"input": "abc"
}
]
}
loc 告诉你出错位置在请求体的 price 字段,msg 说明原因。这种报错对前端调试非常友好。
10-6 在函数中访问模型属性
进了函数内部,你可以像操作普通 Python 对象一样,直接访问模型的属性。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.model_dump()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
这里用到了 item.model_dump(),它把模型转成一个普通字典。这是 Pydantic v2 的写法,用来替代旧版的 .dict()。
我们还顺手算了一个含税价格 price_with_tax,加进返回的字典里。注意访问属性时用的是 item.price、item.tax,就像访问对象字段一样自然。
10-7 请求体搭配路径参数
请求体和路径参数可以同时出现。FastAPI 很聪明,能分辨哪个从路径取、哪个从请求体取。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, **item.model_dump()}
item_id 在路径 {item_id} 里出现,所以是路径参数;item 的类型是 Item 模型,所以是请求体。两者互不干扰。
10-8 三者混用时的识别规则
请求体、路径参数、查询参数能一起用。FastAPI 按下面规则自动判断数据来源:
- 参数名出现在路径的
{}里 → 路径参数。 - 参数是单一类型(
int、str、float、bool等)→ 查询参数。 - 参数类型是 Pydantic 模型 → 请求体。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):
result = {"item_id": item_id, **item.model_dump()}
if q:
result.update({"q": q})
return result
上面的函数里,item_id 来自路径,q 来自查询字符串,item 来自请求体。FastAPI 会把它们各归各位。
Note
q之所以被当成可选的查询参数,是因为它有默认值= None。类型注解str | None本身不影响是否必填,真正起作用的是「有没有默认值」。
10-9 小结
请求体是提交复杂数据的主要方式,用 @app.post 接收最合适。定义它的核心是 Pydantic 的 BaseModel:
- 用标准 Python 类型声明字段,有默认值就可选,没默认值就必填。
- 把模型写成函数参数,FastAPI 自动完成 JSON 解析、类型转换和数据校验。
- 校验失败会返回带精确位置的报错,方便排查。
- 模型结构自动进入
/docs文档,无需手写。 - 在函数中用
.model_dump()(Pydantic v2)把模型转成字典。
掌握请求体,你就具备了构建真实接口的基础能力。下一章我们进一步给字段加上更细的约束。