首页
/ FastAPI 请求体字段校验与元数据:使用 Pydantic Field 为 Body 模型添加验证规则

FastAPI 请求体字段校验与元数据:使用 Pydantic Field 为 Body 模型添加验证规则

2026-09-08 21:38:42作者:柏廷章Berta

本篇技术指南围绕 FastAPI 教程「Body - Fields」章节展开,讲解如何在 Pydantic 模型中借助 Field 声明额外的校验规则与元数据,使请求体字段获得与 QueryPathBody 参数一致的声明能力。读完本文,你将掌握 Field 的导入方式、模型属性声明语法、常用校验与元数据参数、JSON Schema / OpenAPI 的生成机制,以及底层 FieldInfoParam 的继承关系。

为什么需要 Field:从函数参数到模型字段

在 FastAPI 中,你可以用 QueryPathBody路径操作函数 的参数声明额外校验和元数据,例如长度限制、数值范围、标题与描述。但请求体往往不是一个简单参数,而是一个 Pydantic 模型——模型的每个字段同样需要校验和元数据。这时就要用到 Pydantic 提供的 Field

原文档 docs/pt/docs/tutorial/body-fields.md(以及英文原版 docs/en/docs/tutorial/body-fields.md)明确指出:就像可以用 QueryPathBody 在路径操作函数参数中声明附加校验与元数据一样,你可以用 Pydantic 的 Field 在 Pydantic 模型内部声明校验和元数据。

导入 Field:来自 pydantic,而非 fastapi

Field 的导入方式与 QueryPathBody 有一个关键区别,原文档特意用警告框强调:

from pydantic import BaseModel, Field

警告Field 是直接从 pydantic 导入的,而不是像 QueryPathBody 等那样从 fastapi 导入。

这一点在仓库源码中得到印证:FastAPI 自己的 QueryPath 等是定义在 fastapi/param_functions.py 中的函数,而 Field 完全属于 Pydantic 的领域,FastAPI 只是依赖 Pydantic 的 FieldInfo 体系来完成参数解析。

声明模型属性:完整可运行示例

原文档引用的示例代码位于 docs_src/body_fields/tutorial001_an_py310.py(使用 Annotated 风格)和 docs_src/body_fields/tutorial001_py310.py(使用默认值风格)。下面是基于 Annotated 版本的完整代码:

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = Field(
        default=None, title="The description of the item", max_length=300
    )
    price: float = Field(gt=0, description="The price must be greater than zero")
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
    results = {"item_id": item_id, "item": item}
    return results

这里 Field 的应用要点:

  • description 字段:类型 str | None,默认值 None,通过 Field 声明了 title(在 schema 中作为字段标题)和 max_length=300(字符串最大长度)。
  • price 字段:通过 Field(gt=0, ...) 声明数值必须大于 0,并附加 description 说明。
  • tax 字段:未使用 Field,仅作为普通可空字段存在,用于对比展示。
  • 路径操作函数中 item: Annotated[Item, Body(embed=True)] 将请求体以 {"item": {...}} 的形式嵌入,这正是 fastapi/params.pyBodyembed 参数的用途。

原文档还特别提示:每个带有类型、默认值和 Field 的模型属性,其结构与路径操作函数的参数完全一致——只不过把 PathQueryBody 换成了 Field。也就是说,你在参数上学会的一切声明技巧,都可以原样搬到模型字段上。

Field 与 Query / Path / Body 的统一原理

为什么 Field 能和 QueryPathBody 提供几乎一致的参数?原文档的「技术细节」框给出了答案,而仓库源码进一步印证了这条继承链:

  1. Param 基类QueryPathHeaderCookie 创建的对象都是公共基类 Param 的子类实例,而 Param 本身继承自 Pydantic 的 FieldInfo。见 fastapi/params.pyclass Param(FieldInfo)PathQueryHeaderCookie 均以 class Xxx(Param) 定义。
  2. Field 返回 FieldInfo:Pydantic 的 Field 同样返回一个 FieldInfo 实例,与 Param 处在同一类型体系中。
  3. Body 直接继承 FieldInfo:与 Param 不同,Body 是直接继承 FieldInfo 的类(fastapi/params.py),而 FormFile 又继承自 Body,后续教程中你会看到这些子类。
  4. 函数包装:当你从 fastapi 导入 QueryPath 等时,它们实际上是返回特殊类的函数(定义于 fastapi/param_functions.py),内部将参数转发给 fastapi/params.py 中对应的类。

正因为 FieldQuery/Path/Body 最终都收敛到 Pydantic 的 FieldInfo,FastAPI 才能用同一套机制把它们生成的 schema 信息整合进 OpenAPI。

Field 常用参数速查

fastapi/param_functions.pyQueryPath 等函数的签名可以看出,Field 支持的同名参数非常丰富(Field 拥有这些参数的 Pydantic 实现),按用途可分为以下几类:

