尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FastAPI 表单模型(Form Models)实战:用 Pydantic 模型声明与校验表单字段

FastAPI 表单模型(Form Models)实战:用 Pydantic 模型声明与校验表单字段 FastAPI 表单模型Form Models实战用 Pydantic 模型声明与校验表单字段【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapiForm Models表单模型是 FastAPI 提供的一种声明式写法把 HTML 表单中要接收的字段统一建模为一个Pydantic 模型再用Form标注为函数参数即可获得完整的字段抽取、类型校验、文档生成与错误反馈。本文面向登录表单、OAuth 表单、搜索筛选等application/x-www-form-urlencoded场景读完你将掌握如何用一条Annotated[FormModel, Form()]替代大量手写字段解析如何通过model_config {extra: forbid}严格拒绝未声明的表单字段并能理解 FastAPI 在底层如何校验缺失字段、如何约束请求媒体类型。本指南对应的规范文档位于 docs/en/docs/tutorial/request-form-models.md韩文版见 docs/ko/docs/tutorial/request-form-models.md示例代码保存在 docs_src/request_form_models/ 目录。表单模型是什么能解决什么问题在常规的 FastAPI 接口中接收表单往往是逐个参数声明async def login(username: str Form(), password: str Form()): ...当表单字段较多时这种写法不仅冗长而且缺少一个整体结构来约束和复用字段集合。Form Models改变了这一方式——你可以先用 Pydantic 的BaseModel把一组表单字段定义为一个类class FormData(BaseModel): username: str password: str然后在路径操作函数中把整个模型作为参数并用Form()标注它接收的是表单数据。FastAPI 会从请求的表单数据中把username、password等每个字段逐个抽取出来校验后组装成一个FormData实例交给你——这与把 JSON 请求体整体绑定到一个 Pydantic 模型的体验完全一致只是数据来源变成了表单。环境准备先安装 python-multipart表单数据解析依赖python-multipart库因此使用前必须先安装它$ uv add python-multipart如果不安装就使用FormFastAPI 会在启动/请求阶段直接报错。仓库中 fastapi/dependencies/utils.py 的ensure_multipart_is_installed()会做双重检查既检测完全没有安装的情况提示Form data requires python-multipart to be installed也会拦截误装了同名的错误包multipart提示应先pip uninstall multipart再安装正确的python-multipart。版本前提表单模型能力自FastAPI0.113.0起支持其中禁止额外字段extra: forbid自0.114.0起支持。第一步定义一个表单模型并接收表单请求以登录接口为例完整代码如下出自 docs_src/request_form_models/tutorial001_an_py310.pyfrom 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 data如果你所在项目不使用Annotated语法也可以写成等价形式见 docs_src/request_form_models/tutorial001_py310.pyapp.post(/login/) async def login(data: FormData Form()): return data两种写法效果一致。需要注意的关键点FormData中每个字段对应一个必填的表单字段。请求若缺失任一字段FastAPI 会返回422校验错误而不是静默地塞入None。参数整体被Form()标注后该接口的requestBody媒体类型就固定为application/x-www-form-urlencoded因此只能接收表单编码的请求详见下文请求方式约束小节。Pydantic 模型本身就是一套完整的校验与类型系统字段上可以叠加默认值、Field(...)约束、嵌套结构等能力此处统一继承使用。底层原理Form 是如何处理模型类型字段的从源码可以更清晰地理解该特性的实现方式在 fastapi/params.py 中Form是Body的子类其默认media_type为application/x-www-form-urlencoded。当请求需要上传文件时FastAPI 的File会把媒体类型切换为multipart/form-data二者同属python-multipart负责解析的范畴。在 fastapi/dependencies/utils.py 中只要识别到参数是Form类型就会先调用ensure_multipart_is_installed()确保解析依赖已就绪。当注解不是标量类型而是 Pydantic 模型时FastAPI 会把整个请求体当作该模型进行反序列化这与 请求体Body教程 中单个模型作为请求体的机制一致区别仅在于数据来源是表单编码而非 JSON。也就是说表单模型并非新引入一套校验引擎而是把成熟的 Pydantic 模型校验链路复用到表单数据上——表单怎么解析由python-multipart负责字段结构与校验规则则由你的BaseModel类声明。在交互式文档中验证启动应用后访问/docsSwagger UI即可看到/login/接口的请求体说明Schema 引用你定义的FormData模型并明确列出username、password为必填字段媒体类型标注为application/x-www-form-urlencoded。也可以在/docs页面直接点击Try it out填入字段并执行直观验证表单字段的解析与校验行为。行为验证从测试用例理解接口约定仓库为表单模型提供了完整的行为级测试建议对照阅读tests/test_tutorial/test_request_form_models/test_tutorial001.py覆盖基础用法。tests/test_tutorial/test_request_form_models/test_tutorial002.py覆盖禁止额外字段用法。测试揭示了几个容易被忽略的细节1. 正确数据会被原样回显response client.post(/login/, data{username: Foo, password: secret}) assert response.status_code 200 assert response.json() {username: Foo, password: secret}2. 缺失字段返回 422且错误定位在body层response client.post(/login/, data{username: Foo}) # 422detail 中 loc 为 [body, password]type 为 missing注意错误路径loc是[body, password]说明模型整体被视为请求体。3. 请求方式被约束传 JSON 同样报 422由于该路由只声明了表单媒体类型即使用client.post(/login/, json{...})发送 JSONFastAPI 也不会把 JSON 当作表单解析而是返回missing类型的 422 错误——表单字段一个都取不到。4. OpenAPI 生成的 Schema 与模型完全对应测试快照显示/openapi.json中requestBody.content仅包含application/x-www-form-urlencoded其 schema$ref指向FormData而FormData组件中username、password均为type: string且位于required列表中。这意味着字段结构、必填性、媒体类型全部由模型与Form()声明自动推导无需手写任何 OpenAPI 片段。进阶禁止模型之外的额外表单字段在多数场景下客户端多传几个字段并无大碍FastAPI 默认会忽略未声明的字段。但在某些对安全性或契约严谨性要求较高的场景例如避免表单注入、强制前后端契约一致你可能希望只接受模型中声明的字段多余字段一律报错。做法是在 Pydantic 模型中通过model_config把extra配置为forbid完整代码见 docs_src/request_form_models/tutorial002_an_py310.pyfrom typing import Annotated from fastapi import FastAPI, Form from pydantic import BaseModel app FastAPI() class FormData(BaseModel): username: str password: str model_config {extra: forbid} app.post(/login/) async def login(data: Annotated[FormData, Form()]): return data此时若客户端发送如下表单字段username:Rickpassword:Portal Gunextra:Mr. Poopybutthole就会收到 422 错误响应明确告知extra字段不被允许{ detail: [ { type: extra_forbidden, loc: [body, extra], msg: Extra inputs are not permitted, input: Mr. Poopybutthole } ] }对应测试 tests/test_tutorial/test_request_form_models/test_tutorial002.py 验证了该行为正常字段组合返回 200混入extra后返回 422 且错误类型为extra_forbidden。配置extra forbid的另一个连带效应会体现在生成的 OpenAPI 文档中FormDataschema 会额外出现additionalProperties: False向 API 消费者明示除声明字段外不接受任何额外字段。小结使用 Pydantic 模型声明表单字段是 FastAPI 简化表单开发的推荐姿势一组表单字段收敛为一个可复用的BaseModel路由参数从N 个 Form()变成1 个Annotated[Model, Form()]字段的抽取、类型校验、必填校验、422 错误信息由框架自动完成loc指向body.field通过model_config {extra: forbid}可进一步收紧契约拒绝未声明字段所有结构信息媒体类型、字段类型、必填项、是否允许额外字段都会自动反映到/docs与/openapi.json中。表单模型适合纯文本字段的application/x-www-form-urlencoded表单如果还需要同时上传文件可参考仓库中 请求表单与文件Request Forms and Files 的相关教程在表单字段之外配合File/UploadFile使用。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表