查询参数(Query Parameters) —— 这是 FastAPI 中另一个核心概念,用于处理 URL 中 ? 后面的键值对,比如分页、搜索、过滤等场景。
🧩 一、什么是查询参数?
查询参数出现在 URL 的 ? 之后,以 key=value 形式出现,多个参数用 & 连接:
GET /items/?skip=0&limit=10
GET /search?q=python&category=webskip=0、limit=10、q=python都是查询参数- 它们不是资源标识,而是操作选项(如分页、筛选、排序)
✅ 二、基本语法与示例
在 FastAPI 中,函数中未出现在路径 {} 中的参数,默认就是查询参数。
🔹 示例 1:简单查询参数
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}- 请求:
GET /items/
→{"skip": 0, "limit": 10}(使用默认值) - 请求:
GET /items/?skip=20&limit=5
→{"skip": 20, "limit": 5}
✅ 查询参数可选,通过设置默认值实现。
🔹 示例 2:字符串查询(如搜索)
@app.get("/search/")
def search(q: str = ""):
if q:
return {"results": [f"item_{q}_1", f"item_{q}_2"]}
return {"results": []}- 请求:
GET /search/?q=fastapi
→ 返回匹配结果 - 请求:
GET /search/
→ 返回空列表(因为q="")
🔹 示例 3:布尔值、列表等类型
FastAPI 支持多种类型自动转换:
@app.get("/products/")
def list_products(
in_stock: bool = True,
tags: list[str] = None, # Python 3.9+;旧版用 List[str]
):
if tags is None:
tags = []
return {
"in_stock": in_stock,
"tags": tags
}- 请求:
GET /products/?in_stock=false&tags=electronics&tags=smart
→{"in_stock": False, "tags": ["electronics", "smart"]}
💡 多个同名参数(如 tags=...&tags=...)会被自动转为列表!⚠️ 三、重要注意事项(新手易错点)
1️⃣ 查询参数必须有默认值(或使用 Optional)
# ❌ 错误:没有默认值,FastAPI 会认为它是必需的路径参数!
@app.get("/items/")
def read_items(limit: int): # 报错:找不到路径参数 {limit}
# ✅ 正确:给默认值 或 用 Optional
from typing import Optional
def read_items(limit: Optional[int] = None):
...
# 或(Python 3.10+)
def read_items(limit: int | None = None):
...✅ 规则:
- 路径参数 → 出现在路径
{}中 → 必需- 查询参数 → 不在路径中 → 必须有默认值(否则 FastAPI 无法区分)
2️⃣ 参数名大小写敏感,且需合法
URL 中参数名要和函数参数名一致:
def search(Query: str = ""): # 参数名是 Query(大写 Q)→ 必须请求:?Query=xxx,而不是 ?query=xxx
3️⃣ 不要和路径参数重名
@app.get("/users/{user_id}")
def read_user(user_id: int, user_id: str = "default"): # ❌ 重复参数名!这是语法错误!路径参数和查询参数不能同名。
4️⃣ 空值处理:None vs 空字符串
q: str = ""→ 空字符串也是有效值q: Optional[str] = None→ 明确表示“未提供”
根据业务逻辑选择。
🛠 四、高级用法:使用 Query 进行更多控制
FastAPI 提供 Query 类,用于添加校验、文档说明、别名等。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
def read_items(
q: str = Query(
default=None,
min_length=3,
max_length=50,
title="Search Query",
description="关键词,至少3个字符"
),
skip: int = Query(0, ge=0), # ge = greater than or equal
limit: int = Query(10, le=100) # le = less than or equal
):
results = [{"item_id": "foo"}, {"item_id": "bar"}]
if q:
results = [{"item_id": q}]
return {"results": results[:limit]}- 请求:
GET /items/?q=hi→ 返回 422 错误(长度不足) - 自动生成 OpenAPI 文档中的说明和限制!
✅ 推荐在需要输入校验或API 文档优化时使用 Query。🔀 五、路径参数 + 查询参数 混合使用
非常常见!例如:获取某个用户的所有订单,并支持分页。
@app.get("/users/{user_id}/orders/")
def get_user_orders(
user_id: int, # ← 路径参数(必需)
skip: int = 0, # ← 查询参数(可选)
limit: int = 10 # ← 查询参数(可选)
):
return {
"user_id": user_id,
"orders": [f"order_{i}" for i in range(skip, skip + limit)]
}- 请求:
GET /users/123/orders/?skip=10&limit=5 - 响应:包含
user_id=123的订单列表,从第10条开始取5条
📊 六、路径参数 vs 查询参数 对比总结
| 特性 | 路径参数 | 查询参数 |
|---|---|---|
| URL 位置 | /users/123 | /users/?id=123 |
| 是否必需 | ✅ 是 | ❌ 否(可设默认值) |
| 语义 | 标识资源(主键) | 操作选项(过滤、分页) |
| 默认值 | 不支持 | ✅ 必须有(或用 Optional) |
| 类型校验 | 支持 | 支持 |
| 多值 | 不支持 | ✅ 支持(自动转列表) |
| OpenAPI 文档 | 显示在路径中 | 显示在“Parameters”下 |
✅ 七、最佳实践建议
- 资源定位用路径参数:
/users/{id},/posts/{slug} - 过滤/分页用查询参数:
?page=2&size=20,?status=active - 给查询参数设合理默认值:如
limit=10,skip=0 - 用
Query添加校验和文档:提升 API 可用性和安全性 - 避免过度使用查询参数:如果参数是资源核心标识,考虑改用路径参数
🎯 小练习(你可以试试看!)
写一个 API:
- 路径:
/books/{genre}/ 查询参数:
min_rating: float = 0.0(最小评分)author: str = None(可选作者)
- 返回模拟书籍列表
@app.get("/books/{genre}/")
def get_books_by_genre(
genre: str,
min_rating: float = 0.0,
author: str | None = None
):
books = [
{"title": "Book A", "genre": genre, "rating": 4.5, "author": "Alice"},
{"title": "Book B", "genre": genre, "rating": 3.8, "author": "Bob"},
]
filtered = [
b for b in books
if b["rating"] >= min_rating and (author is None or b["author"] == author)
]
return {"books": filtered}