FastAPI 请求体与 Pydantic 模型校验

举报
时光不写 发表于 2026/07/23 16:03:04 2026/07/23
【摘要】 详解 FastAPI 中请求体的使用方式,Pydantic 模型的字段类型、校验规则、嵌套模型、自定义验证器以及结合路径参数和查询参数的完整实战。

在 Web API 开发中,客户端通过请求体(Request Body)向服务端发送 JSON、XML 等结构化数据是最常见的场景。FastAPI 借助 Pydantic 实现了强大的数据校验和序列化能力——你只需定义一个 Python 类,FastAPI 就能自动完成请求体的解析、校验和文档生成。本文带你全面掌握这一核心特性。

什么是请求体

请求体是客户端通过 POST、PUT、PATCH 等方法发送给服务端的数据。与路径参数和查询参数不同,请求体不在 URL 中,而是放在 HTTP 消息的 body 部分,通常以 JSON 格式传输。

在 FastAPI 中声明请求体非常简单——定义一个 Pydantic 模型类,然后将其作为路由函数的参数类型注解即可:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    price: float
    is_offer: bool = False


@app.post("/items/")
async def create_item(item: Item):
    return item

FastAPI 会自动:

  • 读取请求体中的 JSON 数据
  • 根据 Item 模型校验字段类型
  • 将数据转换为对应的 Python 类型
  • 生成 OpenAPI 文档(Swagger UI)

Pydantic 基础字段类型

Pydantic 支持丰富的字段类型,覆盖日常开发所需:

from pydantic import BaseModel
from datetime import datetime
from typing import Optional, List


class User(BaseModel):
    # 基本类型
    id: int                     # 整数
    name: str                   # 字符串
    email: str                  # 字符串

    # 可选字段,默认为 None
    avatar: Optional[str] = None

    # 带默认值的字段
    is_active: bool = True

    # 复杂类型
    tags: List[str] = []        # 字符串列表

    # 日期时间
    created_at: datetime

当请求体传入 "id": "123" 时,Pydantic 会自动将字符串 "123" 转为整数 123;如果传入 "abc",则会返回 422 验证错误及清晰的错误信息。

字段校验与约束

除了类型注解,Pydantic 的 Field 函数提供了丰富的校验能力:

from pydantic import BaseModel, Field


class Product(BaseModel):
    name: str = Field(..., min_length=1, max_length=100, description="商品名称")
    price: float = Field(..., gt=0, description="价格,必须大于0")
    stock: int = Field(default=0, ge=0, description="库存,不能为负数")
    description: str = Field(
        default="暂无描述",
        max_length=500,
        description="商品描述"
    )

常用的 Field 校验参数:

参数 说明
... 必填字段(三个点代表 Required)
min_length / max_length 字符串长度范围
gt / ge / lt / le 数值大于/大于等于/小于/小于等于
regex 正则表达式匹配
default 默认值
description 字段描述(会显示在 API 文档中)

正则校验示例

from pydantic import BaseModel, Field


class RegisterForm(BaseModel):
    username: str = Field(..., min_length=3, max_length=20)
    email: str = Field(
        ...,
        pattern=r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$',
        description="邮箱格式"
    )
    password: str = Field(..., min_length=6, max_length=128)

当传入不合规的邮箱时,FastAPI 返回:

{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "string does not match regex ...",
      "type": "value_error.str.regex"
    }
  ]
}

嵌套模型

一个请求体往往不止一层结构,Pydantic 支持模型嵌套——将复杂数据拆解为多个模型组合:

from pydantic import BaseModel
from typing import List


class Address(BaseModel):
    province: str
    city: str
    detail: str
    zip_code: str = Field(..., pattern=r'^\d{6}$')


class OrderItem(BaseModel):
    product_id: int
    product_name: str
    quantity: int = Field(..., gt=0)
    unit_price: float = Field(..., gt=0)


class Order(BaseModel):
    order_id: str
    customer_name: str
    address: Address              # 嵌套单模型
    items: List[OrderItem]        # 嵌套模型列表
    total_amount: float = Field(..., gt=0)
    note: str = ""

对应请求体 JSON 如下:

{
  "order_id": "ORD-20240001",
  "customer_name": "张三",
  "address": {
    "province": "广东省",
    "city": "深圳市",
    "detail": "科技园路1号",
    "zip_code": "518000"
  },
  "items": [
    {
      "product_id": 1001,
      "product_name": "机械键盘",
      "quantity": 2,
      "unit_price": 299.00
    }
  ],
  "total_amount": 598.00
}

FastAPI 会递归校验每一层嵌套结构,保证数据完整性。

自定义验证器

当内置校验无法满足需求时,可以使用 @validator 装饰器实现自定义校验逻辑:

from pydantic import BaseModel, validator


class UserRegister(BaseModel):
    username: str
    password: str
    confirm_password: str

    @validator('username')
    def username_must_not_contain_special(cls, v: str) -> str:
        if not v.isalnum():
            raise ValueError('用户名只能包含字母和数字')
        return v

    @validator('confirm_password')
    def passwords_match(cls, v: str, values: dict) -> str:
        if 'password' in values and v != values['password']:
            raise ValueError('两次输入的密码不一致')
        return v

values 参数包含前面已验证过的字段值,因此可以在 confirm_password 的验证器中拿到 password 进行比较。

注意:Pydantic V2 中 @validator 已改为 @field_validator,用法类似但参数名略有不同。

结合路径参数与查询参数

请求体、路径参数、查询参数可以同时存在,FastAPI 根据参数声明自动区分:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class ItemUpdate(BaseModel):
    name: str = Field(..., min_length=1)
    price: float = Field(..., gt=0)
    is_offer: bool = False


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,               # 路径参数
    item: ItemUpdate,            # 请求体(Pydantic 模型 = body)
    force: bool = False,         # 查询参数
):
    return {
        "item_id": item_id,
        "force": force,
        "update": item.dict()
    }

识别规则很简单:

  • 在路径中也声明的 → 路径参数
  • 是 Pydantic 模型类型的 → 请求体
  • 是简单类型(str/int/float/bool)且不在路径中 → 查询参数

请求体中的额外字段

默认情况下,如果客户端多传了模型中未定义的字段,Pydantic V1 会忽略它们。如果需要严格模式(拒绝多余字段),可以在模型内部配置:

from pydantic import BaseModel


class StrictItem(BaseModel):
    name: str
    price: float

    class Config:
        extra = "forbid"   # 禁止额外字段

此时多传字段会直接返回 422 错误。

小结

FastAPI 结合 Pydantic 的请求体处理机制让数据校验变得极其简洁:

  • BaseModel 定义数据结构,类型即校验规则
  • Field 添加约束(长度、范围、正则)
  • 用嵌套模型处理复杂 JSON 结构
  • @validator 处理跨字段校验和自定义逻辑

这套机制让开发者无需手写校验代码,同时自动产出清晰的 API 文档,显著提升开发效率和数据质量。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。