FastAPI 学习教程 · 第2部分

请求体、查询参数与 Pydantic 模型

💡 本部分目标:学会接收用户通过 URL 传递的查询参数,以及通过 JSON 发送的请求体数据;掌握使用 Pydantic 定义和验证数据结构。


✅ 一、回顾:什么是"请求"?

当客户端(如浏览器、手机 App、Postman)向你的 API 发起请求时,可能携带以下信息:

类型 示例 用途
路径参数 /users/123 中的 123 标识特定资源
查询参数 /search?q=python&page=2 中的 q=python 用于过滤、分页等
请求体(Body) POST 请求中的 JSON 数据 提交复杂数据(如注册表单)

第1部分我们学了路径参数 ,本部分重点学习查询参数请求体


✅ 二、查询参数(Query Parameters)

查询参数出现在 URL 的 ? 后面,用 & 分隔,例如:

复制代码
/items/?skip=0&limit=10
/users?active=true&role=admin

如何在 FastAPI 中接收查询参数?

只需在函数中添加带默认值的参数,FastAPI 会自动将其识别为查询参数。

示例 1:简单查询参数

python 复制代码
# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

访问:

🔍 注意:因为 skiplimit 有默认值(= 0, = 10),所以是可选 的查询参数。

如果没有默认值(如 q: str),则该参数是必填的。

示例 2:必填 vs 可选查询参数

python 复制代码
@app.get("/search/")
def search(q: str, category: str = None):
    result = {"query": q}
    if category:
        result["category"] = category
    return result
  • ✅ 必须提供 q/search/?q=fastapi
  • ❌ 缺少 q 会报错(422 Validation Error)
  • category 是可选的

✅ 三、请求体(Request Body)

当需要提交复杂数据(如用户注册信息),通常使用 POST 请求 + JSON 请求体

FastAPI 使用 Pydantic 模型 来定义和验证请求体结构。

什么是 Pydantic?

Pydantic 是一个基于 Python 类型提示的数据验证库。FastAPI 内置支持它。

步骤 1:定义数据模型

python 复制代码
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: str | None = None  # 可选字段(Python 3.10+ 语法)
    price: float
    tax: float | None = None

💡 如果你使用的是 Python < 3.10,可以用:

python 复制代码
from typing import Optional
description: Optional[str] = None

步骤 2:在路由中使用模型

python 复制代码
@app.post("/items/")
def create_item(item: Item):
    return item

测试请求体

使用 Swagger UIhttp://127.0.0.1:8000/docs):

  1. 点击 /items/ → "POST"

  2. 点击 "Try it out"

  3. 输入 JSON:

    json 复制代码
    {
      "name": "笔记本电脑",
      "price": 5999.99,
      "tax": 599.99
    }
  4. 点击 "Execute"

你会收到相同的 JSON 响应!

✅ FastAPI 自动:

  • 解析 JSON
  • 验证字段类型(如 price 必须是数字)
  • 转换为 Item 对象
  • 如果数据无效,返回 422 错误(含详细错误信息)

✅ 四、同时使用路径参数、查询参数和请求体

你可以混合使用所有类型的参数!

python 复制代码
@app.put("/items/{item_id}")
def update_item(
    item_id: int,           # 路径参数
    q: str | None = None,   # 查询参数(可选)
    item: Item              # 请求体
):
    result = {"item_id": item_id, "item": item.dict()}
    if q:
        result["q"] = q
    return result

⚠️ 注意:请求体必须是 Pydantic 模型,而路径/查询参数是普通类型。


