在 FastAPI 中,查询参数(Query Parameters) 是 URL 中 ? 后面的键值对,多个参数之间用 & 分隔(例如:/items?skip=0&limit=10)。
FastAPI 的核心魔法在于:任何未在路径(Path)中声明的函数参数,都会被自动视为查询参数。
以下是 FastAPI 查询参数的核心用法和进阶技巧:
1. 基本用法
直接在函数签名中声明参数即可。FastAPI 会自动从 URL 的查询字符串中提取并转换类型。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}- 访问
/items/:返回{"skip": 0, "limit": 10} - 访问
/items/?skip=20&limit=5:返回{"skip": 20, "limit": 5} - 访问
/items/?skip=foo:返回 422 错误,因为foo无法转换为int。
2. 可选查询参数 (Optional)
如果你希望某个查询参数是可选的,只需为其提供一个默认值(通常是 None 或某个具体值)。
from typing import Optional # Python 3.10+ 可直接用 str | None
@app.get("/items/")
async def read_items(q: str | None = None):
if q:
return {"items": [{"name": "Item Foo"}, {"name": "Item Bar"}], "q": q}
return {"items": [{"name": "Item Foo"}, {"name": "Item Bar"}]}- 访问
/items/:q为None。 - 访问
/items/?q=somequery:q为"somequery"。
3. 使用 Query 添加高级验证
你可以从 fastapi 导入 Query,为查询参数添加更严格的验证规则(如长度限制、正则表达式、是否废弃等)。
from fastapi import FastAPI, Query
app = FastAPI()
# 传统写法
@app.get("/items/")
async def read_items(
q: str | None = Query(
default=None,
title="Search query",
description="Query string to search for items",
min_length=3,
max_length=50,
regex="^fixedquery$" # 只允许精确匹配 "fixedquery"
)
):
return {"q": q}如果传入的 q 长度小于 3 或不符合正则,FastAPI 会自动返回清晰的 422 验证错误。
4. 现代推荐写法:使用 Annotated (Python 3.9+)
FastAPI 官方强烈推荐使用 typing.Annotated。它将类型和元数据(如 Query)分离,使代码更清晰,且对类型检查器(如 mypy)更友好。
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 类型提示在前,Query 验证规则在后,默认值放在最后
q: Annotated[str | None, Query(min_length=3, max_length=50, description="Search query")] = None
):
return {"q": q}5. 声明“必需”的查询参数
如果某个查询参数是必须提供的(没有默认值),你可以使用 ... (Ellipsis) 作为默认值,或者在 Annotated 中不提供默认值。
from fastapi import Query
# 传统写法:使用 ... 表示必需
@app.get("/items/")
async def read_items(q: str = Query(..., min_length=3)):
return {"q": q}
# 现代 Annotated 写法:直接不给默认值
@app.get("/items/")
async def read_items_modern(
q: Annotated[str, Query(min_length=3)]
):
return {"q": q}此时访问 /items/(不带 ?q=...)将直接返回 422 错误,提示该字段缺失 (field required)。
6. 多个同名查询参数 (List)
如果 URL 中包含多个同名的查询参数(例如 ?q=apple&q=banana),你可以将类型声明为 list,FastAPI 会自动将其解析为列表。
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 允许传递多个 q 参数,例如 ?q=apple&q=banana
q: Annotated[list[str] | None, Query(title="Query string")] = None
):
return {"q": q}- 访问
/items/?q=apple&q=banana:返回{"q": ["apple", "banana"]}。 - 访问
/items/:返回{"q": None}。
7. 布尔值转换 (Boolean Conversion)
FastAPI 对布尔查询参数有特殊的智能解析。它不仅识别 true/false,还能识别 1/0、on/off、yes/no 等。
@app.get("/items/")
async def read_items(short: bool = False):
if short:
return {"message": "Short response"}
return {"message": "Full response with lots of details"}- 访问
/items/?short=1、/items/?short=true、/items/?short=yes:short都会被解析为True。 - 访问
/items/?short=0或不传:short为False。
8. 标记参数为“已废弃” (Deprecated)
如果你的 API 正在迭代,某个查询参数即将被移除,可以使用 deprecated=True。这会在自动生成的 Swagger UI (OpenAPI) 文档中将该参数划掉并标记为废弃,但代码仍会正常处理它。
@app.get("/items/")
async def read_items(
q: Annotated[str | None, Query(deprecated=True)] = None
):
return {"q": q}💡 最佳实践总结
- 优先使用
Annotated:这是现代 FastAPI 开发的标准,代码可读性和类型提示支持最好。 - 提供合理的默认值:除非业务逻辑强制要求,否则尽量为查询参数提供默认值(如分页的
skip=0,limit=10),以提高 API 的易用性。 - 善用
Query的description:填写清晰的描述,FastAPI 会自动将其渲染到 Swagger UI 中,极大降低前端/其他开发者的对接成本。 - 注意类型安全:始终声明类型(如
int,str,bool),让 FastAPI 帮你挡掉非法的输入,而不是在业务逻辑里手动做try...except。
如果你需要了解如何处理更复杂的场景(如依赖注入中的查询参数、自定义解析逻辑等),随时告诉我!