路徑參數和數值驗證¶
就像您可以使用 Query
宣告更多查詢參數的驗證和中繼資料一樣,您可以使用 Path
為路徑參數宣告相同類型的驗證和中繼資料。
導入 Path¶
首先,從 fastapi
導入 Path
,並導入 Annotated
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Annotated, Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Union
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建議使用 Annotated
版本。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: str | None = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建議使用 Annotated
版本。
from typing import Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: Union[str, None] = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
資訊
FastAPI 從 0.95.0 版開始支援 Annotated
(並開始推薦使用)。
如果您使用的是舊版本,則在嘗試使用 Annotated
時會發生錯誤。
在使用 Annotated
之前,請確保您已將 FastAPI 版本升級到至少 0.95.1。
宣告中繼資料¶
您可以宣告與 Query
相同的所有參數。
例如,要為路徑參數 item_id
宣告 title
中繼資料值,您可以輸入
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Annotated, Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Union
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建議使用 Annotated
版本。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: str | None = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建議使用 Annotated
版本。
from typing import Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: Union[str, None] = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
注意事項
路徑參數始終是必需的,因為它必須是路徑的一部分。即使您將其宣告為 None
或設定預設值,也不會影響任何內容,它仍然是必需的。
根據需要排列參數順序¶
提示
如果您使用 Annotated
,這可能不太重要或必要。
假設您想將查詢參數 q
宣告為必要的 str
。
而且您不需要為該參數宣告任何其他內容,因此您並不需要使用 Query
。
但是您仍然需要為 item_id
路徑參數使用 Path
。而且由於某些原因,您不想使用 Annotated
。
如果您將具有「預設值」的值放在沒有「預設值」的值之前,Python 會發出抱怨。
但是您可以重新排序它們,並將沒有預設值的值(查詢參數 q
)放在前面。
對於 FastAPI 來說,這無關緊要。它會根據參數的名稱、類型和預設宣告(Query
、Path
等)來檢測參數,它不關心順序。
因此,您可以將您的函式宣告為
提示
如果可能,建議使用 Annotated
版本。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
但請記住,如果您使用 Annotated
,就不會有這個問題,因為您沒有使用 Query()
或 Path()
的函式參數預設值,所以順序無關緊要。
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
根據需要排列參數順序,技巧¶
提示
如果您使用 Annotated
,這可能不太重要或必要。
這裡有一個很方便的小技巧,但您不會經常需要它。
如果您想
- 在不使用
Query
或任何預設值的情況下宣告q
查詢參數 - 使用
Path
宣告路徑參數item_id
- 以不同的順序排列它們
- 不使用
Annotated
...Python 有一個特殊的語法可以做到這一點。
將 *
作為函式的第一個參數傳遞。
Python 不會對 *
做任何事情,但它會知道所有後續的參數都應該作為關鍵字參數(鍵值對)來呼叫,也稱為 kwargs
。即使它們沒有預設值。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
使用 Annotated
更好¶
請記住,如果您使用 Annotated
,因為您沒有使用函數參數預設值,您就不會遇到這個問題,而且您可能不需要使用 *
。
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
數字驗證:大於或等於¶
使用 Query
和 Path
(以及您稍後會看到的其他方法),您可以宣告數字限制。
在這裡,使用 ge=1
,item_id
將需要是一個「g
reater than or e
qual」於 1
的整數。
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建議使用 Annotated
版本。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*, item_id: int = Path(title="The ID of the item to get", ge=1), q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
數字驗證:大於和小於或等於¶
同樣適用於
gt
:g
reatert
han(大於)le
:l
ess than ore
qual(小於或等於)
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建議使用 Annotated
版本。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
數字驗證:浮點數、大於和小於¶
數字驗證也適用於 float
值。
這就是能夠宣告 gt
而不僅僅是 ge
的重要性所在。例如,您可以使用它來要求一個值必須大於 0
,即使它小於 1
。
因此,0.5
將是一個有效值。但 0.0
或 0
將無效。
lt
也是如此。
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
提示
如果可能,建議使用 Annotated
版本。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: str,
size: float = Query(gt=0, lt=10.5),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
摘要¶
使用 Query
、Path
(以及您尚未看到的其他方法),您可以以與查詢參數和字串驗證相同的方式宣告中繼資料和字串驗證。
您也可以宣告數字驗證
gt
:g
reatert
han(大於)ge
:g
reater than ore
qual(大於或等於)lt
:l
esst
han(小於)le
:l
ess than ore
qual(小於或等於)
資訊
Query
、Path
以及您稍後將看到的其他類別都是通用 Param
類別的子類別。
它們都共享您看到的用於額外驗證和中繼資料的相同參數。
「技術細節」
當您從 fastapi
導入 Query
、Path
等時,它們實際上是函數。
呼叫這些函數時,會返回同名類別的實例。
因此,您導入 Query
,它是一個函數。當您呼叫它時,它會返回一個也名為 Query
的類別的實例。
這些函數的存在(而不是直接使用類別)是為了讓您的編輯器不會標記有關其類型的錯誤。
這樣,您可以使用普通的編輯器和編碼工具,而無需添加自定義配置來忽略這些錯誤。