当前位置: 首页 > news >正文

FastAPI-P1:Pydantic模型与参数额外信息

欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。

目录

  • 引言
  • 1 Pydantic
    • 1.1 Pydantic的便利
  • 2 为参数声明额外信息和校验
    • 2.1 Query
    • 2.2 Annotated
    • 2.3 Path
      • 2.3.1 核心概念与用法
    • 2.4 Body
      • 2.4.1 核心概念与用法

引言

本篇主要内容:FastAPI常用的Pydantic模型、接口参数声明额外信息和校验做法。
适合快速复习、预览。

资料:

  • fastapi官网:https://fastapi.tiangolo.com/tutorial

1 Pydantic

FastAPI 是基于 Starlette (Web 部分) 和 Pydantic (数据验证部分) 构建的。
其中,Pydantic 是一款用于 Python 数据验证和设置管理 的库。

简单来说,它的核心作用就是:

  • 把普通的数据(比如字典、JSON)变成结构化的数据对象。
  • 在转换过程中,严格检查数据是否符合你定义的规则。

Pydantic的核心是BaseModel。通过继承它来定义自己的数据模型,这个模型就是告诉Pydantic开发者期望的数据结构。

from pydantic import BaseModel, EmailStr
from typing import Optionalclass User(BaseModel):name: strage: intemail: Optional[EmailStr] = None

上面这个 User 类就定义了一个模型:

  • 它必须有 name 字段,且类型是 str
  • 它必须有 age 字段,且类型是 int
  • 它有一个可选的 email 字段,类型是 EmailStr(Pydantic 内置的邮箱验证类型),默认值为 None

Pydantic会自动校验模型内容:

data = {"name": "张三","age": "25", # 注意这里 age 是字符串"email": "zhangsan@example.com"
}try:user = User(**data)print(user.name)  # 输出: 张三print(user.age)   # 输出: 25 (Pydantic 自动转换为整数)print(user.email) # 输出: zhangsan@example.comprint(user)       # 输出: name='张三' age=25 email='zhangsan@example.com'
except Exception as e:print(e)

在这个例子中,Pydantic 做了以下几件事:

  • 它检查了所有字段。
  • 它发现 age 是字符串 "25",但模型要求是 int,于是它 自动完成了类型转换
  • 它甚至检查了 email 的格式,确保它是一个有效的邮箱地址。

与在路径操作函数参数中使用 QueryPathBody 声明额外验证和元数据相同的方式一样,可以在 Pydantic 模型内部使用 Pydantic 的 Field 声明验证和元数据。

from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModel, Fieldapp = FastAPI()class Item(BaseModel):name: strdescription: 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 的工作方式与 QueryPathBody 相同,它具有所有相同的参数等。

1.1 Pydantic的便利

同样是继承,Java 的 Object 类是所有类的最终父类,主要提供了一些基础方法和抽象约定,是面向对象体系的根本标识,目的是为了多态和通用性。

Pydantic的BaseModel继承后,Python Class的管理会简约、便利许多。其则赋予了 Python 类强大的数据管理能力,让数据模型定义、验证和使用变得异常简洁和高效。

  1. 自动化数据验证和类型转换:你不用再手动写大量的 if 语句来检查数据,大大减少了冗余代码。
  2. 清晰的数据模型:你的数据结构一目了然,方便团队协作和代码维护。
  3. 兼容 Python 类型提示:它完美结合了 Python 3.5+ 的类型提示,让你的代码更现代、更易读。
  4. 自动生成文档:Pydantic 模型可以自动生成 OpenAPI (Swagger) 格式的 API 文档,这在构建 API 时非常有用。
  5. 高性能:底层使用 Rust 编写,验证速度非常快,尤其适合处理大量数据。

尽管和Java的Object设计上不一样。但是在继承、组合上与Java对象的用法还是一样的。继承 Pydantic 模型的 Python 类仍然是 Pydantic 模型。 Pydantic 模型可以互相嵌套。

2 为参数声明额外信息和校验

可以通过Query和Annotated来做。

2.1 Query

在 FastAPI 中,Query 是一个专门用于定义 查询参数(Query Parameters) 的函数。

使用 Query 的主要目的是:

  1. 声明参数是查询参数:告诉 FastAPI 这个变量对应的是 URL 中的查询参数。
  2. 设置默认值:如果客户端没有提供这个参数,它会有一个默认值。
  3. 添加额外的验证和元数据:比如最小值、最大长度、描述信息等。
