小白python入门 - 42. 请求体与 Pydantic 模型

发布时间:2026/7/27 6:45:43

小白python入门 - 42. 请求体与 Pydantic 模型
1. 本课定位是什么、为何重要上一课书签 API 已经能「读列表、读详情、删除」参数来自路径和查询串。可是创建、更新资源时客户端通常要发一整段结构化 JSON——标题、URL、是否收藏——而不是把长字段都塞进 Query。手写dict.get东一块西一块很容易漏校验也容易在响应里把内部字段一起泄漏出去。本课引入Pydantic 模型与 FastAPI 的 Body 绑定用类描述数据形状框架负责解析、校验、生成文档并用 Create / Update / Out 分模型把「入库字段」和「对外字段」拆开。数据仍用内存存储。学完你应能 POST 创建、PATCH 部分更新读懂 422 的loc并确认internal_score不会出现在响应里。概念一句话请求体 BodyHTTP 正文里的载荷API 里多为 JSON模型 ModelBaseModel子类字段 类型 约束response_model规定响应长什么样避免内部字段漏出exclude_unset部分更新时只应用客户端真正传了的字段为何重要无边界模型 脏数据入库 敏感字段出站。对比已学已学本课Path/Query 简单类型Body 嵌套结构内存里直接塞 dictCreate/Update/Out分模型422 来自路径类型错422 也可来自 Body 校验失败只有读删加上创建与部分更新2. 本质入站校验、出站过滤可以把模型想成海关入关检查护照字段全不全、格式对不对出关只盖允许出境的章内部备注条不给外人看。FastAPI 在进路由函数前完成入站解析在返回时按response_model再滤一遍。上一课失败分 404/422本课 422 会更常见——空标题、非法 URL、类型不对都会在边界被拦住。先建立「边界合同」直觉再拆三个模型避免一个类打天下。本质JSON → 模型实例失败 422→ 业务用属性 → 按 Out 序列化响应。客户端 JSON | v Pydantic 校验 ----失败--- 422 loc/msg | 成功 v 路由函数业务逻辑 | v response_model 过滤 ----- 响应 JSON3. 约束与常见坑模型用错比不用更危险一个模型既当创建又当更新会导致「更新必须传全字段」或「响应带回哈希」。部分更新若model_dump()不带exclude_unset没传的字段可能变成 None 覆盖原值。这一节把分模型、exclude_unset、response_model 过滤语义钉死。注意过滤输出 ≠ 修改内存对象——internal_score仍可在 store 里只是不返回。约束Create / Update / Out 分开——入库字段 ≠ 对外字段。HttpUrl、Field(min_length...)等在边界拦住脏数据。部分更新用exclude_unsetTrue避免「没传的字段被写成 null」。响应模型会丢掉未声明字段如internal_score。Content-Type 需为application/jsoncurl 要带 Header。常见坑坑现象正确直觉一个模型打天下更新被迫传全字段或泄露敏感字段拆 Create/Update/Out更新用全量 dump未传字段变Nonemodel_dump(exclude_unsetTrue)把内部 dict 当 API 契约字段漂移、泄密明确 Out 模型忽略 422 的loc不知道哪错读loc/msg忘记 Content-Type解析失败或怪错JSON Header以为 response_model 会删内存字段调试以为「存没了」只影响序列化输出4. 三种模型对照Create 描述「新建必须提供什么」Update 字段全可选服务「改一点」Out 描述「客户端永远只能看见什么」。三者字段可以重叠但职责不同。书签域字段保持简单title、url、is_favorite外加 Out 的 id。内部internal_score只存在 store不进 Out。模型方向典型字段BookmarkCreate客户端 → 服务端title, url, is_favoriteBookmarkUpdate客户端 → 服务端字段全可选BookmarkOut服务端 → 客户端id 安全字段frompydanticimportBaseModel,Field,HttpUrlclassBookmarkCreate(BaseModel):title:strField(min_length1,max_length200)url:HttpUrl is_favorite:boolFalseclassBookmarkUpdate(BaseModel):title:str|NoneField(defaultNone,min_length1,max_length200)url:HttpUrl|NoneNoneis_favorite:bool|NoneNoneclassBookmarkOut(BaseModel):id:inttitle:strurl:stris_favorite:bool写法vs说明参数body: BookmarkCreateQueryq: str前者吃 Body后者吃查询串response_modelOut裸return dict前者锁定对外形状Field约束业务里if边界校验优先模型5. 方法与能力按用途归组不要求背完整 Pydantic 文档。入门会这几类能力即可约束、导出、响应声明、嵌套了解、从 ORM 构造下下课。表格当抽屉需要时知道去哪找而不是一次记光所有 API。用途能力约束Field、HttpUrl邮箱类需额外包了解导出model_dump()/model_dump(exclude_unsetTrue)响应response_model...、status_code201从 ORMOut 上model_config {from_attributes: True}第 44 课嵌套字段类型为另一个BaseModel或list[...]HttpUrl 注意入站是 URL 类型写入 dict/存储时常str(body.url)。6. POST 与 PATCH 语义POST 创建成功常用201响应体是新建资源Out。PATCH 部分更新只传要改的字段。PUT 全量替换本课不展开避免和 PATCH 搅在一起。状态码与模型课绑定没有 Body 模型时创建接口几乎写不稳。方法典型用途本课状态码POST/bookmarks新建201 OutPATCH/bookmarks/{id}改部分字段200 OutGET读可加 response_model200DELETE删204上节修改前无模型修改后手动 if 检查 titleField min_lengthreturn 全量 dictresponse_model 滤掉内部字段PATCH 覆盖成 Noneexclude_unset 只改传入项7. 阅读 422 响应校验失败时FastAPI 返回的 JSON 里detail常是列表每项有loc、msg、type。会读loc就能快速定位是 body 的哪个字段错了。这是联调基本功不要只看「失败了」要看「哪里失败」。字段含义loc错误位置如[body,title]msg人话/校验信息type错误类型代码空 title 实验预期状态码 422loc含title。8. 落地场景书签创建与收藏切换场景仍是书签 API新建一条、只改是否收藏、确认内部评分永不返回。内存 store 用自增 id重启丢失——与 41 课一致。把「防泄密」当成功能需求而不是可选美化。场景做法新建书签POST Create → 201 Out改是否收藏PATCH Update只传is_favorite防泄密internal_score不进 Out非法标题422不进 store9. 小步示例response_model 过滤用最小片段理解「内存有、响应无」。综合实践会把片段拼成完整项目。item{id:1,title:Example,url:https://example.com,is_favorite:True,internal_score:42,}# 若 response_modelBookmarkOut响应不含 internal_score位置internal_score_store[1]可以有HTTP 响应 JSON不应有10. 环境准备依赖与 41 课相同本课增加schemas.py。Windows 推荐 Cygwin/WSL 跑 heredoc。mkdir-p~/python-lab/src/day42/routerscd~/python-lab/src/day42 pipinstallfastapi0.110uvicorn[standard]0.2711. 综合实践完整可运行脚本写入 schemas、router、main启动后用三条 curl合法创建、非法 title、PATCH 只改收藏。对照表检查状态码与字段。服务占前台时另开终端。Windows 用 Cygwin/WSL 或手建文件。mkdir-p~/python-lab/src/day42/routerscd~/python-lab/src/day42catschemas.pyEOF from pydantic import BaseModel, Field, HttpUrl class BookmarkCreate(BaseModel): title: str Field(min_length1, max_length200) url: HttpUrl is_favorite: bool False class BookmarkUpdate(BaseModel): title: str | None Field(defaultNone, min_length1, max_length200) url: HttpUrl | None None is_favorite: bool | None None class BookmarkOut(BaseModel): id: int title: str url: str is_favorite: bool EOFcatrouters/bookmarks.pyEOF from fastapi import APIRouter, HTTPException from schemas import BookmarkCreate, BookmarkOut, BookmarkUpdate router APIRouter(prefix/bookmarks, tags[bookmarks]) _store: dict[int, dict] {} _next_id 1 router.get(, response_modellist[BookmarkOut]) def list_bookmarks(): return list(_store.values()) router.post(, response_modelBookmarkOut, status_code201) def create_bookmark(body: BookmarkCreate): global _next_id item { id: _next_id, title: body.title, url: str(body.url), is_favorite: body.is_favorite, internal_score: 42, } _store[_next_id] item _next_id 1 return item router.get(/{bookmark_id}, response_modelBookmarkOut) def get_bookmark(bookmark_id: int): item _store.get(bookmark_id) if not item: raise HTTPException(status_code404, detailbookmark not found) return item router.patch(/{bookmark_id}, response_modelBookmarkOut) def update_bookmark(bookmark_id: int, body: BookmarkUpdate): item _store.get(bookmark_id) if not item: raise HTTPException(status_code404, detailbookmark not found) data body.model_dump(exclude_unsetTrue) if url in data and data[url] is not None: data[url] str(data[url]) item.update(data) return item router.delete(/{bookmark_id}, status_code204) def delete_bookmark(bookmark_id: int): if bookmark_id not in _store: raise HTTPException(status_code404, detailbookmark not found) del _store[bookmark_id] return None EOFcatrouters/__init__.pyEOF EOF cat main.py EOF from fastapi import FastAPI from routers import bookmarks app FastAPI(titleDay42 Bookmark API, version0.1.0) app.include_router(bookmarks.router) app.get(/health) def health(): return {status: ok} EOFuvicorn main:app--reload--host127.0.0.1--port8000验证curl-s-XPOST http://127.0.0.1:8000/bookmarks\-HContent-Type: application/json\-d{title:Example,url:https://example.com,is_favorite:true}curl-s-XPOST http://127.0.0.1:8000/bookmarks\-HContent-Type: application/json\-d{title:,url:https://example.com}curl-s-XPATCH http://127.0.0.1:8000/bookmarks/1\-HContent-Type: application/json\-d{is_favorite:false}curl-shttp://127.0.0.1:8000/bookmarks/1预期请求结果合法 POST201JSON无internal_score空 title422loc含body/titlePATCH只改is_favoritetitle 仍在GET 详情仍无internal_score关键语义response_model过滤输出 ≠ 删除内存里的internal_score。12. 嵌套与列表了解真实书签可能带 tags 列表或 owner 嵌套对象。入门知道「字段类型可以是 list 或另一个 BaseModel」即可本课作业不强制嵌套。列表响应可用response_modellist[BookmarkOut]综合实践已示范。classTag(BaseModel):name:strclassBookmarkCreateNested(BaseModel):title:strurl:HttpUrl tags:list[Tag][]13. 常见问答QCreate 和 Out 都有 title为何还要两个类AOut 需要 idCreate 不应让客户端指定 id未来 Out 还可能隐藏更多字段。QUpdate 全是 Optional 会不会太松APATCH 语义就是可选可用业务规则要求「至少改一个字段」进阶。Q非法 URL 是 422 还是 400APydantic/FastAPI 校验失败通常 422。Q能直接return body吗ACreate 没有 id应构造带 id 的资源再按 Out 返回。14. 自我检查清单能解释 Body 与 Query 的差别会写 Create/Update/Out 三个模型会 POST 201 response_model会 PATCH exclude_unset会读 422 的 loc确认 internal_score 不出现在响应curl 带 Content-Type: application/json15. 与前后课衔接课关系41Path/Query/读删 → 本课 Body 写43模型稳定 → 依赖与配置分层44dict store → ORMOut 加 from_attributes总结带走Body 用模型校验Create/Update/Out 分离422 读 locresponse_model 防泄密部分更新 exclude_unset。模型是边界合同不是数据库表的镜像。请求体用 Pydantic 在边界校验。Create / Update / Out 分模型避免一个类打天下。response_model锁定对外形状过滤内部字段。PATCH 用model_dump(exclude_unsetTrue)做部分更新。校验失败读loc/msg空 title、坏 URL 多为 422。HttpUrl入库时常转为str内存仍可有内部字段。小练笔先做再看答案。可选实践故意漏掉 url 字段观察 422 loc。题 1response_modelBookmarkOut的作用题 2为何密码哈希不该出现在 UserOut题 3exclude_unsetTrue解决什么问题题 4空 title 更可能得到 404 还是 422题 5为「只改 url」设计 Update 请求 JSON 示例。题 6POST 创建成功更常见状态码A. 200 B. 201 C. 204题 7判断response_model 会从数据库/内存里物理删除未声明字段。题 8curl POST JSON 时为什么常需要Content-Type: application/json题 9可选实践POST 一条合法书签后响应 JSON 中搜索internal_score应找不到。题 10Create 模型里应不应该包含id字段让客户端指定为什么小练笔参考答案题 1按 Out 过滤/校验响应并写入 OpenAPI。题 2敏感内部数据返回即泄露。题 3部分更新时只应用客户端真正传入的字段。题 4422题 5{url:https://new.example}其它字段不传。题 6B题 7错主要影响序列化输出题 8声明正文是 JSON便于框架正确解析 Body。题 9以你运行为准响应不应出现该键。题 10一般不应id 由服务端分配避免冲突与伪造。合理即可

相关新闻

科研文献检索革新:语义理解与个性化推荐技术解析

科研文献检索革新:语义理解与个性化推荐技术解析

2026/7/27 6:45:43

1. 科研文献检索的痛点与革新契机文献检索是每个科研工作者日常工作中耗时最多的环节之一。记得我刚开始做研究时,经常花大半天时间在不同数据库间切换,用各种关键词组合反复尝试,结果要么漏掉重要文献,要么被海量无关结果淹没。这…

终极指南:用G-Helper彻底告别华硕笔记本性能焦虑

终极指南:用G-Helper彻底告别华硕笔记本性能焦虑

2026/7/27 6:35:43

终极指南:用G-Helper彻底告别华硕笔记本性能焦虑 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Expertb…

下垂控制与虚拟同步机技术在新能源并网中的Simulink仿真对比

下垂控制与虚拟同步机技术在新能源并网中的Simulink仿真对比

2026/7/27 6:35:43

1. 下垂控制与虚拟同步机技术背景解析在新能源发电系统大规模接入电网的背景下,传统的电网运行方式正面临重大变革。传统电网依赖同步发电机提供的转动惯量和阻尼特性来维持稳定,而光伏、风电等新能源发电设备通过电力电子接口并网时,往往缺乏…

WebSocket安全:Origin验证缺失与跨站劫持的防御实践

WebSocket安全:Origin验证缺失与跨站劫持的防御实践

2026/7/27 7:35:46

1. 项目概述:WebSocket安全中的“门户大开”在构建现代实时Web应用时,WebSocket协议因其全双工、低延迟的特性,已成为聊天室、在线协作、实时数据看板等场景的标配。然而,很多开发者在拥抱其便利性的同时,却常常沿用HT…

SWIG与Embind实现C++到WebAssembly的自动化绑定

SWIG与Embind实现C++到WebAssembly的自动化绑定

2026/7/27 7:35:46

1. 项目概述:当C遇见WebAssembly十年前我第一次尝试把C游戏引擎移植到浏览器时,手工编写JavaScript绑定代码花了整整两周。如今有了Embind和SWIG这样的工具链,同样的工作只需要喝杯咖啡的时间。这次要分享的正是如何用SWIG自动化生成C到Embin…

Linux文件加密实战:GnuPG、VeraCrypt与eCryptfs深度解析

Linux文件加密实战:GnuPG、VeraCrypt与eCryptfs深度解析

2026/7/27 7:35:46

1. 项目概述:为什么Linux文件加密是刚需? 在数据即资产的今天,无论你是运维工程师、开发者,还是普通的技术爱好者,只要你的工作环境是Linux,就绕不开一个核心问题:如何保护那些躺在硬盘里的敏感…

基于YOLOv5的智能养老跌倒检测系统开发实践

基于YOLOv5的智能养老跌倒检测系统开发实践

2026/7/27 7:35:46

1. 项目概述:基于YOLO的智能养老监护系统这个项目是我去年为本地一家养老院开发的智能监护系统,核心目标是解决老年人跌倒后无法及时呼救的痛点问题。根据CDC数据,65岁以上老人每年有1/3会经历跌倒,其中20%会导致严重伤害。传统监…

Laravel集成自托管AI文本检测器:低误报率方案与工程实践

Laravel集成自托管AI文本检测器:低误报率方案与工程实践

2026/7/27 7:35:46

在 Laravel 项目中集成可靠的 AI 文本检测器,特别是需要低误报率(对人工文本的误判率低)的自托管开源方案,已经成为许多内容平台、教育系统和审核工具的实际需求。与直接调用商业 API 不同,自托管方案能更好地控制数据…

数据结构和变量常量

数据结构和变量常量

2026/7/27 7:25:45

前言c语言中的数据类型是什么?为什么需要数据类型?我们用c语言编写程序是为了解决日常生活中的问题,而为了描述这些问题就需要相应的“量”,比如我在网购时,某个商品的价格、销售量、产品名称等数据都需要一个“量”来…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/26 0:04:02

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/26 0:04:02

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/26 0:04:02

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

多模态 AI 前端工程——图像上传、压缩与流式返回的协同设计

多模态 AI 前端工程——图像上传、压缩与流式返回的协同设计

2026/7/27 0:05:04

多模态 AI 前端工程——图像上传、压缩与流式返回的协同设计 一、多模态对话的「首字节延迟」:上传与流式的协同鸿沟 多模态 AI 应用的前端体验,往往卡在"首字节延迟"上。用户上传一张图片,提一个问题,然后盯着空白对…

【微科普】网红水晶香薰真相拆解:透明固体香薰并非香精结晶,一文理清各类无火香薰释香机理

【微科普】网红水晶香薰真相拆解:透明固体香薰并非香精结晶,一文理清各类无火香薰释香机理

2026/7/27 0:05:04

文章目录第一章 大众普遍存在的认知误区:水晶香薰是芳香烃结晶产物1.1 聚丙烯酸钠凝胶水晶珠体系(市面占比90%家用水晶香薰)1.2 无机盐硬质结晶载体:泻盐与钾明矾香薰原石1.3 植物多糖与PVA整块果冻型水晶香膏1.4 唯一特例&#x…

优启通3.7修改版:深度优化的PE系统维护工具

优启通3.7修改版:深度优化的PE系统维护工具

2026/7/27 0:05:04

1. 项目概述今天要跟大家分享的是一个经过深度优化的PE工具——优启通3.7(2025修改版)。这个版本是在原版基础上进行了大量功能增强和兼容性改进的12月最新版本,特别适合系统维护人员和电脑爱好者使用。作为一个长期从事IT运维的老兵&#xf…