✅ 五、为什么使用 Pydantic 模型?

  1. 自动验证:确保数据符合预期格式
  2. 自动生成文档:Swagger UI 会显示每个字段的类型和是否可选
  3. 类型安全:IDE 可以提供智能提示
  4. 数据转换 :比如字符串 "123" 自动转为整数 123(如果字段是 int

✅ 六、完整示例代码(推荐保存为 main.py

python 复制代码
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional  # 如果使用 Python < 3.10

app = FastAPI(title="第2部分:请求体与查询参数")

# 定义数据模型
class UserCreate(BaseModel):
    username: str
    email: str
    age: int
    is_active: bool = True  # 默认值

# 查询参数示例
@app.get("/products/")
def list_products(
    category: Optional[str] = None,
    min_price: float = 0.0,
    max_results: int = 10
):
    products = [
        {"name": "手机", "price": 3999, "category": "电子"},
        {"name": "书", "price": 59, "category": "教育"}
    ]
    # 简单过滤(实际项目中会用数据库)
    filtered = [
        p for p in products
        if p["price"] >= min_price and (not category or p["category"] == category)
    ]
    return {"products": filtered[:max_results]}

# 请求体示例
@app.post("/users/")
def create_user(user: UserCreate):
    return {
        "message": f"用户 {user.username} 已创建!",
        "user": user.dict()
    }

# 混合使用
@app.post("/items/{item_id}/reviews")
def add_review(
    item_id: int,
    review_text: str,          # 查询参数(评论内容)
    rating: int = 5,           # 查询参数(评分,默认5)
    reviewer: UserCreate       # 请求体(评论者信息)
):
    return {
        "item_id": item_id,
        "review": {
            "text": review_text,
            "rating": rating,
            "by": reviewer.username
        }
    }

运行后,在 /docs 中尝试:

  • GET /products/?category=电子&min_price=1000
  • POST /users/ 发送 JSON 用户数据
  • POST /items/123/reviews?review_text=很好用!&rating=4 并附带 reviewer 的 JSON

✅ 七、练习任务(动手实践)

🧠 请先自己尝试完成,再查看下方答案!

任务1:创建一个搜索图书的接口

  • 路由:GET /books/
  • 支持两个可选 查询参数:
    • author(字符串)
    • min_year(整数,默认为 0)
  • 返回示例:{"books": [{"title": "Python入门", "author": "张三", "year": 2022}]}

任务2:实现用户注册接口

  • 路由:POST /register/
  • 请求体包含:
    • username(字符串)
    • password(字符串)
    • email(字符串)
  • 返回注册成功的消息和用户名

任务3(挑战):更新商品信息

  • 路由:PUT /products/{product_id}
  • 路径参数:product_id(整数)
  • 查询参数:include_details(布尔值,默认 False
  • 请求体:包含 name(字符串)、price(浮点数)
  • 如果 include_details=true,在响应中额外返回 "updated_at": "2026-01-12"

✅ 八、练习任务参考答案

✅ 任务1 答案

python 复制代码
@app.get("/books/")
def search_books(author: str = None, min_year: int = 0):
    fake_books = [
        {"title": "Python编程", "author": "李四", "year": 2020},
        {"title": "FastAPI实战", "author": "王五", "year": 2023},
        {"title": "数据科学", "author": "李四", "year": 2021}
    ]
    result = [
        book for book in fake_books
        if (not author or book["author"] == author) and book["year"] >= min_year
    ]
    return {"books": result}

测试:

  • /books/?author=李四&min_year=2021

✅ 任务2 答案

python 复制代码
class RegisterUser(BaseModel):
    username: str
    password: str
    email: str

@app.post("/register/")
def register(user: RegisterUser):
    return {
        "message": "注册成功!",
        "username": user.username
    }

测试(在 Swagger 中):

json 复制代码
{
  "username": "alice",
  "password": "secret123",
  "email": "alice@example.com"
}

✅ 任务3 答案

python 复制代码
from datetime import date

class ProductUpdate(BaseModel):
    name: str
    price: float

@app.put("/products/{product_id}")
def update_product(
    product_id: int,
    include_details: bool = False,
    product: ProductUpdate = None
):
    response = {
        "product_id": product_id,
        "name": product.name,
        "price": product.price
    }
    if include_details:
        response["updated_at"] = str(date.today())  # 如 "2026-01-12"
    return response

💡 注意:product: ProductUpdate = None 不推荐,更好的写法是直接 product: ProductUpdate(因为 PUT 通常需要完整数据)。这里仅为演示。


✅ 九、小结

在本部分,你学会了:

  • 使用查询参数接收 URL 中的过滤条件
  • 使用 Pydantic 模型 定义和验证请求体
  • 混合使用路径参数、查询参数和请求体
  • 利用 FastAPI 自动生成的文档测试复杂接口
相关推荐
石像鬼₧魂石2 小时前
3306 端口(MySQL 数据库)渗透测试全流程学习总结
数据库·学习·mysql
Main. 242 小时前
从0到1学习Qt -- Qt3D入门
开发语言·qt·学习
weixin_462446232 小时前
Python+React 专为儿童打造的汉字学习平台:从学前到小学的智能汉字教育解决方案
python·学习·react.js
星火开发设计2 小时前
C++ deque 全面解析与实战指南
java·开发语言·数据结构·c++·学习·知识
cnxy1882 小时前
Python Web开发新时代:FastAPI vs Django性能对比
前端·python·fastapi
saoys2 小时前
Opencv 学习笔记:图像膨胀 / 腐蚀(附滑块动态调节腐蚀核大小)
笔记·opencv·学习
hhcccchh2 小时前
学习vue第十天 V-Model学习指南:双向绑定的魔法师
前端·vue.js·学习
专注于大数据技术栈3 小时前
java学习--Collection的迭代器
java·python·学习
气概12 小时前
法奥机器人学习使用
学习·junit·机器人