类别 参数 说明
基础 default 字段默认值;不传则字段必填
基础 default_factory 生成默认值的可调用对象
元数据 title 人类可读的标题,会进入 JSON Schema
元数据 description 人类可读的描述,会进入 JSON Schema
字符串校验 min_length / max_length 字符串最小 / 最大长度
字符串校验 pattern 字符串正则表达式(regex 已废弃,改用 pattern
数值校验 gt / ge / lt / le 大于 / 大于等于 / 小于 / 小于等于,仅适用于数值
数值校验 multiple_of 数值必须是该值的倍数
数值校验 allow_inf_nan 是否允许 inf-infnan
数值校验 max_digits / decimal_places 小数值的最大位数 / 最大小数位
别名 alias / validation_alias / serialization_alias 字段别名及校验、序列化阶段的别名
示例 examples / openapi_examples 字段示例(example 已废弃)
其他 deprecated 标记字段为废弃
其他 include_in_schema 是否包含进生成的 OpenAPI
扩展 json_schema_extra / 额外关键字 附加 JSON Schema 数据

需要注意两点:

  • regex 参数在 FastAPI 0.100.0 及 Pydantic v2 中已废弃,应使用 patternexample 在 OpenAPI 3.1.0(使用 JSON Schema 2020-12)中已废弃,应使用 examples。这些废弃提示均以 FastAPIDeprecationWarning 形式出现在 fastapi/params.py 等处的源码中。
  • Path 参数不允许默认值,源码中通过 assert default is ... 强制(fastapi/params.py),这是路径参数特有的约束,模型字段不受此限。

添加额外信息:从 Field 到 JSON Schema 与 OpenAPI

你可以在 Field(以及 QueryBody 等)中声明额外信息,这些信息会进入生成的 JSON Schema。原文档指出,关于声明示例(examples)等高级用法,将在后续「Schema 额外示例」章节详细学习(对应文档 docs/pt/docs/tutorial/schema-extra-example.md)。

额外信息如何影响最终产物?看仓库测试 tests/test_tutorial/test_body_fields/test_tutorial001.py 中对 /openapi.json 的断言即可一目了然:

  • description 字段的 title="The description of the item" 出现在 Item schema 的属性标题中,maxLength: 300 被合并进 anyOf 中的字符串分支;
  • pricegt=0 转换为 exclusiveMinimum: 0.0description 原样保留;
  • tax 没有任何额外约束,schema 中只有普通的可空 number 分支;
  • 由于使用了 Body(embed=True),还生成了一个 Body_update_item_items__item_id__put 包装 schema,其 required 列表包含 item

警告(原文档重点):传给 Field 的额外键也会出现在应用最终的 OpenAPI schema 中。由于这些键未必是 OpenAPI 规范的一部分,一些 OpenAPI 工具(例如 OpenAPI 校验器)可能无法正确处理你生成的 schema。因此,自定义额外键应谨慎使用,并明确其可能带来的兼容性问题。

校验行为验证:测试用例如何证明 Field 生效

仓库测试 tests/test_tutorial/test_body_fields/test_tutorial001.py 从四个维度验证了 Field 的行为,可作为你自行验证的参考:

  1. 合法请求test_items_5):PUT /items/5,body 为 {"item": {"name": "Foo", "price": 3.0}},返回 200,且缺失的 descriptiontax 被补为 None
  2. 类型隐式转换test_items_6):tax 传入字符串 "5.4" 被转换为浮点数 5.4,展示了 Pydantic 的类型转换能力。
  3. 校验失败test_invalid_price):price: -3.0 触发 gt=0 约束,返回 422,错误结构为:
    {
      "type": "greater_than",
      "loc": ["body", "item", "price"],
      "msg": "Input should be greater than 0",
      "input": -3.0,
      "ctx": {"gt": 0.0}
    }
    
    loc 路径精确到 body → item → price,可直接用于前端错误定位。
  4. OpenAPI schema 快照test_openapi_schema):完整断言上述 Item schema 与包装 schema 的生成结果。

此外,该测试通过 fixture 同时运行 tutorial001_py310tutorial001_an_py310 两个版本的示例(tests/test_tutorial/test_body_fields/test_tutorial001.py),说明「默认值风格」与「Annotated 风格」两种写法行为完全等价。

回顾总结

  • 使用 Pydantic 的 Field 可以为模型属性声明额外校验和元数据,功能与 QueryPathBody 对齐。
  • Field 必须从 pydantic 导入;QueryPathBodyfastapi 导入。
  • 底层上,Field 返回 FieldInfo 实例,Query/Path 等返回 ParamFieldInfo 子类)实例,Body 直接返回 FieldInfo 子类实例,三者统一于 Pydantic 的字段信息体系。
  • 校验参数(gtmax_lengthpattern 等)会转化为 JSON Schema 约束并最终体现在 OpenAPI 文档与 422 校验错误中。
  • 额外关键字可用于传递附加 JSON Schema 元数据,但需注意 OpenAPI 工具兼容性。
  • 相关资源:示例代码参数实现参数函数定义测试用例
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
858
1.35 K
docsdocs
暂无描述
Markdown
899
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
923
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.83 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
532
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
524
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
393