1. 什么是请求体?¶
在Web开发中,我们经常需要处理客户端发送的数据。FastAPI中,当客户端通过POST、PUT等方法发送复杂数据(比如JSON格式)时,这些数据会被放在请求体(Request Body)中。和通过URL传递的查询参数(Query Parameters)不同,请求体更适合传递结构化数据(如用户信息、表单等)。
举个例子:用户注册时,我们需要收集姓名、年龄、地址等信息,这些数据如果用查询参数会显得冗长且不安全,因此通常放在请求体中。
2. Pydantic是什么?¶
Pydantic是FastAPI推荐使用的数据验证和解析库。它允许我们定义数据结构(如用户信息、商品信息),并自动进行数据类型检查、格式验证,还能将请求体数据转换为Python对象。
简单来说,Pydantic就像一个“数据保镖”,确保你收到的数据符合预期格式,避免因数据错误导致的API异常。
3. 定义第一个Pydantic模型¶
首先,我们需要安装Pydantic(FastAPI已内置,若未安装可通过pip install pydantic安装)。然后,通过继承pydantic.BaseModel来定义数据模型。
示例1:简单模型(无嵌套)
from pydantic import BaseModel
# 定义一个User模型,包含name和age字段
class User(BaseModel):
name: str # 字符串类型,必填
age: int # 整数类型,必填
# FastAPI接口:接收User模型作为请求体
from fastapi import FastAPI
app = FastAPI()
@app.post("/users/")
def create_user(user: User):
# FastAPI会自动解析请求体为User对象
return {"message": f"用户 {user.name} 创建成功!年龄:{user.age}"}
测试这个接口:
用Postman或curl发送POST请求到http://localhost:8000/users/,请求体为JSON:
{
"name": "小明",
"age": 20
}
接口会返回成功信息:{"message": "用户 小明 创建成功!年龄:20"}。
4. 复杂数据结构:嵌套模型¶
当数据包含子结构时(比如用户有地址信息),我们可以在模型中嵌套其他Pydantic模型。
示例2:嵌套模型(用户+地址)
from pydantic import BaseModel
from typing import Optional # 用于可选字段
# 先定义子模型:地址
class Address(BaseModel):
street: str # 街道
city: str # 城市
zipcode: str = "100000" # 可选,默认值
# 定义主模型:用户(嵌套Address)
class User(BaseModel):
name: str
age: int
address: Optional[Address] = None # 地址是可选的(Optional+默认None)
@app.post("/users/with-address/")
def create_user_with_address(user: User):
# 访问嵌套字段:user.address.street
return {
"name": user.name,
"address": user.address.dict() if user.address else "无地址"
}
测试:
请求体中加入地址信息:
{
"name": "小红",
"age": 22,
"address": {
"street": "科技路100号",
"city": "北京"
}
}
接口返回:{"name": "小红", "address": {"street": "科技路100号", "city": "北京", "zipcode": "100000"}}。
5. 复杂数据结构:列表类型¶
如果需要接收多个同类数据(如用户的兴趣爱好列表),可以用List类型(需导入typing.List)。
示例3:列表类型(兴趣爱好列表)
from pydantic import BaseModel
from typing import List, Optional
class User(BaseModel):
name: str
age: int
hobbies: List[str] = [] # 字符串列表,默认空列表
extra_info: Optional[dict] = None # 可选字典(比如额外信息)
@app.post("/users/with-hobbies/")
def create_user_with_hobbies(user: User):
return {
"name": user.name,
"hobbies": user.hobbies,
"extra_info": user.extra_info if user.extra_info else "无额外信息"
}
测试:
请求体包含列表:
{
"name": "小刚",
"age": 25,
"hobbies": ["篮球", "编程"],
"extra_info": {"height": 180, "weight": 70}
}
接口返回:{"name": "小刚", "hobbies": ["篮球", "编程"], "extra_info": {"height": 180, "weight": 70}}。
6. 复杂数据结构:嵌套列表¶
如果列表中包含其他模型(比如多个商品),可以用List[模型名]。
示例4:嵌套列表(商品列表)
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
class Order(BaseModel):
order_id: int
items: List[Item] # 列表中的每个元素是Item模型
@app.post("/orders/")
def create_order(order: Order):
total = sum(item.price for item in order.items)
return {
"order_id": order.order_id,
"items": [item.dict() for item in order.items],
"total_price": total
}
测试:
请求体包含嵌套列表:
{
"order_id": 1001,
"items": [
{"name": "苹果", "price": 5.0},
{"name": "香蕉", "price": 3.0}
]
}
接口返回总价格:{"order_id": 1001, "items": [{"name": "苹果", "price": 5.0}, {"name": "香蕉", "price": 3.0}], "total_price": 8.0}。
7. 数据验证:自动拦截错误数据¶
Pydantic会自动检查数据是否符合模型定义。如果数据类型错误(比如age写成字符串),FastAPI会返回422 Validation Error。
示例5:验证失败测试
发送错误请求体(age是字符串):
{
"name": "小丽",
"age": "20", # 错误类型:字符串而非整数
"hobbies": ["画画"]
}
接口会返回错误:
{
"detail": [
{
"loc": ["body", "age"],
"msg": "输入值不是整数",
"type": "type_error.integer"
}
]
}
8. 总结¶
- 请求体:适合传递复杂数据(如JSON),通过POST/PUT方法发送。
- Pydantic:定义数据结构、自动验证、减少手动解析代码。
- 嵌套模型:用
模型名作为字段类型实现子结构(如用户+地址)。 - 列表/字典:支持
List和dict类型,满足多数据项需求。 - 自动验证:不符合模型的请求会被FastAPI自动拦截,返回清晰错误信息。
掌握Pydantic是FastAPI处理复杂请求体的核心技能,能让你的API开发更规范、更健壮。
(注:所有代码可直接在FastAPI项目中运行,需安装fastapi和uvicorn:pip install fastapi uvicorn,运行命令:uvicorn main:app --reload)