from fastapi import FastAPI, Queryapp = FastAPI()@app.get("/products/")
async def read_products(# 必需的查询参数,描述为 "产品ID",最小长度1,最大长度50product_id: str = Query(..., min_length=1, max_length=50, description="The ID of the product"),# 可选的查询参数,默认值是0,描述为 "跳过多少个产品"skip: int = Query(0, description="Number of products to skip"),# 可选的查询参数,默认值是10,描述为 "获取多少个产品",最小值1,最大值100limit: int = Query(10, description="Number of products to retrieve", ge=1, le=100)
):return {"product_id": product_id, "skip": skip, "limit": limit}
  • ... (Ellipsis):表示这个参数是必需的,没有默认值。

  • min_length, max_length:字符串长度验证。

  • ge (Greater than or Equal)、le (Less than or Equal):数值范围验证。

  • description:在生成的 OpenAPI 文档中显示这个参数的说明。

  • alias:如果查询参数名和变量名不一致,可以使用 alias 指定。

  • deprecated:标记参数已废弃。

2.2 Annotated

Annotated 是 Python 3.9 引入的一个类型提示工具,位于 typing 模块中。它允许你在类型提示中添加额外的元数据。FastAPI 从 0.95.0 版本开始,强烈推荐使用 Annotated 结合 Query, Path, Body 等函数。

from typing import Annotated, Optional # 导入 Optional 以便演示旧式可选参数
from fastapi import FastAPI, Query, Path, Bodyapp = FastAPI()# --- 查询参数 (Query Parameters) ---
@app.get("/items/")
async def read_items(# 示例 1: 可选查询参数 (Python 3.10+ 推荐语法: 'str | None')# 如果不提供 'q',它将是 Noneq: Annotated[str | None, Query(min_length=3, max_length=50, description="搜索查询字符串")] = None,# 示例 2: 带有默认值的可选查询参数# 如果不提供 'offset',它将是 0offset: Annotated[int, Query(description="跳过的结果数量")] = 0,# 示例 3: 必填查询参数 (使用 '...' 明确标记)# 客户端必须提供 'limit' 参数limit: Annotated[int, Query(ge=1, le=100, description="返回的最大结果数量")] = ...,# 示例 4: 旧式可选查询参数 (Python 3.9 及更早版本常见)# 如果不提供 'category',它将是 Nonecategory: Annotated[Optional[str], Query(max_length=20, description="产品类别")] = None,
):results = {"q": q, "offset": offset, "limit": limit, "category": category, "items": []}# 这里可以根据参数进行数据查询逻辑if q:results["items"].append({"item_id": "Foo", "name": f"Foo {q}"})if category:results["items"].append({"item_id": "Bar", "name": f"Bar in {category}"})return results# --- 路径参数 (Path Parameters) ---
@app.get("/users/{user_id}")
async def get_user_by_id(# 路径参数默认就是必填的,但我们可以用 Annotated 添加元数据user_id: Annotated[int, Path(ge=1, description="用户的唯一ID")]
):return {"user_id": user_id, "message": "Fetching user details"}# --- 请求体 (Request Body) ---
from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = None@app.post("/items/")
async def create_item(# 整个请求体默认就是必填的,Annotated 用于添加更多信息item: Annotated[Item, Body(embed=True, description="要创建的商品数据")]
):return {"message": "Item created successfully", "item": item}

Annotated 的优势:

  • 分离关注点:将参数的类型定义和 FastAPI 特定的元数据定义清晰地分离开来。
    • q: str 负责类型提示
    • Query(...) 负责 FastAPI 参数定义和验证
  • 更易读:当你有多个装饰器或复杂的参数定义时,Annotated 让代码结构更清晰。
  • 兼容性:它与 Python 现有的类型检查工具(如 MyPy)更好地配合。

2.3 Path

Path() 用于从 URL 路径中提取参数。这些参数是 URL 本身的一部分,例如 /items/{item_id} 中的 item_id

2.3.1 核心概念与用法

  • 路径参数: 在 FastAPI 路由中,你可以在 URL 路径中使用大括号 {} 定义路径参数。

  • 类型注解: Path() 通常与 Python 的类型注解一起使用,FastAPI 会自动为你进行数据类型转换和验证。

  • 默认值与校验: 你可以使用 Path() 来设置默认值、添加校验规则(如最小/最大长度、最小值/最大值等)以及添加元数据(如描述、示例)。

from fastapi import FastAPI, Path, Queryapp = FastAPI()@app.get("/items/{item_id}")
async def read_item(# item_id 是路径参数,且是必需的。# 使用 `| None` 表示可选,但这里我们希望它是必需的,所以没有 `| None`item_id: int = Path(...,  # `...` 表示此参数是必需的 (required)title="The ID of the item to get",description="Must be an integer greater than 0 and less than 1000",ge=1, # Greater than or equal to 1lt=1000 # Less than 1000),# q 是查询参数,可以是字符串或 None,默认值为 Noneq: str | None = Query(None, # 默认值min_length=3,max_length=50,description="Optional query string for the item search")
):"""检索特定 ID 的商品信息。"""results = {"item_id": item_id}if q:results.update({"q": q})return results# 💡 运行 FastAPI 应用:
# 保存以上代码为 `main.py`
# 在终端运行: `uvicorn main:app --reload`# 🌐 访问示例:
# - http://127.0.0.1:8000/items/500  (item_id = 500, q = None)
# - http://127.00.1:8000/items/10?q=somequery (item_id = 10, q = "somequery")
# - http://127.00.1:8000/items/0   (会触发校验错误,因为 item_id 必须 >= 1)

