请求体与 Pydantic
这是什么:请求体(body)= 客户端随 POST/PUT 请求发来的数据本体(通常是一段 JSON);Pydantic 是 FastAPI 背后的数据校验库,用 BaseModel 类把「数据长什么样」声明出来,校验全自动。
为什么用:GET 只能带几个查询参数,创建待办、提交订单这种「一整块数据」必须走请求体。手写校验「字段在不在、类型对不对」又烦又漏——用 BaseModel 声明一次,校验、转换、文档三件事一起解决。
如何用:写一个继承 BaseModel 的类,把它标成路由函数的参数,FastAPI 自动把请求 JSON 变成对象。
定义模型:一个类描述一份数据
from pydantic import BaseModel
class Todo(BaseModel):
title: str
done: bool = False
| 行 | 含义 |
|---|---|
title: str |
必填字段:请求里必须有 title,且必须是字符串 |
done: bool = False |
可选字段:不传就用默认值 False |
这就是面向对象里学的类派上了新用场:类不是用来继承复用的,是用来描述数据形状的。
接收请求体:模型当参数
from fastapi import FastAPI
app = FastAPI()
@app.post("/todos")
def create_todo(todo: Todo):
return {"created": todo.title, "done": todo.done}
参数 todo: Todo 不带默认值、又不是基础类型,FastAPI 就把它当请求体处理:把客户端发来的 JSON 按模型解析成 Todo 对象,todo.title 直接用属性访问。
启动后用 /docs 试一下(也可以用 curl / Postman),请求体:
{
"title": "学完 FastAPI",
"done": false
}
响应:
{
"created": "学完 FastAPI",
"done": false
}
自动校验:错一点也不放过
少传必填字段、类型给错,都会被 422 拦下,且明细精确到字段:
{
"detail": [
{
"type": "missing",
"loc": ["body", "title"],
"msg": "Field required"
}
]
}
loc 里的 body.title 直接指出「请求体里缺 title」。对比 Flask 里手写 data.get("title") 逐个检查,这套校验零成本且不会漏。类型不对时还会自动转换:JSON 里给 "done": "true"(字符串),能安全转成 True 就转,转不了才报错。
Field:给字段加规则
类型对了还不够?Field 加约束:
from pydantic import BaseModel, Field
class Todo(BaseModel):
title: str = Field(min_length=1, max_length=50)
priority: int = Field(default=1, ge=1, le=5) # 1~5 级
title 不能是空串、超 50 字符报错;priority 必须在 1 到 5 之间(ge = 大于等于,le = 小于等于)。规则写在类里,接口、文档、校验三处同时生效。
完整小示例:能收能回的小接口
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Todo(BaseModel):
title: str = Field(min_length=1, max_length=50)
done: bool = False
todos: list[Todo] = [] # 先放内存里,下一章换数据库
@app.post("/todos")
def create_todo(todo: Todo):
todos.append(todo)
return {"count": len(todos), "latest": todo.title}
@app.get("/todos")
def list_todos():
return {"total": len(todos), "items": [t.model_dump() for t in todos]}
逐段中文精讲
- 模型区:
Todo声明数据形状,title必填且 1~50 字,done默认False。 todos: list[Todo]:模块级列表当「临时仓库」,服务重启就清空——下章换 SQLite 解决。- POST 路由:
todo: Todo自动完成「解析 + 校验」,能走到函数体说明数据合法,直接入仓。 t.model_dump():Pydantic v2 的「对象转 dict」方法,方便序列化回 JSON 返回。- 跑起来后在
/docs里连发两次 POST,再 GET 一次,你会看到total变成 2。
记忆口诀:继承 BaseModel,字段即规则;少传错类不用怕,422 明细帮你查。
📝 本章小结
- 请求体 = POST/PUT 携带的 JSON 数据;带模型注解的参数自动从 body 解析
BaseModel类声明数据形状:必填靠无默认值,可选靠默认值- 校验失败统一 422,
loc精确到字段;Field可加长度、范围等约束 /docs里点「Try it out」就能填 JSON 调试,替代一多半手动测试
动手改
- 给
Todo加deadline: str | None = None字段(可选截止日期),重看/docs里的示例 - POST 一个缺
title的请求,把 422 的loc抄下来 - 把
priority约束改成ge=1, le=3,传 4 试试会发生什么