查询参数和字符串校验¶
FastAPI 允许为参数声明附加信息与校验。
示例如下:
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = None):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(q: str | None = None):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
查询参数 q
的类型是 Optional[str]
,即它的类型是 str
,但也可以是 None
(其实,是它的默认值为 None
), q
是可选参数。
笔记
默认值是 None
,FastAPI 因此把 q
当作可选参数。
FastAPI 不使用 Optional[str]
中的 Optional
,但 Optional
可以让编辑器提供更好的支持,有助于检查错误。
附加校验¶
接下来,添加一些约束条件:即使 q
是可选的,但只要提供了该参数,该参数的长度就不能超过 50 个字符。
导入 Query
¶
首先,从 fastapi
导入 Query
:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str | None = Query(default=None, max_length=50)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
以 Query
为默认值¶
接下来,把 Query
作为查询参数的默认值,并把 max_length
参数设置为 50:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str | None = Query(default=None, max_length=50)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
此处必须用 Query()
替换函数里的默认值 None
。在此,可以把默认值设置为 Query(default=None)
,它与定义的默认值效果相同。
所以:
q: Union[str, None] = Query(default=None)
……让参数变为可选,可使用:
q: Union[str, None] = None
Python 3.10 以上版本时:
q: str | None = Query(default=None)
……让参数变为可选,可使用:
q: str | None = None
但 Query
能显式声明查询参数。
说明
注意,FastAPI 关注以下内容:
= None
或:
= Query(default=None)
并且通过 None
识别出查询参数是可选的。
Union[str, None]
只是为了让编辑器提供更好的支持,并不会告诉 FastAPI 该参数是可选的。
这样就可以为 Query
传递更多参数。本例使用 max_length
参数约束字符串:
q: Union[str, None] = Query(default=None, max_length=50)
这行代码会校验数据,在数据无效时显示错误信息,并在 OpenAPI 概图的路径操作中存档该参数。
添加更多校验¶
FastAPI 还支持 min_length
参数:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(default=None, min_length=3, max_length=50)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str | None = Query(default=None, min_length=3, max_length=50)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
添加正则表达式¶
FastAPI 还能定义必须与正则表达式匹配的参数:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(
default=None, min_length=3, max_length=50, regex="^fixedquery$"
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str
| None = Query(default=None, min_length=3, max_length=50, regex="^fixedquery$")
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
这个指定的正则表达式通过以下规则检查接收到的参数值:
^
:以该符号之后的字符开头,符号之前没有字符fixedquery
:参数值应与fixedquery
完全匹配$
:到此符号结束,fixedquery
后没有其他字符
就算搞不定正则表达式也不用担心,很多人都觉得正则表达式很难。其实不用正则表达式也可以完成很多工作。
但只要您需要使用正则表达式,请记住,FastAPI 对此提供支持。
默认值¶
Query
的第一个参数是查询参数的默认值。不仅可以使用 None
,还可以使用其他值。
如,声明 min_length
是 3
,默认值是 fixedquery
的查询参数 q
:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(default="fixedquery", min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
笔记
声明了默认值让该参数成为可选参数。
标记为必选¶
不需要声明校验或元数据时,只要不声明默认值,就可以把查询参数 q
变为必选参数,例如用:
q: str
或使用以下代码:
q: Union[str, None] = None
但现在是用 Query
声明该参数,示例如下:
q: Union[str, None] = Query(default=None, min_length=3)
因此,使用 Query
把查询参数声明为必选时,第一个参数的值应为 ...
:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
使用省略号(...
)的必选项¶
还有一种可以显示声明必选值的备选方式。即使用字面值 ...
设置 default
参数:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(default=..., min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
这样一来,FastAPI 就能把该查询参数识别为必选参数。
使用 None
定义必选项¶
声明可以接受 None
的参数,但它仍是必选的。这将强制客户端发送值,即使这个值是 None
。
为了达到这一目的,可以声明 None
是一种有效类型,但仍要使用 default=...
:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=..., min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str | None = Query(default=..., min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
提示
Pydantic 负责实现 FastAPI 中的数据验证与序列化,它支持一种特殊行为,即使用 Optional
或 Union[Something, None]
而无须默认值, 详见 Pydantic 文档中关于 必选可选字段的说明。
用 Pydantic 的 Required
替换省略号(...
)¶
如果不想使用 ...
,可以从 Pydantic 导入 Required
:
from fastapi import FastAPI, Query
from pydantic import Required
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(default=Required, min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
提示
记住,大部分情况下,仅需省略 default
参数即可设置必选,因此通常无须使用 ...
或 Required
.
查询参数列表 / 多个值¶
用 Query
显式定义查询参数时,还可以让它接收一组值,换句话说,就是接收多个值。
例如,在 URL 中声明多个查询参数 q
的代码如下:
from typing import List, Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
query_items = {"q": q}
return query_items
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[list[str], None] = Query(default=None)):
query_items = {"q": q}
return query_items
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: list[str] | None = Query(default=None)):
query_items = {"q": q}
return query_items
然后,输入以下网址:
http://localhost:8000/items/?q=foo&q=bar
就可以在路径操作函数的查询参数 q
中以 Python 列表的形式接收查询参数 q
的多个值(foo
和 bar
)。
因此,该 URL 的响应为:
{
"q": [
"foo",
"bar"
]
}
提示
如上例所示,把查询参数的类型声明为 list
,要显式使用 Query
,否则该参数会被解释为请求体。
API 文档会进行响应更新,允许使用多个值:
含默认值的查询参数列表 / 多个值¶
FastAPI 还支持在未给定值时,为 list
定义默认值:
from typing import List
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: List[str] = Query(default=["foo", "bar"])):
query_items = {"q": q}
return query_items
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: list[str] = Query(default=["foo", "bar"])):
query_items = {"q": q}
return query_items
访问以下网址:
http://localhost:8000/items/
q
的默认值是:["foo", "bar"]
,响应是:
{
"q": [
"foo",
"bar"
]
}
使用 list
¶
也可以直接用 list
代替 List [str]
:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: list = Query(default=[])):
query_items = {"q": q}
return query_items
笔记
注意,此时,FastAPI 不再校验列表中的元素。
例如,List[int]
会校验(并存档)列表中的元素是不是整数。但如果只使用 list
,就没有这种校验。
声明更多元数据¶
FastAPI 还支持为参数添加更多信息。
这些信息包含在 OpenAPI 概图里,用于 API 文档和外部工具。
笔记
注意,不同工具对 OpenAPI 的支持可能不同。
有些工具可能不会显示所有已声明的额外信息,尽管在大多数情况下,这些缺失的功能已经纳入了这些工具的开发计划。
为 Query
添加 title
参数:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(default=None, title="Query string", min_length=3)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str | None = Query(default=None, title="Query string", min_length=3)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
及 description
参数:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(
default=None,
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str
| None = Query(
default=None,
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
参数别名¶
假设要使用的查询参数是 item-query
。
如下所示:
http://127.0.0.1:8000/items/?item-query=foobaritems
但 item-query
不是有效的 Python 变量名。
最接近的有效名称是 item_query
。
但如果必须在 URL 中使用 item-query
……
需要使用 alias
参数声明别名,用于在 URL 中查找这个参数值:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str | None = Query(default=None, alias="item-query")):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
弃用参数¶
如果不再需要某个参数。
但因为某些客户端还在使用该参数,而不得不保留一段时间,此时,需要在文档中把它显示为已弃用。
为此,要在 Query
中使用参数 deprecated=True
:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(
default=None,
alias="item-query",
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
max_length=50,
regex="^fixedquery$",
deprecated=True,
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str
| None = Query(
default=None,
alias="item-query",
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
max_length=50,
regex="^fixedquery$",
deprecated=True,
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
API 文档显示如下:
从 OpenAPI 中排除¶
从生成的 OpenAPI 概图中排除查询参数(从自动文档系统),把 Query
的 include_in_schema
参数设置为 False
:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
hidden_query: Union[str, None] = Query(default=None, include_in_schema=False)
):
if hidden_query:
return {"hidden_query": hidden_query}
else:
return {"hidden_query": "Not found"}
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
hidden_query: str | None = Query(default=None, include_in_schema=False)
):
if hidden_query:
return {"hidden_query": hidden_query}
else:
return {"hidden_query": "Not found"}
小结¶
FastAPI 支持为查询参数声明更多校验和元数据。
常用于校验和元数据的参数包括:
alias
title
description
deprecated
专用于校验字符串的参数包括:
min_length
max_length
regex
本章介绍了如何校验字符串。
下一章介绍如何校验数值等其他类型。