Path-параметры и валидация числовых данных¶
Так же, как с помощью Query
вы можете добавлять валидацию и метаданные для query-параметров, так и с помощью Path
вы можете добавлять такую же валидацию и метаданные для path-параметров.
Импорт Path¶
Сначала импортируйте Path
из fastapi
, а также импортируйте 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
Информация
Поддержка Annotated
была добавлена в FastAPI начиная с версии 0.95.0 (и с этой версии рекомендуется использовать этот подход).
Если вы используете более старую версию, вы столкнётесь с ошибками при попытке использовать Annotated
.
Убедитесь, что вы обновили версию FastAPI как минимум до 0.95.1 перед тем, как использовать Annotated
.
Определите метаданные¶
Вы можете указать все те же параметры, что и для Query
.
Например, чтобы указать значение метаданных title
для path-параметра item_id
, вы можете написать:
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
Примечание
Path-параметр всегда является обязательным, поскольку он составляет часть пути.
Поэтому следует объявить его с помощью ...
, чтобы обозначить, что этот параметр обязательный.
Тем не менее, даже если вы объявите его как None
или установите для него значение по умолчанию, это ни на что не повлияет и параметр останется обязательным.
Задайте нужный вам порядок параметров¶
Подсказка
Это не имеет большого значения, если вы используете Annotated
.
Допустим, вы хотите объявить query-параметр q
как обязательный параметр типа str
.
И если вам больше ничего не нужно указывать для этого параметра, то нет необходимости использовать Query
.
Но вам по-прежнему нужно использовать Path
для path-параметра item_id
. И если по какой-либо причине вы не хотите использовать Annotated
, то могут возникнуть небольшие сложности.
Если вы поместите параметр со значением по умолчанию перед другим параметром, у которого нет значения по умолчанию, то Python укажет на ошибку.
Но вы можете изменить порядок параметров, чтобы параметр без значения по умолчанию (query-параметр 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
безQuery
и без значения по умолчанию - объявить path-параметр
item_id
с помощьюPath
- указать их в другом порядке
- не использовать
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
должен быть больше или равен 1
("g
reater than or e
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", 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
(и других классов, которые мы пока не затронули) вы можете добавлять метаданные и строковую валидацию тем же способом, как и в главе Query-параметры и валидация строк.
А также вы можете добавить валидацию числовых данных:
gt
: больше (g
reatert
han)ge
: больше или равно (g
reater than ore
qual)lt
: меньше (l
esst
han)le
: меньше или равно (l
ess than ore
qual)
Информация
Query
, Path
и другие классы, которые мы разберём позже, являются наследниками общего класса Param
.
Все они используют те же параметры для дополнительной валидации и метаданных, которые вы видели ранее.
Технические детали
Query
, Path
и другие "классы", которые вы импортируете из fastapi
, на самом деле являются функциями, которые при вызове возвращают экземпляры одноимённых классов.
Объект Query
, который вы импортируете, является функцией. И при вызове она возвращает экземпляр одноимённого класса Query
.
Использование функций (вместо использования классов напрямую) нужно для того, чтобы ваш редактор не подсвечивал ошибки, связанные с их типами.
Таким образом вы можете использовать привычный вам редактор и инструменты разработки, не добавляя дополнительных конфигураций для игнорирования подобных ошибок.