mirror of https://github.com/tiangolo/fastapi.git
474 lines
26 KiB
Markdown
474 lines
26 KiB
Markdown
# Query-параметры и валидация строк { #query-parameters-and-string-validations }
|
||
|
||
**FastAPI** позволяет определять дополнительную информацию и выполнять валидацию для ваших параметров.
|
||
|
||
Рассмотрим это приложение в качестве примера:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
|
||
|
||
Query-параметр `q` имеет тип `str | None`, это означает, что он имеет тип `str`, но также может быть `None`. Значение по умолчанию действительно `None`, поэтому FastAPI будет знать, что он не обязателен.
|
||
|
||
/// note | Примечание
|
||
|
||
FastAPI поймёт, что значение `q` не обязательно, из‑за значения по умолчанию `= None`.
|
||
|
||
Аннотация `str | None` позволит вашему редактору кода обеспечить лучшую поддержку и находить ошибки.
|
||
|
||
///
|
||
|
||
## Дополнительная валидация { #additional-validation }
|
||
|
||
Мы собираемся добавить ограничение: хотя `q` и необязателен, когда он передан, **его длина не должна превышать 50 символов**.
|
||
|
||
### Импорт `Query` и `Annotated` { #import-query-and-annotated }
|
||
|
||
Чтобы сделать это, сначала импортируйте:
|
||
|
||
* `Query` из `fastapi`
|
||
* `Annotated` из `typing`
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||
|
||
/// info | Дополнительная информация
|
||
|
||
Поддержка `Annotated` (и рекомендация использовать его) появилась в FastAPI версии 0.95.0.
|
||
|
||
Если у вас более старая версия, при попытке использовать `Annotated` вы получите ошибки.
|
||
|
||
Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} как минимум до 0.95.1 перед использованием `Annotated`.
|
||
|
||
///
|
||
|
||
## Использовать `Annotated` в типе для параметра `q` { #use-annotated-in-the-type-for-the-q-parameter }
|
||
|
||
Помните, я уже говорил, что `Annotated` можно использовать для добавления метаданных к параметрам в разделе [Введение в типы Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
|
||
|
||
Пришло время использовать его с FastAPI. 🚀
|
||
|
||
У нас была такая аннотация типа:
|
||
|
||
//// tab | Python 3.10+
|
||
|
||
```Python
|
||
q: str | None = None
|
||
```
|
||
|
||
////
|
||
|
||
//// tab | Python 3.9+
|
||
|
||
```Python
|
||
q: Union[str, None] = None
|
||
```
|
||
|
||
////
|
||
|
||
Мы «обернём» это в `Annotated`, и получится:
|
||
|
||
//// tab | Python 3.10+
|
||
|
||
```Python
|
||
q: Annotated[str | None] = None
|
||
```
|
||
|
||
////
|
||
|
||
//// tab | Python 3.9+
|
||
|
||
```Python
|
||
q: Annotated[Union[str, None]] = None
|
||
```
|
||
|
||
////
|
||
|
||
Обе версии означают одно и то же: `q` — параметр, который может быть `str` или `None`, и по умолчанию равен `None`.
|
||
|
||
А теперь к самому интересному. 🎉
|
||
|
||
## Добавим `Query` в `Annotated` для параметра `q` { #add-query-to-annotated-in-the-q-parameter }
|
||
|
||
Теперь, когда у нас есть `Annotated`, куда можно поместить дополнительную информацию (в нашем случае — дополнительные правила валидации), добавим `Query` внутрь `Annotated` и установим параметр `max_length` равным `50`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
|
||
|
||
Обратите внимание, что значение по умолчанию по‑прежнему `None`, то есть параметр остаётся необязательным.
|
||
|
||
Но теперь, добавив `Query(max_length=50)` внутрь `Annotated`, мы говорим FastAPI, что этому значению нужна **дополнительная валидация** — максимум 50 символов. 😎
|
||
|
||
/// tip | Совет
|
||
|
||
Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие — `Path()`, `Body()`, `Header()` и `Cookie()`, — они также принимают те же аргументы, что и `Query()`.
|
||
|
||
///
|
||
|
||
Теперь FastAPI будет:
|
||
|
||
* **валидировать** данные, удостоверяясь, что максимальная длина — 50 символов;
|
||
* показывать **понятную ошибку** клиенту, если данные невалидны;
|
||
* **документировать** параметр в *операции пути* схемы OpenAPI (он будет показан в **UI автоматической документации**).
|
||
|
||
## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
|
||
|
||
В предыдущих версиях FastAPI (до <abbr title="до 2023-03">0.95.0</abbr>) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.
|
||
|
||
/// tip | Подсказка
|
||
|
||
Для нового кода и везде, где это возможно, используйте `Annotated`, как описано выше. У этого есть несколько преимуществ (см. ниже) и нет недостатков. 🍰
|
||
|
||
///
|
||
|
||
Вот как можно использовать `Query()` как значение по умолчанию для параметра функции, установив `max_length` равным 50:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
|
||
|
||
Так как в этом случае (без `Annotated`) мы заменяем в функции значение по умолчанию `None` на `Query()`, теперь нужно указать значение по умолчанию через параметр `Query(default=None)`, это служит той же цели — задать значение по умолчанию (по крайней мере для FastAPI).
|
||
|
||
Итак:
|
||
|
||
```Python
|
||
q: str | None = Query(default=None)
|
||
```
|
||
|
||
...делает параметр необязательным со значением по умолчанию `None`, так же как:
|
||
|
||
```Python
|
||
q: str | None = None
|
||
```
|
||
|
||
Но вариант с `Query` явно объявляет его как query-параметр.
|
||
|
||
Затем мы можем передать и другие параметры в `Query`. В данном случае — параметр `max_length`, применимый к строкам:
|
||
|
||
```Python
|
||
q: str | None = Query(default=None, max_length=50)
|
||
```
|
||
|
||
Это провалидирует данные, покажет понятную ошибку, если данные невалидны, и задокументирует параметр в *операции пути* схемы OpenAPI.
|
||
|
||
### `Query` как значение по умолчанию или внутри `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||
|
||
Помните, что при использовании `Query` внутри `Annotated` нельзя указывать параметр `default` у `Query`.
|
||
|
||
Вместо этого используйте обычное значение по умолчанию параметра функции. Иначе это будет неоднозначно.
|
||
|
||
Например, так делать нельзя:
|
||
|
||
```Python
|
||
q: Annotated[str, Query(default="rick")] = "morty"
|
||
```
|
||
|
||
...потому что непонятно, какое значение должно быть по умолчанию: `"rick"` или `"morty"`.
|
||
|
||
Следовательно, используйте (предпочтительно):
|
||
|
||
```Python
|
||
q: Annotated[str, Query()] = "rick"
|
||
```
|
||
|
||
...или в старой кодовой базе вы увидите:
|
||
|
||
```Python
|
||
q: str = Query(default="rick")
|
||
```
|
||
|
||
### Преимущества `Annotated` { #advantages-of-annotated }
|
||
|
||
**Рекомендуется использовать `Annotated`** вместо задания значения по умолчанию в параметрах функции — так **лучше** по нескольким причинам. 🤓
|
||
|
||
**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
|
||
|
||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||
|
||
Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
|
||
|
||
Так как `Annotated` может содержать больше одной аннотации метаданных, теперь вы можете использовать ту же функцию и с другими инструментами, например с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
|
||
|
||
## Больше валидаций { #add-more-validations }
|
||
|
||
Можно также добавить параметр `min_length`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
|
||
|
||
## Регулярные выражения { #add-regular-expressions }
|
||
|
||
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) - это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||
|
||
Данный шаблон регулярного выражения проверяет, что полученное значение параметра:
|
||
|
||
* `^`: начинается с следующих символов, до них нет символов.
|
||
* `fixedquery`: имеет точное значение `fixedquery`.
|
||
* `$`: заканчивается здесь, после `fixedquery` нет никаких символов.
|
||
|
||
Если вы теряетесь во всех этих идеях про **«регулярные выражения»**, не переживайте. Это сложная тема для многих. Многое можно сделать и без них.
|
||
|
||
Теперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.
|
||
|
||
## Значения по умолчанию { #default-values }
|
||
|
||
Конечно, можно использовать и другие значения по умолчанию, не только `None`.
|
||
|
||
Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
|
||
|
||
/// note | Примечание
|
||
|
||
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.
|
||
|
||
///
|
||
|
||
## Обязательные параметры { #required-parameters }
|
||
|
||
Когда не требуется объявлять дополнительные проверки или метаданные, можно сделать query-параметр `q` обязательным, просто не указывая значение по умолчанию, например:
|
||
|
||
```Python
|
||
q: str
|
||
```
|
||
|
||
вместо:
|
||
|
||
```Python
|
||
q: str | None = None
|
||
```
|
||
|
||
Но сейчас мы объявляем его через `Query`, например так:
|
||
|
||
```Python
|
||
q: Annotated[str | None, Query(min_length=3)] = None
|
||
```
|
||
|
||
Поэтому, когда вам нужно объявить значение как обязательное при использовании `Query`, просто не указывайте значение по умолчанию:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
|
||
|
||
### Обязательный, но может быть `None` { #required-can-be-none }
|
||
|
||
Можно объявить, что параметр может принимать `None`, но при этом остаётся обязательным. Это заставит клиентов отправлять значение, даже если это значение — `None`.
|
||
|
||
Для этого объявите, что `None` — валидный тип, но просто не задавайте значение по умолчанию:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
|
||
|
||
## Query-параметр - список / несколько значений { #query-parameter-list-multiple-values }
|
||
|
||
Когда вы явно объявляете query-параметр через `Query`, можно также указать, что он принимает список значений, иначе говоря — несколько значений.
|
||
|
||
Например, чтобы объявить query-параметр `q`, который может встречаться в URL несколько раз, можно написать:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
|
||
|
||
Тогда при таком URL:
|
||
|
||
```
|
||
http://localhost:8000/items/?q=foo&q=bar
|
||
```
|
||
|
||
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
|
||
|
||
Таким образом, ответ на этот URL будет:
|
||
|
||
```JSON
|
||
{
|
||
"q": [
|
||
"foo",
|
||
"bar"
|
||
]
|
||
}
|
||
```
|
||
|
||
/// tip | Совет
|
||
|
||
Чтобы объявить query-параметр типа `list`, как в примере выше, нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
|
||
|
||
///
|
||
|
||
Интерактивная документация API обновится соответствующим образом и позволит передавать несколько значений:
|
||
|
||
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||
|
||
### Query-параметр - список / несколько значений со значением по умолчанию { #query-parameter-list-multiple-values-with-defaults }
|
||
|
||
Можно также определить значение по умолчанию как `list`, если ничего не передано:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
|
||
|
||
Если вы перейдёте по адресу:
|
||
|
||
```
|
||
http://localhost:8000/items/
|
||
```
|
||
|
||
значение по умолчанию для `q` будет: `["foo", "bar"]`, и ответом будет:
|
||
|
||
```JSON
|
||
{
|
||
"q": [
|
||
"foo",
|
||
"bar"
|
||
]
|
||
}
|
||
```
|
||
|
||
#### Просто `list` { #using-just-list }
|
||
|
||
Можно использовать `list` напрямую вместо `list[str]`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
|
||
|
||
/// note | Примечание
|
||
|
||
Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.
|
||
|
||
Например, `list[int]` проверит (и задокументирует), что элементы списка — целые числа. А просто `list` — нет.
|
||
|
||
///
|
||
|
||
## Больше метаданных { #declare-more-metadata }
|
||
|
||
Можно добавить больше информации о параметре.
|
||
|
||
Эта информация будет включена в сгенерированную OpenAPI-схему и использована интерфейсами документации и внешними инструментами.
|
||
|
||
/// note | Примечание
|
||
|
||
Помните, что разные инструменты могут иметь разный уровень поддержки OpenAPI.
|
||
|
||
Некоторые из них пока могут не показывать всю дополнительную информацию, хотя в большинстве случаев недостающая возможность уже запланирована к разработке.
|
||
|
||
///
|
||
|
||
Можно задать `title`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
|
||
|
||
И `description`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
|
||
|
||
## Псевдонимы параметров { #alias-parameters }
|
||
|
||
Представьте, что вы хотите, чтобы параметр назывался `item-query`.
|
||
|
||
Например:
|
||
|
||
```
|
||
http://127.0.0.1:8000/items/?item-query=foobaritems
|
||
```
|
||
|
||
Но `item-query` — недопустимое имя переменной в Python.
|
||
|
||
Ближайший вариант — `item_query`.
|
||
|
||
Но вам всё равно нужно именно `item-query`...
|
||
|
||
Тогда можно объявить `alias`, и этот псевдоним будет использован для поиска значения параметра:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
|
||
|
||
## Маркировка параметров как устаревших { #deprecating-parameters }
|
||
|
||
Предположим, этот параметр вам больше не нравится.
|
||
|
||
Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как <abbr title="устаревший, не рекомендуется использовать">устаревший</abbr>.
|
||
|
||
Тогда передайте параметр `deprecated=True` в `Query`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
|
||
|
||
В документации это будет показано так:
|
||
|
||
<img src="/img/tutorial/query-params-str-validations/image01.png">
|
||
|
||
## Исключить параметры из OpenAPI { #exclude-parameters-from-openapi }
|
||
|
||
Чтобы исключить query-параметр из генерируемой OpenAPI-схемы (и, следовательно, из систем автоматической документации), укажите у `Query` параметр `include_in_schema=False`:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
|
||
|
||
## Кастомная валидация { #custom-validation }
|
||
|
||
Бывают случаи, когда нужна **кастомная валидация**, которую нельзя выразить параметрами выше.
|
||
|
||
В таких случаях можно использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки, что значение — это `str`).
|
||
|
||
Этого можно добиться, используя <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` Pydantic</a> внутри `Annotated`.
|
||
|
||
/// tip | Совет
|
||
|
||
В Pydantic также есть <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> и другие. 🤓
|
||
|
||
///
|
||
|
||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) - веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||
|
||
/// info | Дополнительная информация
|
||
|
||
Это доступно в Pydantic версии 2 и выше. 😎
|
||
|
||
///
|
||
|
||
/// tip | Совет
|
||
|
||
Если вам нужна валидация, требующая общения с каким‑либо **внешним компонентом** — базой данных или другим API — вместо этого используйте **Зависимости FastAPI** (FastAPI Dependencies), вы познакомитесь с ними позже.
|
||
|
||
Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в запросе.
|
||
|
||
///
|
||
|
||
### Понимание этого кода { #understand-that-code }
|
||
|
||
Важный момент — это использовать **`AfterValidator` с функцией внутри `Annotated`**. Смело пропускайте эту часть. 🤸
|
||
|
||
---
|
||
|
||
Но если вам любопытен именно этот пример и всё ещё интересно, вот немного подробностей.
|
||
|
||
#### Строка и `value.startswith()` { #string-with-value-startswith }
|
||
|
||
Заметили? Метод строки `value.startswith()` может принимать кортеж — тогда будет проверено каждое значение из кортежа:
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
|
||
|
||
#### Случайный элемент { #a-random-item }
|
||
|
||
С помощью `data.items()` мы получаем <abbr title="Объект, по которому можно итерироваться циклом for, например список, множество и т. п.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
|
||
|
||
Мы превращаем этот итерируемый объект в обычный `list` через `list(data.items())`.
|
||
|
||
Затем с `random.choice()` можно получить **случайное значение** из списка — то есть кортеж вида `(id, name)`. Это будет что‑то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||
|
||
После этого мы **присваиваем эти два значения** кортежа переменным `id` и `name`.
|
||
|
||
Так что, если пользователь не передал ID элемента, он всё равно получит случайную рекомендацию.
|
||
|
||
...и всё это в **одной простой строке**. 🤯 Разве не прекрасен Python? 🐍
|
||
|
||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||
|
||
## Резюме { #recap }
|
||
|
||
Вы можете объявлять дополнительные проверки и метаданные для параметров.
|
||
|
||
Общие метаданные и настройки:
|
||
|
||
* `alias`
|
||
* `title`
|
||
* `description`
|
||
* `deprecated`
|
||
|
||
Проверки, специфичные для строк:
|
||
|
||
* `min_length`
|
||
* `max_length`
|
||
* `pattern`
|
||
|
||
Кастомные проверки с использованием `AfterValidator`.
|
||
|
||
В этих примерах вы видели, как объявлять проверки для значений типа `str`.
|
||
|
||
Смотрите следующие главы, чтобы узнать, как объявлять проверки для других типов, например чисел.
|