FastAPI 表单模型实战:用 Pydantic 模型声明与校验表单字段
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
本篇基于 FastAPI 官方教程文档《Formularmodelle(表单模型)》,讲解如何在 FastAPI 中直接使用Pydantic 模型来声明表单字段(form fields):从安装依赖、声明Form参数、自动从请求中提取并校验各字段,到通过extra = "forbid"禁止客户端提交模型中未声明的额外字段。读完后你将掌握这套自 FastAPI0.113.0起支持的表单建模能力,并理解其在 OpenAPI 文档生成与请求校验中的底层实现(0.114.0 起额外支持禁止额外字段)。
前置条件:安装 python-multipart
使用表单功能的第一步是安装python-multipart包。将其添加到你的项目中:
$ uv add python-multipart这个依赖在 FastAPI 内部是被硬性检查的。从源码看,fastapi/dependencies/utils.py 中定义了专门的错误提示与检查函数ensure_multipart_is_installed():它尝试导入python_multipart并断言版本大于0.0.12,若导入失败或版本过低则抛出RuntimeError,提示安装python-multipart;甚至针对误装了名为multipart(而非python-multipart)的包的情况也准备了单独的提示multipart_incorrect_install_error。所以遇到 "Form data requires python-multipart" 报错时,检查包名和版本是第一排查方向。
版本前提说明:
- 使用 Pydantic 模型声明表单字段:自 FastAPI
0.113.0起支持; - 通过
extra: "forbid"禁止额外表单字段:自 FastAPI0.114.0起支持。
用 Pydantic 模型声明表单字段
你只需声明一个包含所有期望接收的表单字段的Pydantic 模型,然后把路径操作函数中的参数声明为Form即可。完整可运行示例(对应 docs_src/request_form_models/tutorial001_an_py310.py):
from typing import Annotated from fastapi import FastAPI, Form from pydantic import BaseModel app = FastAPI() class FormData(BaseModel): username: str password: str @app.post("/login/") async def login(data: Annotated[FormData, Form()]): return dataFastAPI会从请求的表单数据中提取每个字段的数据,完成 Pydantic 校验后,把定义好的 Pydantic 模型实例传递给你的端点函数。
底层实现:Form 继承自 Body
从源码结构看,Form在 fastapi/params.py 中定义为class Form(Body),即表单参数在内部被当作一种特殊的 Body 参数处理。其构造函数签名为:
class Form(Body): def __init__( self, default: Any = Undefined, *, default_factory: Callable[[], Any] | None = _Unset, annotation: Any | None = None, media_type: str = "application/x-www-form-urlencoded", alias: str | None = None, # ... 以及 gt/ge/lt/le、min_length/max_length、pattern、discriminator、strict 等 )关键点是默认media_type为"application/x-www-form-urlencoded"——这意味着默认的表单模型端点接收的是 URL 编码的表单数据(浏览器<form>默认提交格式),而不是multipart/form-data文件上传格式。参数解析完成后,FastAPI 按模型定义逐字段提取并校验,最终端点拿到的是类型化的FormData实例,而不是原始字典。
在 /docs 界面验证
你可以在/docs的文档 UI 中直接测试该端点(见文首截图)。OpenAPI Schema 会正确生成表单请求体。测试用例 tests/test_tutorial/test_request_form_models/test_tutorial001.py 中的test_openapi_schema断言了生成的 Schema 结构,核心片段如下:
{ "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": {"$ref": "#/components/schemas/FormData"} } }, "required": true } }可以看到:请求体以application/x-www-form-urlencoded为 content type,Schema 通过$ref指向组件区中的FormData模型定义,且标记为required: true。组件区中FormData的定义为:
{ "FormData": { "properties": { "username": {"type": "string", "title": "Username"}, "password": {"type": "string", "title": "Password"} }, "type": "object", "required": ["username", "password"], "title": "FormData" } }这意味着 API 客户端可以基于 OpenAPI 规范自动生成表单请求代码,字段类型与必填约束都来自你的 Pydantic 模型。
校验行为:缺字段与内容类型不符都会得到 422
同一测试文件还验证了多种失败场景,对实际联调很有参考价值:
| 请求方式 | 结果 |
|---|---|
POST /login/,data={"username": "Foo", "password": "secret"} | 200,返回{"username": "Foo", "password": "secret"} |
缺少password字段 | 422,type: "missing",loc: ["body", "password"],msg: "Field required" |
缺少username字段 | 422,type: "missing",loc: ["body", "username"] |
| 完全不携带数据 | 422,两个字段均报missing |
以 JSON 方式发送(json={...}而非表单数据) | 422,两个字段均报missing |
最后一条值得特别注意:如果客户端用 JSON 而不是表单编码发送数据,FastAPI 无法从表单数据中提取到任何字段,会以"字段缺失"的方式返回422校验错误,而不是成功接收。
禁止额外的表单字段
在某些特殊使用场景(可能并不常见)下,你希望将表单字段限制为 Pydantic 模型中声明的那些字段,并禁止任何额外字段。此能力自 FastAPI0.114.0起支持。
方法是通过 Pydantic 的模型配置,将extra字段设置为forbid(对应 docs_src/request_form_models/tutorial002_an_py310.py):
class FormData(BaseModel): username: str password: str model_config = {"extra": "forbid"}如果客户端尝试提交额外数据,会收到一个错误响应。例如,客户端尝试发送以下表单字段:
username:Rickpassword:Portal Gunextra:Mr. Poopybutthole
它将收到一个提示extra字段不被允许的 Error 响应:
{ "detail": [ { "type": "extra_forbidden", "loc": ["body", "extra"], "msg": "Extra inputs are not permitted", "input": "Mr. Poopybutthole" } ] }源码与测试印证
extra = "forbid"的影响体现在两个层面,均可在仓库中找到证据:
- 运行时校验:tests/test_tutorial/test_request_form_models/test_tutorial002.py 中的
test_post_body_extra_form用data={"username": "Foo", "password": "secret", "extra": "extra"}发起请求,断言返回422,且detail中为type: "extra_forbidden"、loc: ["body", "extra"]的校验错误——与上文文档给出的错误响应结构完全一致。 - OpenAPI Schema 同步更新:
test_tutorial002.py中的test_openapi_schema断言生成的FormDataSchema 中额外出现了"additionalProperties": false(tutorial001 的对应 Schema 中没有这一项)。也就是说extra = "forbid"不仅影响运行时行为,还会反映到对外发布的 API 契约中,让 API 消费方能明确感知"不允许额外字段"。
从源码结构看,这一行为源自 Pydantic 模型配置与 FastAPI 表单参数解析的结合:Form参数在内部走 Body 参数流程(见 fastapi/params.py 中Form(Body)的定义),而 Pydantic 模型自身的model_config会原样参与实例化与 Schema 导出,因此无需 FastAPI 侧做特殊处理即可同时作用于校验与文档生成。
总结
- 你只需要声明一个包含期望表单字段的Pydantic 模型,并把参数标记为
Form(),FastAPI 就会自动从请求的表单数据中逐字段提取并校验,然后把模型实例交给端点函数(FastAPI0.113.0+); - 表单功能依赖
python-multipart包,FastAPI 内部通过ensure_multipart_is_installed()强制检查该依赖; Form参数默认以application/x-www-form-urlencoded接收数据,OpenAPI 文档会自动生成对应的必填请求体 Schema,便于 API 文档展示与客户端代码生成;- 通过
model_config = {"extra": "forbid"}可以禁止客户端提交模型之外的额外表单字段,触发extra_forbidden校验错误,并同步在 OpenAPI Schema 中标记additionalProperties: false(FastAPI0.114.0+); - 相关示例代码见 docs_src/request_form_models/ 目录,回归测试见 tests/test_tutorial/test_request_form_models/ 目录,可对照源码验证上述全部行为。
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考