Skip to content

请求体与数据模型 ​

为什么创建操作常用请求体 ​

商品可能有名称、价格、库存、标签和描述。把这些全部塞进 URL 不方便;用 JSON 对象更容易描述它们的结构。

完整示例:

python
from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class ProductCreate(BaseModel):
    name: str = Field(min_length=1, max_length=100)
    price: float = Field(gt=0)
    stock: int = Field(ge=0)
    description: str | None = None
    tags: list[str] = Field(default_factory=list)


@app.post("/products", status_code=201)
def create_product(product: ProductCreate):
    return product

因为 product 是模型参数,FastAPI 默认从 JSON 请求体读取它。官方请求体说明

可提交:

json
{
  "name": "入门教材",
  "price": 39.9,
  "stock": 10,
  "tags": ["学习"]
}

description 和 tags 可以省略;name、price、stock 必须提供。价格为负数或库存为负数会被拒绝。示例使用浮点数学习校验,真实金额通常要根据业务使用 Decimal 或整数最小货币单位。

请求体、路径、查询可以同时存在 ​

追加到本章完整示例:

python
@app.put("/products/{product_id}")
def replace_product(
    product_id: int,
    product: ProductCreate,
    notify: bool = False,
):
    return {
        "id": product_id,
        "notify": notify,
        "product": product,
    }

调用时:product_id 在路径中,notify 在查询字符串中,商品数据在请求体中。

一个 HTTP 请求只有一个请求体。多个模型参数不表示多个请求体,而是框架按参数名组织同一个 JSON 对象的结构。官方多个请求体参数说明

嵌套模型:对象里再放对象 ​

下面是模型定义片段:

python
class Address(BaseModel):
    city: str
    street: str


class OrderCreate(BaseModel):
    product_ids: list[int]
    address: Address

对应 JSON:

json
{
  "product_ids": [1, 2],
  "address": {
    "city": "上海",
    "street": "示例路 10 号"
  }
}

嵌套模型让每一层数据都有清楚的声明。比起只写一个没有字段规则的 dict,更容易定位错误。官方嵌套模型说明

Body(embed=True) 改变外层结构 ​

追加到本章完整示例:

python
from typing import Annotated
from fastapi import Body


@app.post("/wrapped-products")
def create_wrapped_product(
    product: Annotated[ProductCreate, Body(embed=True)],
):
    return product

这时客户端要提交:

json
{
  "product": {
    "name": "入门教材",
    "price": 39.9,
    "stock": 10
  }
}

单个模型默认可以直接接收商品对象;embed=True 要求加上 product 这一层。请求结构要与接口声明一致。

本章练习 ​

定义订单模型,包含客户姓名、至少一个商品编号、收货地址。

提示:列表也可以用 Field(min_length=1) 约束元素数量。

过关标准:能把一份 JSON 写成模型,也能根据模型写出合法请求体。