committed by
GitHub
1 changed files with 491 additions and 0 deletions
@ -0,0 +1,491 @@ |
|||
# Query параметри та валідація рядків |
|||
|
|||
**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` дозволить Вашому редактору коду надавати кращу підтримку та виявляти помилки. |
|||
|
|||
/// |
|||
|
|||
## Додаткова валідація |
|||
|
|||
Ми хочемо, щоб навіть якщо `q` є необов’язковим, **його довжина не перевищувала 50 символів**, якщо він все ж буде переданий. |
|||
|
|||
### Імпорт `Query` та `Annotated` |
|||
|
|||
Щоб це зробити, спочатку імпортуємо: |
|||
|
|||
* `Query` з `fastapi` |
|||
* `Annotated` з `typing` |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *} |
|||
|
|||
/// info | Інформація |
|||
|
|||
FastAPI додав підтримку `Annotated` (і почав рекомендувати його) у версії 0.95.0. |
|||
|
|||
Якщо у Вас старіша версія, під час використання `Annotated` можуть виникати помилки. |
|||
|
|||
Переконайтеся, що Ви [оновили версію FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до принаймні 0.95.1, перш ніж використовувати `Annotated`. |
|||
|
|||
/// |
|||
|
|||
## Використання `Annotated` у типі параметра `q` |
|||
|
|||
Пам’ятаєте, як я раніше розповідав, що `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.8+ |
|||
|
|||
```Python |
|||
q: Union[str, None] = None |
|||
``` |
|||
|
|||
//// |
|||
|
|||
Тепер ми загорнемо її у `Annotated`, і отримаємо: |
|||
|
|||
//// tab | Python 3.10+ |
|||
|
|||
```Python |
|||
q: Annotated[str | None] = None |
|||
``` |
|||
|
|||
//// |
|||
|
|||
//// tab | Python 3.8+ |
|||
|
|||
```Python |
|||
q: Annotated[Union[str, None]] = None |
|||
``` |
|||
|
|||
//// |
|||
|
|||
Обидві ці версії означають одне й те саме: `q` — це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`. |
|||
|
|||
А тепер переходимо до цікавого! 🎉 |
|||
|
|||
## Додавання `Query` до `Annotated` у параметр `q` |
|||
|
|||
Тепер, коли у нас є `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 символів |
|||
* Покажe **чітку помилку** клієнту, якщо дані недійсні |
|||
* **Задокументує** параметр в OpenAPI-схемі *операції шляху* (що відобразиться в **автоматично згенерованій документації**) |
|||
|
|||
## Альтернативний (застарілий) метод: Query як значення за замовчуванням |
|||
|
|||
У попередніх версіях 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` всередині `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` |
|||
|
|||
**Використання `Annotated` є рекомендованим** замість задання значення за замовчуванням у параметрах функції, оскільки воно **краще** з кількох причин. 🤓 |
|||
|
|||
Значення **за замовчуванням** параметра **функції** є його **фактичним значенням за замовчуванням**, що є більш інтуїтивним у Python загалом. 😌 |
|||
|
|||
Ви можете **викликати** ту саму функцію **в інших місцях** без FastAPI, і вона **працюватиме очікувано**. Якщо параметр є **обов’язковим** (без значення за замовчуванням), Ваш **редактор** повідомить про помилку, а **Python** також видасть помилку, якщо Ви виконаєте функцію без передавання цього параметра. |
|||
|
|||
Якщо Ви не використовуєте `Annotated`, а використовуєте **(старий) стиль значень за замовчуванням**, то при виклику цієї функції без FastAPI **в інших місцях**, потрібно **не забути** передати їй аргументи, інакше значення будуть відрізнятися від очікуваних (наприклад, Ви отримаєте `QueryInfo` або подібне замість `str`). Ваш редактор не повідомить про помилку, і Python також не видасть помилку при запуску функції, поки не виникне помилка під час виконання операцій усередині. |
|||
|
|||
Оскільки `Annotated` може містити кілька анотацій метаданих, Ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀 |
|||
|
|||
## Додавання додаткових валідацій |
|||
|
|||
Ви також можете додати параметр `min_length`: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *} |
|||
|
|||
## Додавання регулярних виразів |
|||
|
|||
Ви можете визначити <abbr title="Регулярний вираз (regex або regexp) — це послідовність символів, яка визначає шаблон для пошуку в рядках.">регулярний вираз</abbr> pattern, якому має відповідати параметр: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *} |
|||
|
|||
Цей конкретний шаблон регулярного виразу перевіряє, що отримане значення параметра: |
|||
|
|||
* `^`: починається з наступних символів, перед якими немає інших символів. |
|||
* `fixedquery`: точно відповідає значенню `fixedquery`. |
|||
* `$`: закінчується тут, після `fixedquery` немає жодних символів. |
|||
|
|||
Якщо Ви почуваєтеся розгублено щодо **"регулярних виразів"**, не хвилюйтеся. Вони є складною темою для багатьох людей. Ви все одно можете зробити багато речей без їх використання. |
|||
|
|||
Але тепер Ви знаєте, що коли вони знадобляться, їх можна застосовувати у **FastAPI**. |
|||
|
|||
### Pydantic v1 `regex` замість `pattern` |
|||
|
|||
До версії Pydantic 2 і FastAPI 0.100.0 параметр називався `regex` замість `pattern`, але тепер він застарів. |
|||
|
|||
Ви все ще можете зустріти код, який використовує його: |
|||
|
|||
//// tab | Pydantic v1 |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *} |
|||
|
|||
//// |
|||
|
|||
Але майте на увазі, що він є застарілим і його слід оновити до нового параметра `pattern`. 🤓 |
|||
|
|||
## Значення за замовчуванням |
|||
|
|||
Ви можете використовувати значення за замовчуванням, відмінні від `None`. |
|||
|
|||
Наприклад, якщо Ви хочете оголосити параметр запиту `q` з `min_length` `3` і значенням за замовчуванням `"fixedquery"`: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *} |
|||
|
|||
/// note | Технічні деталі |
|||
|
|||
Наявність значення за замовчуванням будь-якого типу, включаючи `None`, робить параметр необов’язковим (not required). |
|||
|
|||
/// |
|||
|
|||
## Обов’язкові параметри |
|||
|
|||
Якщо нам не потрібно вказувати додаткові перевірки або метадані, ми можемо зробити параметр `q` обов’язковим, просто не оголошуючи значення за замовчуванням, наприклад: |
|||
|
|||
```Python |
|||
q: str |
|||
``` |
|||
|
|||
замість: |
|||
|
|||
```Python |
|||
q: str | None = None |
|||
``` |
|||
|
|||
Але тепер ми оголошуємо його з `Query`, наприклад: |
|||
|
|||
//// tab | Annotated |
|||
|
|||
```Python |
|||
q: Annotated[str | None, Query(min_length=3)] = None |
|||
``` |
|||
|
|||
//// |
|||
|
|||
Тому, якщо Вам потрібно зробити значення обов’язковим, використовуючи `Query`, просто не вказуйте значення за замовчуванням: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} |
|||
|
|||
### Обов’язкове значення, яке може бути `None` |
|||
|
|||
Ви можете вказати, що параметр може приймати `None`, але при цьому залишається обов’язковим. Це змусить клієнтів надіслати значення, навіть якщо воно дорівнює `None`. |
|||
|
|||
Щоб зробити це, оголосіть, що `None` є допустимим типом, але не вказуйте значення за замовчуванням: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *} |
|||
|
|||
## Список параметрів запиту / кілька значень |
|||
|
|||
Якщо Ви визначаєте параметр запиту за допомогою `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`) у вигляді списку `list` в Python у Вашій *функції обробки шляху*, у *параметрі функції* `q`. |
|||
|
|||
Отже, відповідь на цей URL буде: |
|||
|
|||
```JSON |
|||
{ |
|||
"q": [ |
|||
"foo", |
|||
"bar" |
|||
] |
|||
} |
|||
``` |
|||
|
|||
/// tip | Підказка |
|||
|
|||
Щоб оголосити параметр запиту з типом `list`, як у наведеному вище прикладі, потрібно явно використовувати `Query`, інакше він буде інтерпретований як тіло запиту. |
|||
|
|||
/// |
|||
|
|||
Інтерактивна API-документація оновиться відповідно, дозволяючи передавати кілька значень: |
|||
|
|||
<img src="/img/tutorial/query-params-str-validations/image02.png"> |
|||
|
|||
### Список параметрів запиту / кілька значень за замовчуванням |
|||
|
|||
Ви також можете визначити значення за замовчуванням для `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` |
|||
|
|||
Ви також можете використовувати `list` без уточнення типу, замість `list[str]`: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *} |
|||
|
|||
/// note | Технічні деталі |
|||
|
|||
Майте на увазі, що в цьому випадку FastAPI не перевірятиме вміст списку. |
|||
|
|||
Наприклад, `list[int]` перевірятиме (і документуватиме), що всі елементи списку є цілими числами. Але `list` без уточнення цього не робитиме. |
|||
|
|||
/// |
|||
|
|||
## Додавання додаткових метаданих |
|||
|
|||
Ви можете додати більше інформації про параметр. |
|||
|
|||
Ця інформація буде включена у згенерований 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] *} |
|||
|
|||
## Аліаси параметрів |
|||
|
|||
Уявіть, що Ви хочете, щоб параметр називався `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] *} |
|||
|
|||
## Виведення параметрів як застарілих |
|||
|
|||
Припустимо, що Ви більше не хочете використовувати цей параметр. |
|||
|
|||
Вам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але Ви хочете, щоб документація чітко показувала, що він є <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 |
|||
|
|||
Щоб виключити параметр запиту зі згенерованої схеми OpenAPI (і, таким чином, з автоматичних систем документації), встановіть параметр `include_in_schema` для `Query` в `False`: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *} |
|||
|
|||
## Кастомна валідація |
|||
|
|||
Можуть бути випадки, коли Вам потрібно провести **кастомну валідацію**, яку не можна реалізувати за допомогою параметрів, показаних вище. |
|||
|
|||
У таких випадках ви можете використати **кастомну функцію валідації**, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`). |
|||
|
|||
Це можна досягти за допомогою <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">Pydantic's `AfterValidator`</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 означає Міжнародний стандартний номер книги">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 Dependencies**. Ви дізнаєтесь про них пізніше. |
|||
|
|||
Ці кастомні валідатори використовуються для речей, які можна перевірити лише з **тими даними**, що надані в запиті. |
|||
|
|||
/// |
|||
|
|||
### Зрозумійте цей код |
|||
|
|||
Головний момент – це використання **`AfterValidator` з функцією всередині `Annotated`**. Можете пропустити цю частину, якщо хочете. 🤸 |
|||
|
|||
--- |
|||
|
|||
Але якщо Вам цікаво розібратися в цьому конкретному прикладі коду і Вам ще не набридло, ось кілька додаткових деталей. |
|||
|
|||
#### Рядок із `value.startswith()` |
|||
|
|||
Звернули увагу? Рядок із `value.startswith()` може приймати кортеж, і тоді він перевірятиме кожне значення в кортежі: |
|||
|
|||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *} |
|||
|
|||
#### Випадковий елемент |
|||
|
|||
За допомогою `data.items()` ми отримуємо <abbr title="Об'єкт, який можна перебирати в циклі, як-от список чи множину.">ітерабельний об'єкт</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] *} |
|||
|
|||
## Підсумок |
|||
|
|||
Ви можете оголошувати додаткові валідації та метаінформацію для своїх параметрів. |
|||
|
|||
Загальні валідації та метаінформація: |
|||
|
|||
* `alias` |
|||
* `title` |
|||
* `description` |
|||
* `deprecated` |
|||
|
|||
Валідації, специфічні для рядків: |
|||
|
|||
* `min_length` |
|||
* `max_length` |
|||
* `pattern` |
|||
|
|||
Кастомні валідації за допомогою `AfterValidator`. |
|||
|
|||
У цих прикладах Ви побачили, як оголошувати валідації для значень `str`. |
|||
|
|||
Дивіться наступні розділи, щоб дізнатися, як оголошувати валідації для інших типів, наприклад чисел. |
Loading…
Reference in new issue