2.4 Body

Body() 用于从 HTTP 请求的请求体中提取数据。这通常用于 POSTPUTPATCH 请求,这些请求通常会发送结构化的数据(如 JSON)。

2.4.1 核心概念与用法

  • 请求体: 客户端向服务器发送的数据,通常以 JSON、XML 或表单数据的形式存在。FastAPI 主要推荐使用 JSON。

  • Pydantic 模型: Body() 最常与 Pydantic 模型一起使用。Pydantic 模型定义了请求体的结构和数据类型,FastAPI 会自动将接收到的 JSON 数据解析并验证为 Pydantic 模型的实例。

  • 单个或多个体参数: 你可以在一个路径操作函数中定义一个或多个 Body() 参数。

  • 默认值与校验: 类似于 Path(),你可以设置默认值和添加校验规则。

from fastapi import FastAPI, Body
from pydantic import BaseModelapp = FastAPI()# 定义一个 Pydantic 模型来表示请求体的数据结构
class Item(BaseModel):name: str# description 是可选的字符串,默认值是 Nonedescription: str | None = Noneprice: float# tax 是可选的浮点数,默认值是 Nonetax: float | None = Noneclass User(BaseModel):username: strfull_name: str | None = None@app.post("/items/")
async def create_item(# item 是请求体参数,它是 Item 类型的 Pydantic 模型实例。# 同样,`...` 表示这个请求体是必需的。item: Item = Body(...,title="Item to be created",description="Details of the new item including name, description, price, and optional tax.",example={ # 为 OpenAPI 文档提供示例"name": "Super Laptop","description": "A powerful machine for all your needs.","price": 1500.0,"tax": 120.0})
):"""创建一个新的商品记录。"""return item@app.post("/offers/{item_id}")
async def make_offer(item_id: int = Path(..., description="The ID of the item for the offer"),# item 作为请求体参数,FastAPI 默认会将其解析为 Item 实例item: Item,# user 明确指定为另一个请求体参数,使用 `Body(...)`user: User = Body(...,title="User making the offer",description="Details of the user making the offer.",example={"username": "jane.doe","full_name": "Jane Doe"})
):"""为一个商品创建报价。"""return {"item_id": item_id, "item": item, "user": user}# 🌐 测试示例 (使用 Postman, Insomnia 或 cURL):# 🚀 POST http://127.0.0.1:8000/items/
# Headers: Content-Type: application/json
# Body (JSON):
# {
#     "name": "Wireless Mouse",
#     "description": "Ergonomic design",
#     "price": 25.99
# }
# (tax 字段由于是 `None` 默认值,可以不传)# 🚀 POST http://127.0.0.1:8000/offers/123
# Headers: Content-Type: application/json
# Body (JSON):
# {
#     "item": {
#         "name": "Cool Gadget",
#         "price": 99.99
#     },
#     "user": {
#         "username": "alice_smith"
#     }
# }
http://www.dtcms.com/a/278726.html

相关文章:

  • ThreadLocal结构
  • 02 51单片机之LED闪烁
  • 用TensorFlow进行逻辑回归(三)
  • 计算机网络通信的相关知识总结
  • Faiss库
  • 玩转Docker | 使用Docker部署TeamMapper思维导图应用程序
  • JavaScript 性能优化实战:深入性能瓶颈,精炼优化技巧与最佳实践
  • 深入理解MyBatis延迟加载:原理、配置与实战优化
  • 浏览器自动化领域的MCP
  • Ubuntu22.04 python环境管理
  • 前端常见十大问题讲解
  • priority_queue的使用和模拟实现以及仿函数
  • 【记忆化搜索 BFS】P9038 [PA 2021] Butelki|普及+
  • 赋能公安行业信息化PPT(46页)
  • 软考 系统架构设计师系列知识点之杂项集萃(111)
  • [C语言语法笔记] 批量处理错误 goto
  • make_ext4fs工具详解
  • Why C# and .NET are still relevant in 2025
  • Windows 上安装 FFmpeg
  • Spring的`@Value`注解使用详细说明
  • Git 使用技巧与原理(一)—— 基础操作
  • SpringMVC3
  • 后端接口通用返回格式与异常处理实现
  • SpringMVC2
  • C++中STL六大组件List的简单介绍
  • 基于GA遗传优化的多边形拟合算法matlab仿真
  • 能源管理系统中的物联网数据采集:深度探索与操作指南
  • AI Linux 运维笔记
  • vmware使用说明
  • Python密码学库之pycryptodome使用详解