mirror of
https://github.com/fastapi/fastapi.git
synced 2026-07-13 08:23:16 -04:00
🌐 Update translations for ru (update-outdated) (#15894)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Yurii Motov <109919500+YuriiMotov@users.noreply.github.com> Co-authored-by: Yurii Motov <yurii.motov.monte@gmail.com>
This commit is contained in:
committed by
GitHub
parent
473acc1adf
commit
c5ab51d50f
@@ -258,7 +258,7 @@ works(foo="bar") # Это работает 🎉
|
||||
* `bar` как `str`
|
||||
* `baz` как `list`
|
||||
|
||||
* Учебник — Руководство пользователя
|
||||
* Учебник - Руководство пользователя
|
||||
* Расширенное руководство пользователя
|
||||
* Документация по SQLModel
|
||||
* Документация API
|
||||
@@ -461,7 +461,7 @@ works(foo="bar") # Это работает 🎉
|
||||
* библиотека
|
||||
* lifespan
|
||||
* блокировка
|
||||
* middleware (Промежуточный слой)
|
||||
* middleware (промежуточный слой)
|
||||
* мобильное приложение
|
||||
* модуль
|
||||
* монтирование
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Дополнительные статус-коды { #additional-status-codes }
|
||||
|
||||
|
||||
По умолчанию **FastAPI** будет возвращать ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`.
|
||||
|
||||
Он будет использовать статус-код по умолчанию или тот, который вы укажете в вашей *операции пути*.
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
|
||||
|
||||
Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится "bar" в атрибуте `checker.fixed_content`.
|
||||
Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится `"bar"` в атрибуте `checker.fixed_content`.
|
||||
|
||||
## Используем экземпляр как зависимость { #use-the-instance-as-a-dependency }
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
…и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчику пути*:
|
||||
…и передаст возвращённое значение как значение зависимости в нашу *функцию-обработчик пути* в параметр `fixed_content_included`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ FastAPI построен поверх **Pydantic**, и я показывал в
|
||||
|
||||
И, конечно, поддерживаются те же возможности:
|
||||
|
||||
- валидация данных
|
||||
- сериализация данных
|
||||
- документирование данных и т.д.
|
||||
* валидация данных
|
||||
* сериализация данных
|
||||
* документирование данных и т.д.
|
||||
|
||||
Это работает так же, как с Pydantic-моделями. И на самом деле под капотом это достигается тем же образом, с использованием Pydantic.
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# События lifespan { #lifespan-events }
|
||||
|
||||
Вы можете определить логику (код), которую нужно выполнить перед тем, как приложение начнет запускаться. Это означает, что этот код будет выполнен один раз, перед тем как приложение начнет получать HTTP-запросы.
|
||||
Вы можете определить логику (код), которую нужно выполнить перед тем, как приложение **запустится**. Это означает, что этот код будет выполнен **один раз**, **перед** тем как приложение **начнет получать HTTP-запросы**.
|
||||
|
||||
Аналогично, вы можете определить логику (код), которую нужно выполнить, когда приложение завершает работу. В этом случае код будет выполнен один раз, после обработки, возможно, многих запросов.
|
||||
Аналогично, вы можете определить логику (код), которую нужно выполнить, когда приложение **завершает работу**. В этом случае код будет выполнен **один раз**, **после обработки**, возможно, **многих HTTP-запросов**.
|
||||
|
||||
Поскольку этот код выполняется до того, как приложение начинает принимать запросы, и сразу после того, как оно заканчивает их обрабатывать, он охватывает весь lifespan (жизненный цикл) приложения (слово «lifespan» станет важным через секунду 😉).
|
||||
Поскольку этот код выполняется до того, как приложение **начинает** принимать HTTP-запросы, и сразу после того, как оно **заканчивает** их обрабатывать, он охватывает весь **lifespan** (жизненный цикл) приложения (слово «lifespan» станет важным через секунду 😉).
|
||||
|
||||
Это может быть очень полезно для настройки ресурсов, которые нужны для всего приложения, которые разделяются между запросами и/или которые нужно затем очистить. Например, пул подключений к базе данных или загрузка общей модели Машинного обучения.
|
||||
Это может быть очень полезно для настройки **ресурсов**, которые нужны для всего приложения, которые **разделяются** между HTTP-запросами и/или которые нужно затем **очистить**. Например, пул подключений к базе данных или загрузка общей модели Машинного обучения.
|
||||
|
||||
## Вариант использования { #use-case }
|
||||
|
||||
Начнем с примера варианта использования, а затем посмотрим, как это решить.
|
||||
Начнем с примера **варианта использования**, а затем посмотрим, как это решить.
|
||||
|
||||
Представим, что у вас есть несколько моделей Машинного обучения, которые вы хотите использовать для обработки запросов. 🤖
|
||||
Представим, что у вас есть несколько **моделей Машинного обучения**, которые вы хотите использовать для обработки HTTP-запросов. 🤖
|
||||
|
||||
Эти же модели разделяются между запросами, то есть это не одна модель на запрос, не одна на пользователя и т.п.
|
||||
Эти же модели разделяются между HTTP-запросами, то есть это не одна модель на HTTP-запрос, не одна на пользователя и т.п.
|
||||
|
||||
Представим, что загрузка модели может занимать довольно много времени, потому что ей нужно прочитать много данных с диска. Поэтому вы не хотите делать это для каждого запроса.
|
||||
Представим, что загрузка модели может **занимать довольно много времени**, потому что ей нужно прочитать много **данных с диска**. Поэтому вы не хотите делать это для каждого HTTP-запроса.
|
||||
|
||||
Вы могли бы загрузить её на верхнем уровне модуля/файла, но это означало бы, что модель загружается даже если вы просто запускаете простой автоматический тест; тогда этот тест будет медленным, так как ему придется ждать загрузки модели перед запуском независимой части кода.
|
||||
Вы могли бы загрузить её на верхнем уровне модуля/файла, но это означало бы, что модель будет **загружаться** даже если вы просто запускаете простой автоматический тест; тогда этот тест будет **медленным**, так как ему придется ждать загрузки модели перед запуском независимой части кода.
|
||||
|
||||
Именно это мы и решим: давайте загружать модель перед тем, как начнётся обработка запросов, но только непосредственно перед тем, как приложение начнет принимать запросы, а не во время загрузки кода.
|
||||
Именно это мы и решим: давайте загружать модель перед тем, как начнётся обработка HTTP-запросов, но только непосредственно перед тем, как приложение начнет принимать HTTP-запросы, а не во время загрузки кода.
|
||||
|
||||
## Lifespan { #lifespan }
|
||||
|
||||
Вы можете определить логику для startup и shutdown, используя параметр `lifespan` приложения `FastAPI` и «менеджер контекста» (через секунду покажу что это).
|
||||
Вы можете определить логику для *startup* и *shutdown*, используя параметр `lifespan` приложения `FastAPI` и «менеджер контекста» (через секунду покажу что это).
|
||||
|
||||
Начнем с примера, а затем разберём его подробнее.
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
|
||||
|
||||
Здесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup.
|
||||
Здесь мы симулируем дорогую операцию *startup* по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен **до** того, как приложение **начнет принимать HTTP-запросы**, во время *startup*.
|
||||
|
||||
А затем сразу после `yield` мы выгружаем модель. Этот код будет выполнен после того, как приложение закончит обрабатывать запросы, непосредственно перед shutdown. Это может, например, освободить ресурсы, такие как память или GPU.
|
||||
А затем сразу после `yield` мы выгружаем модель. Этот код будет выполнен **после** того, как приложение **закончит обрабатывать HTTP-запросы**, непосредственно перед *shutdown*. Это может, например, освободить ресурсы, такие как память или GPU.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
`shutdown` произойдёт, когда вы останавливаете приложение.
|
||||
`shutdown` произойдёт, когда вы **останавливаете** приложение.
|
||||
|
||||
Возможно, вам нужно запустить новую версию, или вы просто устали от него. 🤷
|
||||
|
||||
@@ -50,26 +50,26 @@
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
|
||||
|
||||
Первая часть функции, до `yield`, будет выполнена до запуска приложения.
|
||||
Первая часть функции, до `yield`, будет выполнена **до** запуска приложения.
|
||||
|
||||
А часть после `yield` будет выполнена после завершения работы приложения.
|
||||
А часть после `yield` будет выполнена **после** завершения работы приложения.
|
||||
|
||||
### Асинхронный менеджер контекста { #async-context-manager }
|
||||
|
||||
Если присмотреться, функция декорирована `@asynccontextmanager`.
|
||||
|
||||
Это превращает функцию в «асинхронный менеджер контекста».
|
||||
Это превращает функцию в «**асинхронный менеджер контекста**».
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
|
||||
|
||||
Менеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:
|
||||
**Менеджер контекста** в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:
|
||||
|
||||
```Python
|
||||
with open("file.txt") as file:
|
||||
file.read()
|
||||
```
|
||||
|
||||
В последних версиях Python есть также асинхронный менеджер контекста. Его используют с `async with`:
|
||||
В последних версиях Python есть также **асинхронный менеджер контекста**. Его используют с `async with`:
|
||||
|
||||
```Python
|
||||
async with lifespan(app):
|
||||
@@ -80,7 +80,7 @@ async with lifespan(app):
|
||||
|
||||
В нашем примере выше мы не используем его напрямую, а передаём его в FastAPI, чтобы он использовал его сам.
|
||||
|
||||
Параметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.
|
||||
Параметр `lifespan` приложения `FastAPI` принимает **асинхронный менеджер контекста**, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
|
||||
|
||||
@@ -88,13 +88,13 @@ async with lifespan(app):
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Рекомендуемый способ обрабатывать startup и shutdown — использовать параметр `lifespan` приложения `FastAPI`, как описано выше. Если вы укажете параметр `lifespan`, обработчики событий `startup` и `shutdown` больше вызываться не будут. Либо всё через `lifespan`, либо всё через события — не одновременно.
|
||||
Рекомендуемый способ обрабатывать *startup* и *shutdown* — использовать параметр `lifespan` приложения `FastAPI`, как описано выше. Если вы укажете параметр `lifespan`, обработчики событий `startup` и `shutdown` больше вызываться не будут. Либо всё через `lifespan`, либо всё через события — не одновременно.
|
||||
|
||||
Эту часть, скорее всего, можно пропустить.
|
||||
|
||||
///
|
||||
|
||||
Есть альтернативный способ определить логику, которую нужно выполнить во время startup и во время shutdown.
|
||||
Есть альтернативный способ определить логику, которую нужно выполнить во время *startup* и во время *shutdown*.
|
||||
|
||||
Вы можете определить обработчики событий (функции), которые нужно выполнить до старта приложения или при его завершении.
|
||||
|
||||
@@ -110,7 +110,7 @@ async with lifespan(app):
|
||||
|
||||
Вы можете добавить более одного обработчика события.
|
||||
|
||||
И ваше приложение не начнет принимать запросы, пока все обработчики события `startup` не завершатся.
|
||||
И ваше приложение не начнет принимать HTTP-запросы, пока все обработчики события `startup` не завершатся.
|
||||
|
||||
### Событие `shutdown` { #shutdown-event }
|
||||
|
||||
@@ -140,7 +140,7 @@ async with lifespan(app):
|
||||
|
||||
### `startup` и `shutdown` вместе { #startup-and-shutdown-together }
|
||||
|
||||
С высокой вероятностью логика для вашего startup и shutdown связана: вы можете хотеть что-то запустить, а затем завершить, получить ресурс, а затем освободить его и т.д.
|
||||
С высокой вероятностью логика для вашего *startup* и *shutdown* связана: вы можете хотеть что-то запустить, а затем завершить, получить ресурс, а затем освободить его и т.д.
|
||||
|
||||
Делать это в отдельных функциях, которые не разделяют общую логику или переменные, сложнее, так как придётся хранить значения в глобальных переменных или использовать похожие приёмы.
|
||||
|
||||
@@ -148,9 +148,9 @@ async with lifespan(app):
|
||||
|
||||
## Технические детали { #technical-details }
|
||||
|
||||
Немного технических подробностей для любопытных умников. 🤓
|
||||
Просто техническая подробность для любопытных умников. 🤓
|
||||
|
||||
Под капотом, в ASGI-технической спецификации, это часть [Протокола Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), и он определяет события `startup` и `shutdown`.
|
||||
Под капотом, в технической спецификации ASGI, это часть [Протокола Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), и он определяет события `startup` и `shutdown`.
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
@@ -162,4 +162,4 @@ async with lifespan(app):
|
||||
|
||||
## Подприложения { #sub-applications }
|
||||
|
||||
🚨 Имейте в виду, что эти события lifespan (startup и shutdown) будут выполнены только для основного приложения, а не для [Подприложения — Mounts](sub-applications.md).
|
||||
🚨 Имейте в виду, что эти события lifespan (startup и shutdown) будут выполнены только для основного приложения, а не для [Подприложений - Mounts](sub-applications.md).
|
||||
|
||||
@@ -20,20 +20,6 @@ FastAPI автоматически генерирует спецификации
|
||||
|
||||
///
|
||||
|
||||
## Генераторы SDK от спонсоров FastAPI { #sdk-generators-from-fastapi-sponsors }
|
||||
|
||||
В этом разделе представлены решения с **венчурной поддержкой** и **поддержкой компаний** от компаний, которые спонсируют FastAPI. Эти продукты предоставляют **дополнительные возможности** и **интеграции** сверх высококачественно генерируемых SDK.
|
||||
|
||||
Благодаря ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ эти компании помогают обеспечивать, чтобы фреймворк и его **экосистема** оставались здоровыми и **устойчивыми**.
|
||||
|
||||
Их спонсорство также демонстрирует серьёзную приверженность **сообществу** FastAPI (вам), показывая, что им важно не только предоставлять **отличный сервис**, но и поддерживать **надёжный и процветающий фреймворк** FastAPI. 🙇
|
||||
|
||||
Например, вы можете попробовать:
|
||||
|
||||
* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)
|
||||
|
||||
Некоторые из этих решений также могут быть open source или иметь бесплатные тарифы, так что вы сможете попробовать их без финансовых затрат. Другие коммерческие генераторы SDK доступны и их можно найти онлайн. 🤓
|
||||
|
||||
## Создать TypeScript SDK { #create-a-typescript-sdk }
|
||||
|
||||
Начнём с простого приложения FastAPI:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Base64 и файлы { #base64-vs-files }
|
||||
|
||||
Сначала рассмотрите возможность использовать [Файлы в запросе](../tutorial/request-files.md) для загрузки бинарных данных и [Пользовательский HTTP-ответ — FileResponse](./custom-response.md#fileresponse--fileresponse-) для отправки бинарных данных вместо кодирования их в JSON.
|
||||
Сначала рассмотрите возможность использовать [Файлы в запросе](../tutorial/request-files.md) для загрузки бинарных данных и [Пользовательский HTTP-ответ — FileResponse](./custom-response.md#fileresponse) для отправки бинарных данных вместо кодирования их в JSON.
|
||||
|
||||
JSON может содержать только строки в кодировке UTF-8, поэтому он не может содержать «сырые» байты.
|
||||
|
||||
@@ -14,7 +14,7 @@ Base64 может кодировать бинарные данные в стро
|
||||
|
||||
## Pydantic `bytes` { #pydantic-bytes }
|
||||
|
||||
Вы можете объявить Pydantic-модель с полями `bytes`, а затем использовать `val_json_bytes` в конфиге модели, чтобы указать использовать base64 для валидации входящих JSON-данных; как часть этой валидации строка base64 будет декодирована в байты.
|
||||
Вы можете объявить Pydantic-модель с полями `bytes`, а затем использовать `val_json_bytes` в конфиге модели, чтобы указать использовать base64 для *валидации* входящих JSON-данных; как часть этой валидации строка base64 будет декодирована в байты.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
|
||||
|
||||
@@ -52,12 +52,12 @@ Base64 может кодировать бинарные данные в стро
|
||||
|
||||
## Pydantic `bytes` для выходных данных { #pydantic-bytes-for-output-data }
|
||||
|
||||
Вы также можете использовать поля `bytes` с `ser_json_bytes` в конфиге модели для выходных данных, и Pydantic будет сериализовать байты в base64 при формировании JSON-ответа.
|
||||
Вы также можете использовать поля `bytes` с `ser_json_bytes` в конфиге модели для выходных данных, и Pydantic будет *сериализовать* байты в base64 при формировании JSON-ответа.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
|
||||
|
||||
## Pydantic `bytes` для входных и выходных данных { #pydantic-bytes-for-input-and-output-data }
|
||||
|
||||
И, конечно, вы можете использовать одну и ту же модель, настроенную на использование base64, чтобы обрабатывать и входящие данные (валидация) с `val_json_bytes`, и исходящие данные (сериализация) с `ser_json_bytes` при приеме и отправке JSON-данных.
|
||||
И, конечно, вы можете использовать одну и ту же модель, настроенную на использование base64, чтобы обрабатывать и входящие данные (*валидировать*) с `val_json_bytes`, и исходящие данные (*сериализовать*) с `ser_json_bytes` при приеме и отправке JSON-данных.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Обратные вызовы в OpenAPI { #openapi-callbacks }
|
||||
|
||||
Вы можете создать API с *операцией пути* (обработчиком пути), которая будет инициировать HTTP-запрос к *внешнему API*, созданному кем-то другим (скорее всего тем же разработчиком, который будет использовать ваш API).
|
||||
Вы можете создать API с *операцией пути* (обработчиком пути), которая будет инициировать HTTP-запрос к *внешнему API*, созданному кем-то другим (скорее всего тем же разработчиком, который будет *использовать* ваш API).
|
||||
|
||||
Процесс, происходящий, когда ваше приложение API обращается к *внешнему API*, называется «callback» (обратный вызов). Программное обеспечение, написанное внешним разработчиком, отправляет HTTP-запрос вашему API, а затем ваш API выполняет обратный вызов, отправляя HTTP-запрос во *внешний API* (который, вероятно, тоже создал тот же разработчик).
|
||||
Процесс, происходящий, когда ваше приложение API обращается к *внешнему API*, называется «callback» (обратный вызов). Потому что программное обеспечение, написанное внешним разработчиком, отправляет HTTP-запрос вашему API, а затем ваш API выполняет обратный вызов, отправляя HTTP-запрос во *внешний API* (который, вероятно, тоже создал тот же разработчик).
|
||||
|
||||
В этом случае вам может понадобиться задокументировать, как должно выглядеть это внешнее API: какую *операцию пути* оно должно иметь, какое тело запроса ожидать, какой ответ возвращать и т.д.
|
||||
В этом случае вам может понадобиться задокументировать, как это внешнее API *должно* выглядеть: какую *операцию пути* оно должно иметь, какое тело запроса ожидать, какой HTTP-ответ возвращать и т.д.
|
||||
|
||||
## Приложение с обратными вызовами { #an-app-with-callbacks }
|
||||
|
||||
@@ -82,7 +82,7 @@ httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
||||
|
||||
Когда вы пишете код для документирования обратного вызова, полезно представить, что вы — тот самый *внешний разработчик*. И что вы сейчас реализуете *внешний API*, а не *свой API*.
|
||||
|
||||
Временное принятие этой точки зрения (внешнего разработчика) поможет интуитивно понять, куда поместить параметры, какую Pydantic-модель использовать для тела запроса, для ответа и т.д. во *внешнем API*.
|
||||
Временное принятие этой точки зрения (внешнего разработчика) поможет интуитивно понять, куда поместить параметры, какую Pydantic-модель использовать для тела запроса, для HTTP-ответа и т.д. во *внешнем API*.
|
||||
|
||||
///
|
||||
|
||||
@@ -99,7 +99,7 @@ httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
||||
Она должна выглядеть как обычная *операция пути* FastAPI:
|
||||
|
||||
* Вероятно, в ней должно быть объявление тела запроса, например `body: InvoiceEvent`.
|
||||
* А также может быть объявление модели ответа, например `response_model=InvoiceEventReceived`.
|
||||
* А также может быть объявление HTTP-ответа, который она должна возвращать, например `response_model=InvoiceEventReceived`.
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
|
||||
|
||||
@@ -124,7 +124,7 @@ httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
||||
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
||||
```
|
||||
|
||||
с телом JSON:
|
||||
с телом запроса JSON:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -140,7 +140,7 @@ https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
||||
https://www.external.org/events/invoices/2expen51ve
|
||||
```
|
||||
|
||||
с телом JSON примерно такого вида:
|
||||
с телом запроса JSON примерно такого вида:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -149,7 +149,7 @@ https://www.external.org/events/invoices/2expen51ve
|
||||
}
|
||||
```
|
||||
|
||||
и будет ожидать от *внешнего API* ответ с телом JSON вида:
|
||||
и будет ожидать от *внешнего API* HTTP-ответ с JSON в теле ответа:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -163,17 +163,17 @@ https://www.external.org/events/invoices/2expen51ve
|
||||
|
||||
///
|
||||
|
||||
### Подключите маршрутизатор обратного вызова { #add-the-callback-router }
|
||||
### Добавьте роутер обратного вызова { #add-the-callback-router }
|
||||
|
||||
К этому моменту у вас есть необходимые *операции пути* обратного вызова (те, которые *внешний разработчик* должен реализовать во *внешнем API*) в созданном выше маршрутизаторе обратных вызовов.
|
||||
К этому моменту у вас есть необходимые *операции пути* обратного вызова (те, которые *внешний разработчик* должен реализовать во *внешнем API*) в созданном выше роутере обратных вызовов.
|
||||
|
||||
Теперь используйте параметр `callbacks` в *декораторе операции пути вашего API*, чтобы передать атрибут `.routes` из этого маршрутизатора обратных вызовов:
|
||||
Теперь используйте параметр `callbacks` в *декораторе операции пути вашего API*, чтобы передать атрибут `.routes` из этого роутера обратных вызовов:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Обратите внимание, что вы передаёте не сам маршрутизатор (`invoices_callback_router`) в `callback=`, а его атрибут `.routes`, то есть `invoices_callback_router.routes`. FastAPI будет использовать эти маршруты для генерации документации OpenAPI для обратных вызовов.
|
||||
Обратите внимание, что вы передаёте не сам роутер (`invoices_callback_router`) в `callbacks=`, а его атрибут `.routes`, то есть `invoices_callback_router.routes`. FastAPI будет использовать эти маршруты для генерации документации OpenAPI для обратных вызовов.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Response - Изменение статус-кода { #response-change-status-code }
|
||||
|
||||
Вы, вероятно, уже читали о том, что можно установить [статус-код ответа по умолчанию](../tutorial/response-status-code.md).
|
||||
Вы, вероятно, уже читали о том, что можно установить [статус-код ответа](../tutorial/response-status-code.md) по умолчанию.
|
||||
|
||||
Но в некоторых случаях нужно вернуть другой статус-код, отличный от значения по умолчанию.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
## Использование параметра `Response` { #use-a-response-parameter }
|
||||
|
||||
Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (как и для cookies и HTTP-заголовков).
|
||||
Вы можете объявить параметр типа `Response` в вашей *функции-обработчике пути* (как и для cookies и HTTP-заголовков).
|
||||
|
||||
И затем вы можете установить `status_code` в этом *временном* объекте ответа.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Cookies в ответе { #response-cookies }
|
||||
|
||||
|
||||
## Использование параметра `Response` { #use-a-response-parameter }
|
||||
|
||||
Вы можете объявить параметр типа `Response` в вашей функции-обработчике пути.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Использовать параметр `Response` { #use-a-response-parameter }
|
||||
|
||||
Вы можете объявить параметр типа `Response` в вашей функции-обработчике пути (как можно сделать и для cookie).
|
||||
Вы можете объявить параметр типа `Response` в вашей *функции-обработчике пути* (как можно сделать и для cookie).
|
||||
|
||||
А затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа.
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
**FastAPI** использует этот *временный* ответ, чтобы извлечь HTTP-заголовки (а также cookie и статус-код) и поместит их в финальный HTTP-ответ, который содержит возвращённое вами значение, отфильтрованное согласно `response_model`.
|
||||
|
||||
Вы также можете объявлять параметр `Response` в зависимостях и устанавливать в них заголовки (и cookie).
|
||||
Вы также можете объявлять параметр `Response` в зависимостях и устанавливать в них HTTP-заголовки (и cookie).
|
||||
|
||||
## Вернуть `Response` напрямую { #return-a-response-directly }
|
||||
|
||||
Вы также можете добавить HTTP-заголовки, когда возвращаете `Response` напрямую.
|
||||
|
||||
Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md), и передайте заголовки как дополнительный параметр:
|
||||
Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md), и передайте HTTP-заголовки как дополнительный параметр:
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
|
||||
**FastAPI** предоставляет те же самые `starlette.responses` как `fastapi.responses` — для вашего удобства как разработчика. Но большинство доступных классов ответов поступают напрямую из Starlette.
|
||||
|
||||
И поскольку `Response` часто используется для установки заголовков и cookie, **FastAPI** также предоставляет его как `fastapi.Response`.
|
||||
И поскольку `Response` часто используется для установки HTTP-заголовков и cookie, **FastAPI** также предоставляет его как `fastapi.Response`.
|
||||
|
||||
///
|
||||
|
||||
## Пользовательские HTTP-заголовки { #custom-headers }
|
||||
|
||||
Помните, что собственные проприетарные заголовки можно добавлять, [используя префикс `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
|
||||
Помните, что собственные проприетарные HTTP-заголовки можно добавлять, [используя префикс `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
|
||||
|
||||
Но если у вас есть пользовательские заголовки, которые вы хотите показывать клиенту в браузере, вам нужно добавить их в настройки CORS (подробнее см. в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), используя параметр `expose_headers`, описанный в [документации Starlette по CORS](https://www.starlette.dev/middleware/#corsmiddleware).
|
||||
Но если у вас есть пользовательские HTTP-заголовки, которые вы хотите показывать клиенту в браузере, вам нужно добавить их в настройки CORS (подробнее см. в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), используя параметр `expose_headers`, описанный в [документации Starlette по CORS](https://www.starlette.dev/middleware/#corsmiddleware).
|
||||
|
||||
@@ -76,7 +76,7 @@ OAuth2 со scopes — это механизм, который использу
|
||||
|
||||
Так как теперь мы объявляем эти scopes, они появятся в документации API при входе/авторизации.
|
||||
|
||||
И вы сможете выбрать, какие scopes вы хотите выдать доступ: `me` и `items`.
|
||||
И вы сможете выбрать, для каких scopes хотите предоставить доступ: `me` и `items`.
|
||||
|
||||
Это тот же механизм, когда вы даёте разрешения при входе через Facebook, Google, GitHub и т.д.:
|
||||
|
||||
@@ -100,7 +100,7 @@ OAuth2 со scopes — это механизм, который использу
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
|
||||
|
||||
## Объявление scopes в *обработчиках путей* и зависимостях { #declare-scopes-in-path-operations-and-dependencies }
|
||||
## Объявление scopes в *операциях пути* и зависимостях { #declare-scopes-in-path-operations-and-dependencies }
|
||||
|
||||
Теперь объявим, что операция пути для `/users/me/items/` требует scope `items`.
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
### Создание `Settings` только один раз с помощью `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
Чтение файла с диска обычно затратная (медленная) операция, поэтому, вероятно, вы захотите сделать это один раз и затем переиспользовать один и тот же объект настроек, а не читать файл при каждом запросе.
|
||||
Чтение файла с диска обычно затратная (медленная) операция, поэтому, вероятно, вы захотите сделать это один раз и затем переиспользовать один и тот же объект настроек, а не читать файл при каждом HTTP-запросе.
|
||||
|
||||
Но каждый раз, когда мы делаем:
|
||||
|
||||
@@ -222,13 +222,13 @@ def get_settings():
|
||||
return Settings()
|
||||
```
|
||||
|
||||
мы бы создавали этот объект для каждого запроса и читали файл `.env` на каждый запрос. ⚠️
|
||||
мы бы создавали этот объект для каждого HTTP-запроса и читали файл `.env` на каждый HTTP-запрос. ⚠️
|
||||
|
||||
Но так как мы используем декоратор `@lru_cache` сверху, объект `Settings` будет создан только один раз — при первом вызове. ✔️
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
|
||||
|
||||
Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.
|
||||
Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих HTTP-запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.
|
||||
|
||||
#### Технические детали `lru_cache` { #lru-cache-technical-details }
|
||||
|
||||
@@ -299,4 +299,4 @@ participant execute as Execute function
|
||||
|
||||
* Используя зависимость, вы упрощаете тестирование.
|
||||
* Можно использовать файлы `.env`.
|
||||
* `@lru_cache` позволяет не читать файл dotenv снова и снова для каждого запроса, при этом давая возможность переопределять его во время тестирования.
|
||||
* `@lru_cache` позволяет не читать файл dotenv снова и снова для каждого HTTP-запроса, при этом давая возможность переопределять его во время тестирования.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Если вам нужно передавать потоковые данные, которые можно представить как JSON, воспользуйтесь [стримингом JSON Lines](../tutorial/stream-json-lines.md).
|
||||
|
||||
Но если вы хотите передавать в потоке чистые бинарные данные или строки, ниже показано, как это сделать.
|
||||
Но если вы хотите передавать в потоке **чистые бинарные данные** или строки, ниже показано, как это сделать.
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
@@ -40,7 +40,7 @@ FastAPI будет передавать каждый чанк данных в `S
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
|
||||
|
||||
Это также означает, что с `StreamingResponse` у вас есть и свобода, и ответственность — производить и кодировать байты данных ровно в том виде, в котором они должны быть отправлены, независимо от аннотаций типов. 🤓
|
||||
Это также означает, что с `StreamingResponse` у вас есть и **свобода**, и **ответственность** — производить и кодировать байты данных ровно в том виде, в котором они должны быть отправлены, независимо от аннотаций типов. 🤓
|
||||
|
||||
### Потоковая передача байтов { #stream-bytes }
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
Нужно импортировать `WSGIMiddleware` из `a2wsgi`.
|
||||
|
||||
Затем оберните WSGI‑приложение (например, Flask) в middleware (Промежуточный слой).
|
||||
Затем оберните WSGI‑приложение (например, Flask) в middleware (промежуточный слой).
|
||||
|
||||
После этого смонтируйте его на путь.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
Вместо него рекомендуется использовать пакет `a2wsgi`. Использование остаётся таким же.
|
||||
|
||||
Просто убедитесь, что пакет `a2wsgi` установлен, и импортируйте `WSGIMiddleware` из `a2wsgi`.
|
||||
Просто убедитесь, что пакет `a2wsgi` установлен, и правильно импортируйте `WSGIMiddleware` из `a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
Он относительно тесно связан с реляционными базами данных (например, MySQL или PostgreSQL), поэтому использовать NoSQL-базу данных (например, Couchbase, MongoDB, Cassandra и т. п.) в качестве основного хранилища не очень просто.
|
||||
|
||||
Он был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами <abbr title="Internet of Things – Интернет вещей">IoT</abbr>), которые с ним общаются.
|
||||
Он был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами <abbr title="Internet of Things - Интернет вещей">IoT</abbr>), которые с ним общаются.
|
||||
|
||||
### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }
|
||||
|
||||
@@ -88,7 +88,7 @@ Requests имеет очень простой и понятный дизайн,
|
||||
response = requests.get("http://example.com/some/url")
|
||||
```
|
||||
|
||||
Соответствующая в FastAPI API-операция пути могла бы выглядеть так:
|
||||
Соответствующая в FastAPI API-*операция пути* могла бы выглядеть так:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@app.get("/some/url")
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
results = await some_library()
|
||||
```
|
||||
|
||||
Тогда объявляйте *функции-обработчиков пути* с `async def`, например:
|
||||
Тогда объявляйте *функции-обработчики пути* с `async def`, например:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -29,7 +29,7 @@ async def read_results():
|
||||
|
||||
---
|
||||
|
||||
Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т.д.) и не поддерживает использование `await` (сейчас это относится к большинству библиотек для БД), тогда объявляйте *функции-обработчиков пути* как обычно, просто с `def`, например:
|
||||
Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т.д.) и не поддерживает использование `await` (сейчас это относится к большинству библиотек для БД), тогда объявляйте *функции-обработчики пути* как обычно, просто с `def`, например:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -48,7 +48,7 @@ def results():
|
||||
|
||||
---
|
||||
|
||||
**Примечание**: вы можете смешивать `def` и `async def` в *функциях-обработчиков пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо.
|
||||
**Примечание**: вы можете смешивать `def` и `async def` в *функциях-обработчиках пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо.
|
||||
|
||||
В любом из случаев выше FastAPI всё равно работает асинхронно и очень быстро.
|
||||
|
||||
@@ -249,7 +249,7 @@ def results():
|
||||
|
||||
Именно такая асинхронность сделала NodeJS популярным (хотя NodeJS — не параллельный), и это сильная сторона Go как языка программирования.
|
||||
|
||||
Того же уровня производительности вы получаете с **FastAPI**.
|
||||
Тот же уровень производительности вы получаете с **FastAPI**.
|
||||
|
||||
А так как можно одновременно использовать параллелизм и асинхронность, вы получаете производительность выше, чем у большинства протестированных фреймворков на NodeJS и на уровне Go, который — компилируемый язык, ближе к C [(всё благодаря Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).
|
||||
|
||||
@@ -340,7 +340,7 @@ burgers = get_burgers(2)
|
||||
|
||||
---
|
||||
|
||||
Итак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функцию-обработчик пути*, которая её использует, с `async def`, например:
|
||||
Итак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функции-обработчики пути*, которые её используют, с `async def`, например:
|
||||
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Развертывание FastAPI у облачных провайдеров { #deploy-fastapi-on-cloud-providers }
|
||||
|
||||
Вы можете использовать практически любого облачного провайдера, чтобы развернуть свое приложение на FastAPI.
|
||||
Вы можете использовать практически **любого облачного провайдера**, чтобы развернуть свое приложение на FastAPI.
|
||||
|
||||
В большинстве случаев у основных облачных провайдеров есть руководства по развертыванию FastAPI на их платформе.
|
||||
|
||||
@@ -16,7 +16,7 @@ FastAPI Cloud — основной спонсор и источник финан
|
||||
|
||||
## Облачные провайдеры — спонсоры { #cloud-providers-sponsors }
|
||||
|
||||
Некоторые другие облачные провайдеры ✨ [**спонсируют FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ тоже. 🙇
|
||||
Некоторые другие облачные провайдеры ✨ [**спонсируют FastAPI**](https://github.com/sponsors/tiangolo) ✨ тоже. 🙇
|
||||
|
||||
Возможно, вы захотите попробовать их сервисы и воспользоваться их руководствами:
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@
|
||||
|
||||
Не беспокойтесь, если некоторые пункты про **контейнеры**, Docker или Kubernetes пока кажутся неочевидными.
|
||||
|
||||
Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md).
|
||||
Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в одной из будущих глав: [FastAPI внутри контейнеров — Docker](docker.md).
|
||||
|
||||
///
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Я приведу более конкретные примеры с контейнерами в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md).
|
||||
Я приведу более конкретные примеры с контейнерами в одной из будущих глав: [FastAPI внутри контейнеров — Docker](docker.md).
|
||||
|
||||
///
|
||||
|
||||
@@ -301,9 +301,9 @@
|
||||
|
||||
Также возможен **всплеск** использования вашего API: он мог «взорваться» по популярности, или какие‑то сервисы/боты начали его активно использовать. На такие случаи стоит иметь запас ресурсов.
|
||||
|
||||
Можно задать **целевое значение**, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание.
|
||||
Можно задать **произвольное число** в качестве цели, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание.
|
||||
|
||||
Можно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные распределённые системы мониторинга.
|
||||
Можно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные инструменты мониторинга, которые могут быть распределены по серверам и т.п.
|
||||
|
||||
## Резюме { #recap }
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ CMD fastapi run app/main.py --port 80
|
||||
|
||||
#### За прокси-сервером TSL-терминации { #behind-a-tls-termination-proxy }
|
||||
|
||||
Если вы запускаете контейнер за прокси-сервером TSL-терминации (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.
|
||||
Если вы запускаете контейнер за прокси-сервером TSL-терминации (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что можно доверять заголовкам, отправленным этим прокси и сообщающим, что приложение работает за HTTPS, и т.д.
|
||||
|
||||
```Dockerfile
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
@@ -407,9 +407,9 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
|
||||
|
||||
1. Копируем файл `main.py` напрямую в `/code` (без директории `./app`).
|
||||
|
||||
2. Используем `fastapi run` для запуска приложения из одного файла `main.py`.
|
||||
2. Используем `fastapi run`, чтобы «отдавать» приложение из одного файла `main.py`.
|
||||
|
||||
Когда вы передаёте файл в `fastapi run`, он автоматически определит, что это одиночный файл, а не часть пакета, и поймёт, как его импортировать и запустить ваше FastAPI-приложение. 😎
|
||||
Когда вы передаёте файл в `fastapi run`, он автоматически определит, что это одиночный файл, а не часть пакета, и поймёт, как импортировать и «отдавать» ваше FastAPI-приложение. 😎
|
||||
|
||||
## Концепции развертывания { #deployment-concepts }
|
||||
|
||||
@@ -525,7 +525,7 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
|
||||
Вы можете развёртывать на **одном сервере** (не кластере) с **Docker Compose**, и у вас не будет простого способа управлять репликацией контейнеров (в Docker Compose), сохраняя общую сеть и **балансировку нагрузки**.
|
||||
|
||||
Тогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркеров** внутри.
|
||||
Тогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркер-процессов** внутри.
|
||||
|
||||
---
|
||||
|
||||
@@ -566,7 +566,7 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
|
||||
### Один контейнер { #single-container }
|
||||
|
||||
Если у вас простая схема с **одним контейнером**, который затем запускает несколько **воркеров** (или один процесс), можно выполнить подготовительные шаги в этом же контейнере непосредственно перед запуском процесса с приложением.
|
||||
Если у вас простая схема с **одним контейнером**, который затем запускает несколько **воркер-процессов** (или один процесс), можно выполнить подготовительные шаги в этом же контейнере непосредственно перед запуском процесса с приложением.
|
||||
|
||||
### Базовый Docker-образ { #base-docker-image }
|
||||
|
||||
@@ -580,7 +580,7 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
|
||||
/// note | Технические подробности
|
||||
|
||||
Этот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркеров Uvicorn.
|
||||
Этот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркер-процессы Uvicorn.
|
||||
|
||||
Но теперь, когда Uvicorn (и команда `fastapi`) поддерживают `--workers`, нет причин использовать базовый Docker-образ вместо сборки своего (кода получается примерно столько же 😅).
|
||||
|
||||
@@ -615,4 +615,4 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
|
||||
В большинстве случаев вы, вероятно, не захотите использовать какой-либо базовый образ, а вместо этого **соберёте образ контейнера с нуля** на основе официального Docker-образа Python.
|
||||
|
||||
Заботясь о **порядке** инструкций в `Dockerfile` и используя **кэш Docker**, вы можете **минимизировать время сборки**, чтобы повысить продуктивность (и не скучать). 😎
|
||||
Заботясь о **порядке** инструкций в `Dockerfile` и используя **кэш Docker**, вы можете **минимизировать время сборки**, чтобы повысить продуктивность (и не скучать). 😎
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Если вы торопитесь или вам это не важно, переходите к следующим разделам с пошаговыми инструкциями по настройке всего разными способами.
|
||||
Если вы торопитесь или вам это не важно, продолжайте со следующих разделов с пошаговыми инструкциями по настройке всего разными способами.
|
||||
|
||||
///
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера).
|
||||
|
||||
Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет <dfn title="Со временем не меняется. Не динамический.">постоянный</dfn> **публичный IP-адрес**.
|
||||
Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет <dfn title="Не меняется со временем. Не динамический.">постоянный</dfn> **публичный IP-адрес**.
|
||||
|
||||
На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**.
|
||||
|
||||
@@ -194,7 +194,7 @@ DNS‑серверы ответят браузеру, какой **конкре
|
||||
|
||||
Когда вы используете прокси для обработки HTTPS, ваш **сервер приложения** (например, Uvicorn через FastAPI CLI) ничего не знает о процессе HTTPS, он общается обычным HTTP с **прокси‑сервером TLS-терминации**.
|
||||
|
||||
Обычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **проксирован**.
|
||||
Обычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **переслан** прокси.
|
||||
|
||||
/// note | Технические детали
|
||||
|
||||
@@ -218,7 +218,7 @@ DNS‑серверы ответят браузеру, какой **конкре
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Подробнее об этом вы можете узнать в документации: [За прокси — Включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)
|
||||
Подробнее об этом вы можете узнать в документации: [За прокси — включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Используйте команду `fastapi run` { #use-the-fastapi-run-command }
|
||||
|
||||
Коротко: используйте `fastapi run`, чтобы запустить ваше приложение FastAPI:
|
||||
Коротко: используйте `fastapi run`, чтобы предоставлять доступ к вашему приложению FastAPI:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
- **Развернуть в FastAPI Cloud** — развертывание вашего приложения в один клик в [FastAPI Cloud](https://fastapicloud.com/).
|
||||
- **Поток логов приложения** — потоковая передача логов в реальном времени из вашего приложения, развернутого в FastAPI Cloud, с фильтрацией по уровню и текстовым поиском.
|
||||
|
||||
Если вы хотите поверхностно ознакомиться с возможностями расширения, откройте палитру команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> или на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), выберите «Welcome: Open walkthrough...», а затем «Get started with FastAPI».
|
||||
Если вы хотите ознакомиться с возможностями расширения, вы можете посмотреть walkthrough расширения, открыв палитру команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> или на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>) и выбрав «Welcome: Open walkthrough...», а затем walkthrough «Get started with FastAPI».
|
||||
|
||||
@@ -50,9 +50,9 @@ Hello Wade Wilson
|
||||
|
||||
////
|
||||
|
||||
## Чтение переменных окружения в python { #read-env-vars-in-python }
|
||||
## Чтение переменных окружения в Python { #read-env-vars-in-python }
|
||||
|
||||
Так же существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**.
|
||||
Также существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**.
|
||||
|
||||
Например, у вас есть файл `main.py`:
|
||||
|
||||
@@ -67,7 +67,7 @@ print(f"Hello {name} from Python")
|
||||
|
||||
Второй аргумент [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) - это возвращаемое по умолчанию значение.
|
||||
|
||||
Если значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `«World»` в качестве значения по умолчанию.
|
||||
Если значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `"World"` в качестве значения по умолчанию.
|
||||
|
||||
///
|
||||
|
||||
@@ -157,13 +157,13 @@ Hello World from Python
|
||||
|
||||
///
|
||||
|
||||
## Типизация и Валидация { #types-and-validation }
|
||||
## Типы и валидация { #types-and-validation }
|
||||
|
||||
Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS).
|
||||
|
||||
Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая валидация должны быть выполнены в коде.
|
||||
|
||||
Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md).
|
||||
Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенном руководстве пользователя - Настройки и переменные окружения](./advanced/settings.md).
|
||||
|
||||
## Переменная окружения `PATH` { #path-environment-variable }
|
||||
|
||||
@@ -285,14 +285,14 @@ $ C:\opt\custompython\bin\python
|
||||
|
||||
////
|
||||
|
||||
Эта информация будет полезна при изучении [Виртуальных окружений](virtual-environments.md).
|
||||
Эта информация будет полезна при изучении [виртуальных окружений](virtual-environments.md).
|
||||
|
||||
## Вывод { #conclusion }
|
||||
|
||||
Благодаря этому вы должны иметь базовое представление о том, что такое **переменные окружения** и как использовать их в Python.
|
||||
|
||||
Подробнее о них вы также можете прочитать в [статье о переменных окружения на википедии](https://en.wikipedia.org/wiki/Environment_variable).
|
||||
Подробнее о них вы также можете прочитать в [статье о переменных окружения на Википедии](https://en.wikipedia.org/wiki/Environment_variable).
|
||||
|
||||
Во многих случаях не всегда очевидно, как переменные окружения могут быть полезны и применимы. Но они постоянно появляются в различных сценариях разработки, поэтому знать о них полезно.
|
||||
|
||||
Например, эта информация понадобится вам в следующем разделе, посвященном [Виртуальным окружениям](virtual-environments.md).
|
||||
Например, эта информация понадобится вам в следующем разделе, посвященном [виртуальным окружениям](virtual-environments.md).
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), с интерактивным исследованием, вызовом и тестированием вашего API прямо из браузера.
|
||||
|
||||

|
||||

|
||||
|
||||
* Альтернативная документация API в [**ReDoc**](https://github.com/Rebilly/ReDoc).
|
||||
|
||||
@@ -36,7 +36,7 @@ from datetime import date
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Объявляем параметр как `str`
|
||||
# Объявляем переменную как `str`
|
||||
# и получаем поддержку редактора кода внутри функции
|
||||
def main(user_id: str):
|
||||
return user_id
|
||||
@@ -71,9 +71,9 @@ my_second_user: User = User(**second_user_data)
|
||||
|
||||
///
|
||||
|
||||
### Поддержка редакторов { #editor-support }
|
||||
### Поддержка редакторов кода { #editor-support }
|
||||
|
||||
Весь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода.
|
||||
Весь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов кода еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода.
|
||||
|
||||
В опросах Python‑разработчиков видно, [что одной из самых часто используемых функций является «автозавершение»](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).
|
||||
|
||||
@@ -81,15 +81,15 @@ my_second_user: User = User(**second_user_data)
|
||||
|
||||
Вам редко нужно будет возвращаться к документации.
|
||||
|
||||
Вот как ваш редактор может вам помочь:
|
||||
Вот как ваш редактор кода может вам помочь:
|
||||
|
||||
* в [Visual Studio Code](https://code.visualstudio.com/):
|
||||
|
||||

|
||||

|
||||
|
||||
* в [PyCharm](https://www.jetbrains.com/pycharm/):
|
||||
|
||||

|
||||

|
||||
|
||||
Вы будете получать автозавершение кода даже там, где вы считали это невозможным раньше. Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе.
|
||||
|
||||
@@ -151,11 +151,11 @@ FastAPI включает в себя чрезвычайно простую в и
|
||||
|
||||
Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать «плагин» для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*.
|
||||
|
||||
### Проверен { #tested }
|
||||
### Протестирован { #tested }
|
||||
|
||||
* 100% <dfn title="Количество автоматически проверяемого кода">покрытие тестами</dfn>.
|
||||
* 100% <dfn title="Количество автоматически протестированного кода">покрытие тестами</dfn>.
|
||||
* 100% <dfn title="Аннотации типов Python, благодаря которым ваш редактор кода и внешние инструменты могут обеспечить вам лучшую поддержку">аннотирование типов</dfn> в кодовой базе.
|
||||
* Используется в продакшн‑приложениях.
|
||||
* Используется в приложениях в продакшн.
|
||||
|
||||
## Возможности Starlette { #starlette-features }
|
||||
|
||||
@@ -190,7 +190,7 @@ FastAPI включает в себя чрезвычайно простую в и
|
||||
* **Никакой нервотрёпки**:
|
||||
* Не нужно изучать новые схемы в микроязыках.
|
||||
* Если вы знаете типы в Python, вы знаете, как использовать Pydantic.
|
||||
* Прекрасно сочетается с вашим **<abbr title="Integrated Development Environment - Интегрированная среда разработки: похоже на редактор кода">IDE</abbr>/<dfn title="Программа, которая проверяет код на ошибки">линтер</dfn>/мозгом**:
|
||||
* Прекрасно сочетается с вашим **<abbr title="Integrated Development Environment - Интегрированная среда разработки: похожая на редактор кода">IDE</abbr>/<dfn title="Программа, которая проверяет код на ошибки">линтер</dfn>/мозгом**:
|
||||
* Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными.
|
||||
* Валидация **сложных структур**:
|
||||
* Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing`.
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
## Подписаться на автора { #follow-the-author }
|
||||
|
||||
Вы можете подписаться на [меня (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com) в нескольких местах, чтобы узнавать новости о FastAPI и друзьях:
|
||||
Вы можете подписаться на [меня (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), автора, в нескольких местах, чтобы узнавать новости о FastAPI и друзьях:
|
||||
|
||||
* [@tiangolo в **GitHub**](https://github.com/tiangolo).
|
||||
* [@tiangolo в **X (Twitter)**](https://x.com/tiangolo)
|
||||
|
||||
@@ -26,7 +26,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы
|
||||
|
||||
## Изменить тему { #change-the-theme }
|
||||
|
||||
Аналогично вы можете задать тему подсветки синтаксиса с ключом "syntaxHighlight.theme" (обратите внимание, что посередине стоит точка):
|
||||
Аналогично вы можете задать тему подсветки синтаксиса с ключом `"syntaxHighlight.theme"` (обратите внимание, что посередине стоит точка):
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
|
||||
Некоторые сценарии:
|
||||
|
||||
* Преобразование тел запросов, не в формате JSON, в JSON (например, [`msgpack`](https://msgpack.org/index.html)).
|
||||
* Преобразование тел запросов не в формате JSON в JSON (например, [`msgpack`](https://msgpack.org/index.html)).
|
||||
* Распаковка тел запросов, сжатых с помощью gzip.
|
||||
* Автоматическое логирование всех тел запросов.
|
||||
|
||||
## Обработка пользовательского кодирования тела запроса { #handling-custom-request-body-encodings }
|
||||
|
||||
Посмотрим как использовать пользовательский подкласс `Request` для распаковки gzip-запросов.
|
||||
Посмотрим, как использовать пользовательский подкласс `Request` для распаковки gzip-запросов.
|
||||
|
||||
И подкласс `APIRoute`, чтобы использовать этот пользовательский класс запроса.
|
||||
|
||||
@@ -38,9 +38,9 @@
|
||||
|
||||
Сначала создадим класс `GzipRequest`, который переопределит метод `Request.body()` и распакует тело запроса при наличии соответствующего HTTP-заголовка.
|
||||
|
||||
Если в заголовке нет `gzip`, он не будет пытаться распаковывать тело.
|
||||
Если в HTTP-заголовке нет `gzip`, он не будет пытаться распаковывать тело.
|
||||
|
||||
Таким образом, один и тот же класс маршрута сможет обрабатывать как gzip-сжатые, так и несжатые запросы.
|
||||
Таким образом, один и тот же класс маршрута сможет обрабатывать как gzip-сжатые, так и несжатые HTTP-запросы.
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
Тем же подходом можно воспользоваться, чтобы получить доступ к телу запроса в обработчике исключений.
|
||||
|
||||
Нужно лишь обработать запрос внутри блока `try`/`except`:
|
||||
Нужно лишь обработать HTTP-запрос внутри блока `try`/`except`:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
|
||||
|
||||
@@ -104,6 +104,6 @@
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
|
||||
|
||||
В этом примере *операции пути*, объявленные в `router`, будут использовать пользовательский класс `TimedRoute` и получат дополнительный HTTP-заголовок `X-Response-Time` в ответе с временем, затраченным на формирование ответа:
|
||||
В этом примере *операции пути*, объявленные в `router`, будут использовать пользовательский класс `TimedRoute` и получат дополнительный HTTP-заголовок `X-Response-Time` в HTTP-ответе с временем, затраченным на формирование HTTP-ответа:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# GraphQL { #graphql }
|
||||
|
||||
|
||||
Так как **FastAPI** основан на стандарте **ASGI**, очень легко интегрировать любую библиотеку **GraphQL**, также совместимую с ASGI.
|
||||
|
||||
Вы можете комбинировать обычные *операции пути* FastAPI с GraphQL в одном приложении.
|
||||
|
||||
@@ -8,6 +8,8 @@ FastAPI версии 0.119.0 добавил частичную поддержк
|
||||
|
||||
FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать `pydantic.v1`.
|
||||
|
||||
FastAPI 0.128.0 также убрал поддержку `pydantic.v1`, так что последние версии FastAPI требуют Pydantic v2.
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
|
||||
@@ -54,6 +56,16 @@ Pydantic v2 включает всё из Pydantic v1 как подмодуль `
|
||||
|
||||
### Поддержка FastAPI для Pydantic v1 внутри v2 { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Эта поддержка FastAPI для моделей `pydantic.v1` была добавлена в **FastAPI 0.119.0** и удалена в **FastAPI 0.128.0**. Она задумывалась как временная помощь при миграции на Pydantic v2.
|
||||
|
||||
В текущих версиях FastAPI использование модели `pydantic.v1` в вашем приложении вызовет ошибку.
|
||||
|
||||
Остальная часть этого раздела описывает временную поддержку, доступную только в этих старых версиях.
|
||||
|
||||
///
|
||||
|
||||
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 изнутри Pydantic v2, чтобы упростить миграцию на v2.
|
||||
|
||||
Таким образом, вы можете обновить Pydantic до последней версии 2 и сменить импорты на подмодуль `pydantic.v1` — во многих случаях всё просто заработает.
|
||||
@@ -122,6 +134,12 @@ graph TB
|
||||
|
||||
### Мигрируйте по шагам { #migrate-in-steps }
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Постепенная миграция с использованием моделей Pydantic v1 и v2 в одном приложении, описанная ниже, работает только в **FastAPI 0.119.0 до 0.127.x**. Она была удалена в **FastAPI 0.128.0**, последние версии требуют модели **Pydantic v2**.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Сначала попробуйте `bump-pydantic`: если тесты проходят и всё работает, вы справились одной командой. ✨
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Разделять схемы OpenAPI для входа и выхода или нет { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
При использовании **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
|
||||
С момента выхода **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
|
||||
|
||||
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON-схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ FastAPI — это современный, быстрый (высокопрои
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
### Ключевой-спонсор { #keystone-sponsor }
|
||||
### Ключевой спонсор { #keystone-sponsor }
|
||||
|
||||
<div class="fastapi-sponsors fastapi-sponsors--keystone">
|
||||
{% for sponsor in sponsors.keystone -%}
|
||||
@@ -161,7 +161,7 @@ FastAPI — это современный, быстрый (высокопрои
|
||||
|
||||
В конце 2025 года вышел [мини-документальный фильм о FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE), вы можете посмотреть его онлайн:
|
||||
|
||||
<a class="fastapi-feature-banner" href="https://www.youtube.com/watch?v=mpR8ngthqiE"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
<a class="fastapi-feature-banner" href="https://www.youtube.com/watch?v=mpR8ngthqiE"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="Мини-документальный фильм о FastAPI"></a>
|
||||
|
||||
## **Typer**, FastAPI для CLI { #typer-the-fastapi-of-clis }
|
||||
|
||||
@@ -364,11 +364,11 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
* Нажмите кнопку «Try it out», это позволит вам заполнить параметры и напрямую взаимодействовать с API:
|
||||
|
||||

|
||||

|
||||
|
||||
* Затем нажмите кнопку «Execute», интерфейс свяжется с вашим API, отправит параметры, получит результаты и отобразит их на экране:
|
||||
|
||||

|
||||

|
||||
|
||||
### Обновление альтернативной документации API { #alternative-api-docs-upgrade }
|
||||
|
||||
@@ -471,7 +471,7 @@ item: Item
|
||||
|
||||
...и посмотрите, как ваш редактор кода будет автоматически дополнять атрибуты и знать их типы:
|
||||
|
||||

|
||||

|
||||
|
||||
Более полный пример с дополнительными возможностями см. в <a href="https://fastapi.tiangolo.com/ru/tutorial/">Учебник - Руководство пользователя</a>.
|
||||
|
||||
@@ -524,7 +524,7 @@ FastAPI Cloud — основной спонсор и источник финан
|
||||
|
||||
#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI — это open source и стандартизированный фреймворк. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.
|
||||
FastAPI — это проект с открытым исходным кодом, основанный на стандартах. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.
|
||||
|
||||
Следуйте руководствам вашего облачного провайдера по развертыванию приложений FastAPI. 🤓
|
||||
|
||||
@@ -544,7 +544,7 @@ FastAPI зависит от Pydantic и Starlette.
|
||||
|
||||
Используется Pydantic:
|
||||
|
||||
* [`email-validator`](https://github.com/JoshData/python-email-validator) — для проверки адресов электронной почты.
|
||||
* [`email-validator`](https://github.com/JoshData/python-email-validator) — для валидации адресов электронной почты.
|
||||
|
||||
Используется Starlette:
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
- 🦇 Поддержка тёмной темы.
|
||||
- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшн.
|
||||
- 🔒 Безопасное хэширование паролей по умолчанию.
|
||||
- 🔑 Аутентификация по JWT‑токенам.
|
||||
- 🔑 Аутентификация JWT (JSON Web Token).
|
||||
- 📫 Восстановление пароля по электронной почте.
|
||||
- ✅ Тесты с [Pytest](https://pytest.org).
|
||||
- 📞 [Traefik](https://traefik.io) в роли обратного прокси / балансировщика нагрузки.
|
||||
- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд‑прокси Traefik для автоматического получения сертификатов HTTPS.
|
||||
- 🏭 CI (continuous integration) и CD (continuous deployment) на основе GitHub Actions.
|
||||
- 🏭 CI (непрерывная интеграция) и CD (непрерывное развертывание) на основе GitHub Actions.
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# Введение в типы Python { #python-types-intro }
|
||||
|
||||
Python поддерживает необязательные «подсказки типов» (их также называют «аннотациями типов»).
|
||||
Python поддерживает необязательные «аннотации типов» (также называемые «подсказками типов»).
|
||||
|
||||
Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять <dfn title="например: str, int, float, bool">тип</dfn> переменной.
|
||||
Эти **«аннотации типов»**, или просто аннотации, — это специальный синтаксис, позволяющий объявлять <dfn title="например: str, int, float, bool">тип</dfn> переменной.
|
||||
|
||||
Объявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать.
|
||||
|
||||
Это всего лишь **краткое руководство / напоминание** о подсказках типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.
|
||||
Это всего лишь **краткое руководство / напоминание** об аннотациях типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.
|
||||
|
||||
**FastAPI** целиком основан на этих подсказках типов — они дают ему множество преимуществ и выгод.
|
||||
**FastAPI** целиком основан на этих аннотациях типов — они дают ему множество преимуществ и выгод.
|
||||
|
||||
Но даже если вы никогда не используете **FastAPI**, вам будет полезно немного узнать о них.
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
Если вы являетесь экспертом в Python и уже знаете всё о подсказках типов, переходите к следующей главе.
|
||||
Если вы являетесь экспертом в Python и уже знаете всё об аннотациях типов, переходите к следующей главе.
|
||||
|
||||
///
|
||||
|
||||
@@ -76,7 +76,7 @@ John Doe
|
||||
|
||||
Вот и всё.
|
||||
|
||||
Это и есть «подсказки типов»:
|
||||
Это и есть «аннотации типов»:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
|
||||
|
||||
@@ -90,9 +90,9 @@ John Doe
|
||||
|
||||
Здесь мы используем двоеточия (`:`), а не знак равенства (`=`).
|
||||
|
||||
И добавление подсказок типов обычно не меняет поведение программы по сравнению с вариантом без них.
|
||||
И добавление аннотаций типов обычно не меняет поведение программы по сравнению с вариантом без них.
|
||||
|
||||
Но теперь представьте, что вы снова посередине написания этой функции, только уже с подсказками типов.
|
||||
Но теперь представьте, что вы снова посередине написания этой функции, только уже с аннотациями типов.
|
||||
|
||||
В тот же момент вы пробуете вызвать автозавершение с помощью `Ctrl+Space` — и видите:
|
||||
|
||||
@@ -104,7 +104,7 @@ John Doe
|
||||
|
||||
## Больше мотивации { #more-motivation }
|
||||
|
||||
Посмотрите на эту функцию — у неё уже есть подсказки типов:
|
||||
Посмотрите на эту функцию — у неё уже есть аннотации типов:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
|
||||
|
||||
@@ -118,7 +118,7 @@ John Doe
|
||||
|
||||
## Объявление типов { #declaring-types }
|
||||
|
||||
Вы только что увидели основное место, где объявляют подсказки типов — параметры функции.
|
||||
Вы только что увидели основное место, где объявляют аннотации типов — параметры функции.
|
||||
|
||||
Это также основное место, где вы будете использовать их с **FastAPI**.
|
||||
|
||||
@@ -293,9 +293,9 @@ def some_function(data: Any):
|
||||
|
||||
Вы увидите намного больше всего этого на практике в [Учебник - Руководство пользователя](tutorial/index.md).
|
||||
|
||||
## Подсказки типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
|
||||
## Аннотации типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
|
||||
|
||||
В Python также есть возможность добавлять **дополнительные <dfn title="Данные о данных, в данном случае — информация о типе, например описание.">метаданные</dfn>** к подсказкам типов с помощью `Annotated`.
|
||||
В Python также есть возможность добавлять **дополнительные <dfn title="Данные о данных, в данном случае — информация о типе, например описание.">метаданные</dfn>** к аннотациям типов с помощью `Annotated`.
|
||||
|
||||
Вы можете импортировать `Annotated` из `typing`.
|
||||
|
||||
@@ -321,16 +321,16 @@ def some_function(data: Any):
|
||||
|
||||
## Аннотации типов в **FastAPI** { #type-hints-in-fastapi }
|
||||
|
||||
**FastAPI** использует эти подсказки типов для выполнения нескольких задач.
|
||||
**FastAPI** использует эти аннотации типов для выполнения нескольких задач.
|
||||
|
||||
С **FastAPI** вы объявляете параметры с подсказками типов и получаете:
|
||||
С **FastAPI** вы объявляете параметры с аннотациями типов и получаете:
|
||||
|
||||
* **Поддержку редактора кода**.
|
||||
* **Проверки типов**.
|
||||
|
||||
...и **FastAPI** использует эти же объявления для:
|
||||
|
||||
* **Определения требований**: из path-параметров пути запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.
|
||||
* **Определения требований**: из path-параметров HTTP-запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.
|
||||
* **Преобразования данных**: из HTTP-запроса к требуемому типу.
|
||||
* **Валидации данных**: приходящих с каждого HTTP-запроса:
|
||||
* Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные некорректны.
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
```
|
||||
|
||||
/// tip | Подсказка
|
||||
@@ -58,16 +58,16 @@ from app.routers import items
|
||||
|
||||
```bash
|
||||
.
|
||||
├── app # "app" пакет
|
||||
├── app # "app" — Python-пакет
|
||||
│ ├── __init__.py # этот файл превращает "app" в "Python-пакет"
|
||||
│ ├── main.py # модуль "main", напр.: import app.main
|
||||
│ ├── dependencies.py # модуль "dependencies", напр.: import app.dependencies
|
||||
│ └── routers # подпакет "routers"
|
||||
│ │ ├── __init__.py # превращает "routers" в подпакет
|
||||
│ └── routers # "routers" — "Python-подпакет"
|
||||
│ │ ├── __init__.py # превращает "routers" в "Python-подпакет"
|
||||
│ │ ├── items.py # подмодуль "items", напр.: import app.routers.items
|
||||
│ │ └── users.py # подмодуль "users", напр.: import app.routers.users
|
||||
│ └── internal # подпакет "internal"
|
||||
│ ├── __init__.py # превращает "internal" в подпакет
|
||||
│ └── internal # "internal" — "Python-подпакет"
|
||||
│ ├── __init__.py # превращает "internal" в "Python-подпакет"
|
||||
│ └── admin.py # подмодуль "admin", напр.: import app.internal.admin
|
||||
```
|
||||
|
||||
@@ -121,7 +121,7 @@ from app.routers import items
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Для простоты мы воспользовались выдуманным заголовком.
|
||||
Для простоты мы воспользовались выдуманным HTTP-заголовком.
|
||||
|
||||
В реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md).
|
||||
|
||||
@@ -163,9 +163,9 @@ async def read_item(item_id: str):
|
||||
|
||||
В нашем случае префиксом является `/items`.
|
||||
|
||||
Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот маршрутизатор.
|
||||
Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот роутер.
|
||||
|
||||
И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в маршрутизаторе и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
|
||||
И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в роутере и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
@@ -185,7 +185,7 @@ async def read_item(item_id: str):
|
||||
* Все они будут включать предопределённые `responses`.
|
||||
* Все эти *операции пути* будут иметь список `dependencies`, вычисляемых/выполняемых перед ними.
|
||||
* Если вы также объявите зависимости в конкретной *операции пути*, **они тоже будут выполнены**.
|
||||
* Сначала выполняются зависимости маршрутизатора, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md), и затем обычные параметрические зависимости.
|
||||
* Сначала выполняются зависимости роутера, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md), и затем обычные параметрические зависимости.
|
||||
* Вы также можете добавить [`Security`-зависимости с `scopes`](../advanced/security/oauth2-scopes.md).
|
||||
|
||||
/// tip | Подсказка
|
||||
@@ -263,7 +263,7 @@ from ...dependencies import get_token_header
|
||||
|
||||
то это бы означало:
|
||||
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) расположен в (каталоге `app/routers/`)...
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
|
||||
* перейти в родительский пакет (каталог `app/`)...
|
||||
* затем перейти в родительский пакет этого пакета (родительского пакета нет, `app` — верхний уровень 😱)...
|
||||
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
@@ -285,7 +285,7 @@ from ...dependencies import get_token_header
|
||||
|
||||
Эта последняя операция пути будет иметь комбинацию тегов: `["items", "custom"]`.
|
||||
|
||||
И в документации у неё будут оба ответа: один для `404` и один для `403`.
|
||||
И в документации у неё будут оба HTTP-ответа: один для `404` и один для `403`.
|
||||
|
||||
///
|
||||
|
||||
@@ -325,7 +325,7 @@ from .routers import items, users
|
||||
|
||||
означает:
|
||||
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) расположен в (каталоге `app/`)...
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) (каталог `app/`)...
|
||||
* найти подпакет `routers` (каталог `app/routers/`)...
|
||||
* и импортировать из него подмодули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
|
||||
|
||||
@@ -392,19 +392,19 @@ from .routers.users import router
|
||||
|
||||
С помощью `app.include_router()` мы можем добавить каждый `APIRouter` в основное приложение `FastAPI`.
|
||||
|
||||
Он включит все маршруты этого маршрутизатора как часть приложения.
|
||||
Он включит все маршруты этого роутера как часть приложения.
|
||||
|
||||
/// note | Технические детали
|
||||
|
||||
FastAPI сохраняет исходный `APIRouter` и его `APIRoute` активными, когда маршрутизатор включается в основное приложение.
|
||||
FastAPI сохраняет исходный `APIRouter` и его `APIRoute` активными, когда роутер включается в основное приложение.
|
||||
|
||||
Это означает, что пользовательские подклассы `APIRouter` и `APIRoute` по-прежнему участвуют после подключения маршрутизатора.
|
||||
Это означает, что пользовательские подклассы `APIRouter` и `APIRoute` по-прежнему участвуют после подключения роутера.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
При подключении маршрутизаторов не нужно беспокоиться о производительности.
|
||||
При подключении роутеров не нужно беспокоиться о производительности.
|
||||
|
||||
Это сделано максимально лёгким и не добавляет накладных расходов на каждый запрос.
|
||||
|
||||
@@ -435,7 +435,7 @@ FastAPI сохраняет исходный `APIRouter` и его `APIRoute` а
|
||||
* Префикс `/admin`.
|
||||
* Тег `admin`.
|
||||
* Зависимость `get_token_header`.
|
||||
* Ответ `418`. 🍵
|
||||
* HTTP-ответ `418`. 🍵
|
||||
|
||||
Но это повлияет только на этот `APIRouter` в нашем приложении, а не на любой другой код, который его использует.
|
||||
|
||||
@@ -461,7 +461,7 @@ FastAPI сохраняет исходный `APIRouter` и его `APIRoute` а
|
||||
|
||||
Это потому, что мы хотим включить их *операции пути* в схему OpenAPI и пользовательские интерфейсы.
|
||||
|
||||
FastAPI сохраняет исходные маршрутизаторы и операции пути активными и комбинирует префиксы маршрутизаторов, зависимости, теги, ответы и другие метаданные при обработке запросов и генерации OpenAPI.
|
||||
FastAPI сохраняет исходные роутеры и операции пути активными и комбинирует префиксы роутеров, зависимости, теги, HTTP-ответы и другие метаданные при обработке HTTP-запросов и генерации OpenAPI.
|
||||
|
||||
///
|
||||
|
||||
@@ -516,9 +516,9 @@ $ fastapi dev
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## Подключение одного и того же маршрутизатора несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
## Подключение одного и того же роутера несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
Вы можете использовать `.include_router()` несколько раз с *одним и тем же* маршрутизатором, используя разные префиксы.
|
||||
Вы можете использовать `.include_router()` несколько раз с *одним и тем же* роутером, используя разные префиксы.
|
||||
|
||||
Это может быть полезно, например, чтобы предоставить доступ к одному и тому же API с разными префиксами, например `/api/v1` и `/api/latest`.
|
||||
|
||||
@@ -534,14 +534,14 @@ router.include_router(other_router)
|
||||
|
||||
Вы можете сделать это до или после подключения `router` к приложению `FastAPI`. FastAPI всё равно включит *операции пути* из `other_router` в маршрутизацию и OpenAPI.
|
||||
|
||||
То же относится к *операциям пути*, добавленным позже в маршрутизаторы. Они также будут видны через более раннее включение.
|
||||
То же относится к *операциям пути*, добавленным позже в роутеры. Они также будут видны через более раннее включение.
|
||||
|
||||
/// warning | Технические детали
|
||||
|
||||
Избегайте прямой мутации `router.routes` после включения маршрутизатора. FastAPI рассматривает включение маршрутизатора как «живое», поэтому исходный маршрутизатор и его маршруты остаются частью маршрутизации и генерации OpenAPI.
|
||||
Избегайте прямой мутации `router.routes` после включения роутера. FastAPI рассматривает включение роутера как «живое», поэтому исходный роутер и его маршруты остаются частью маршрутизации и генерации OpenAPI.
|
||||
|
||||
Используйте документированные API, такие как декораторы операций пути и `.include_router()`, чтобы добавлять маршруты и маршрутизаторы.
|
||||
Используйте документированные API, такие как декораторы операций пути и `.include_router()`, чтобы добавлять маршруты и роутеры.
|
||||
|
||||
Считайте `router.routes` низкоуровневым деревом маршрутов, которое может содержать определения маршрутов и включённые маршрутизаторы, и избегайте воспринимать его как плоский список итоговых операций пути.
|
||||
Считайте `router.routes` низкоуровневым деревом маршрутов, которое может содержать определения маршрутов и включённые роутеры, и избегайте воспринимать его как плоский список итоговых операций пути.
|
||||
|
||||
///
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
## Поля-списки с параметром типа { #list-fields-with-type-parameter }
|
||||
|
||||
В Python есть специальный способ объявлять списки с внутренними типами, или «параметрами типа»:
|
||||
Но в Python есть специальный способ объявлять списки с внутренними типами, или «параметрами типа»:
|
||||
|
||||
### Объявите `list` с параметром типа { #declare-a-list-with-a-type-parameter }
|
||||
|
||||
@@ -110,7 +110,7 @@ my_list: list[str]
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
|
||||
|
||||
Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д.) JSON-содержимое в следующем формате:
|
||||
Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д.) JSON-тело запроса в следующем формате:
|
||||
|
||||
```JSON hl_lines="11"
|
||||
{
|
||||
@@ -154,9 +154,9 @@ my_list: list[str]
|
||||
|
||||
///
|
||||
|
||||
## Тела с чистыми списками элементов { #bodies-of-pure-lists }
|
||||
## Тела запросов с чистыми списками элементов { #bodies-of-pure-lists }
|
||||
|
||||
Если верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic:
|
||||
Если верхний уровень значения JSON-тела запроса представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic:
|
||||
|
||||
```Python
|
||||
images: list[Image]
|
||||
@@ -212,7 +212,7 @@ images: list[Image]
|
||||
|
||||
С помощью **FastAPI** вы получаете максимальную гибкость, предоставляемую моделями Pydantic, сохраняя при этом простоту, краткость и элегантность вашего кода.
|
||||
|
||||
И дополнительно вы получаете:
|
||||
Но со всеми преимуществами:
|
||||
|
||||
* Поддержку редактора кода (автозавершение доступно везде!)
|
||||
* Преобразование данных (также известно как парсинг / сериализация)
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
* Считает тело запроса как JSON.
|
||||
* Приведёт данные к соответствующим типам (если потребуется).
|
||||
* Проведёт валидацию данных.
|
||||
* Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно и что было некорректно.
|
||||
* Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно and что было некорректно.
|
||||
* Передаст полученные данные в параметр `item`.
|
||||
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т.п.) для всех атрибутов и их типов.
|
||||
* Сгенерирует определения [JSON Schema](https://json-schema.org) для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Отладка { #debugging }
|
||||
|
||||
Вы можете подключить отладчик в своем редакторе, например, в Visual Studio Code или PyCharm.
|
||||
Вы можете подключить отладчик в своем редакторе кода, например, в Visual Studio Code или PyCharm.
|
||||
|
||||
## Вызов `uvicorn` { #call-uvicorn }
|
||||
|
||||
В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:
|
||||
В вашем FastAPI приложении, импортируйте и запустите `uvicorn` напрямую:
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
|
||||
|
||||
@@ -62,7 +62,7 @@ from myapp import app
|
||||
# Еще немного кода
|
||||
```
|
||||
|
||||
то автоматическая создаваемая внутри файла `myapp.py` переменная `__name__` будет иметь значение отличающееся от `"__main__"`.
|
||||
то автоматически создаваемая внутри файла `myapp.py` переменная `__name__` будет иметь значение, отличающееся от `"__main__"`.
|
||||
|
||||
Следовательно, строка:
|
||||
|
||||
@@ -80,7 +80,7 @@ from myapp import app
|
||||
|
||||
## Запуск вашего кода с помощью отладчика { #run-your-code-with-your-debugger }
|
||||
|
||||
Так как вы запускаете сервер Uvicorn непосредственно из вашего кода, вы можете вызвать Python программу (ваше FastAPI приложение) напрямую из отладчика.
|
||||
Так как вы запускаете сервер Uvicorn непосредственно из вашего кода, вы можете запустить Python программу (ваше FastAPI приложение) напрямую из отладчика.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ FastAPI поддерживает зависимости, которые выпо
|
||||
|
||||
### Всегда делайте `raise` в зависимостях с `yield` и `except` { #always-raise-in-dependencies-with-yield-and-except }
|
||||
|
||||
Если вы ловите исключение в зависимости с `yield`, то, если вы не вызываете другой `HTTPException` или что-то подобное, вам следует повторно вызвать исходное исключение.
|
||||
Если вы ловите исключение в зависимости с `yield`, то, если вы не вызываете другой `HTTPException` или что-то подобное, **вам следует повторно вызвать исходное исключение**.
|
||||
|
||||
Вы можете повторно вызвать то же самое исключение с помощью `raise`:
|
||||
|
||||
@@ -234,6 +234,7 @@ participant operation as Функция-обработчик пути
|
||||
Зависимости с `yield` со временем эволюционировали, чтобы покрыть разные сценарии и исправить некоторые проблемы.
|
||||
|
||||
Если вы хотите посмотреть, что менялось в разных версиях FastAPI, вы можете прочитать об этом подробнее в продвинутом руководстве: [Продвинутые зависимости — зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).
|
||||
|
||||
## Контекстные менеджеры { #context-managers }
|
||||
|
||||
### Что такое «контекстные менеджеры» { #what-are-context-managers }
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
При этом у вас останутся те же возможности, что и до сих пор:
|
||||
|
||||
* Отличная поддержка редактора кода.
|
||||
* Преобразование данных из входящих запросов.
|
||||
* Преобразование данных из входящих HTTP-запросов.
|
||||
* Преобразование данных для ответа.
|
||||
* Валидация данных.
|
||||
* Автоматическая аннотация и документация.
|
||||
@@ -23,32 +23,32 @@
|
||||
|
||||
* `UUID`:
|
||||
* Стандартный "Универсальный уникальный идентификатор", используемый в качестве идентификатора во многих базах данных и системах.
|
||||
* В запросах и ответах будет представлен как `str`.
|
||||
* В HTTP-запросах и HTTP-ответах будет представлен как `str`.
|
||||
* `datetime.datetime`:
|
||||
* Встроенный в Python `datetime.datetime`.
|
||||
* В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15T15:53:00+05:00`.
|
||||
* В HTTP-запросах и HTTP-ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15T15:53:00+05:00`.
|
||||
* `datetime.date`:
|
||||
* Встроенный в Python `datetime.date`.
|
||||
* В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15`.
|
||||
* В HTTP-запросах и HTTP-ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15`.
|
||||
* `datetime.time`:
|
||||
* Встроенный в Python `datetime.time`.
|
||||
* В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `14:23:55.003`.
|
||||
* В HTTP-запросах и HTTP-ответах будет представлен как `str` в формате ISO 8601, например: `14:23:55.003`.
|
||||
* `datetime.timedelta`:
|
||||
* Встроенный в Python `datetime.timedelta`.
|
||||
* В запросах и ответах будет представлен в виде общего количества секунд типа `float`.
|
||||
* В HTTP-запросах и HTTP-ответах будет представлен в виде общего количества секунд типа `float`.
|
||||
* Pydantic также позволяет представить его как "Кодировку разницы во времени ISO 8601", [см. документацию для получения дополнительной информации](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
|
||||
* `frozenset`:
|
||||
* В запросах и ответах обрабатывается так же, как и `set`:
|
||||
* В запросах будет прочитан список, исключены дубликаты и преобразован в `set`.
|
||||
* В ответах `set` будет преобразован в `list`.
|
||||
* В HTTP-запросах и HTTP-ответах обрабатывается так же, как и `set`:
|
||||
* В HTTP-запросах будет прочитан список, исключены дубликаты и преобразован в `set`.
|
||||
* В HTTP-ответах `set` будет преобразован в `list`.
|
||||
* В сгенерированной схеме будет указано, что значения `set` уникальны (с помощью JSON-схемы `uniqueItems`).
|
||||
* `bytes`:
|
||||
* Встроенный в Python `bytes`.
|
||||
* В запросах и ответах будет рассматриваться как `str`.
|
||||
* В сгенерированной схеме будет указано, что это `str` в формате `binary`.
|
||||
* В HTTP-запросах и HTTP-ответах будет рассматриваться как `str`.
|
||||
* В сгенерированной схеме будет указано, что это `str` в "формате" `binary`.
|
||||
* `Decimal`:
|
||||
* Встроенный в Python `Decimal`.
|
||||
* В запросах и ответах обрабатывается так же, как и `float`.
|
||||
* В HTTP-запросах и HTTP-ответах обрабатывается так же, как и `float`.
|
||||
* Вы можете проверить все допустимые типы данных Pydantic здесь: [Типы данных Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).
|
||||
|
||||
## Пример { #example }
|
||||
|
||||
@@ -208,4 +208,4 @@ some_variable: PlaneItem | CarItem
|
||||
|
||||
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждого случая.
|
||||
|
||||
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояние, включающее `password`, `password_hash` и отсутствие пароля.
|
||||
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". **Пользователь** — пример такой "сущности", с состояниями, которые включают `password`, `password_hash` или отсутствие пароля.
|
||||
|
||||
@@ -244,9 +244,9 @@ CLI автоматически определит ваше приложение
|
||||
|
||||
Это будет основная точка взаимодействия для создания всего вашего API.
|
||||
|
||||
### Шаг 3: создайте *операцию пути (path operation)* { #step-3-create-a-path-operation }
|
||||
### Шаг 3: создайте *операцию пути* { #step-3-create-a-path-operation }
|
||||
|
||||
#### Путь (path) { #path }
|
||||
#### Путь { #path }
|
||||
|
||||
Здесь «путь» — это последняя часть URL, начиная с первого символа `/`.
|
||||
|
||||
@@ -270,7 +270,7 @@ https://example.com/items/foo
|
||||
|
||||
При создании API «путь» — это основной способ разделения «задач» и «ресурсов».
|
||||
|
||||
#### Операция (operation) { #operation }
|
||||
#### Операция { #operation }
|
||||
|
||||
«Операция» здесь — это один из HTTP-«методов».
|
||||
|
||||
@@ -303,16 +303,16 @@ https://example.com/items/foo
|
||||
|
||||
Таким образом, в OpenAPI каждый HTTP-метод называется «операцией».
|
||||
|
||||
Мы тоже будем называть их «операциями».
|
||||
Мы тоже будем называть их «**операциями**».
|
||||
|
||||
#### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator }
|
||||
#### Определите *декоратор операции пути* { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
|
||||
|
||||
`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих:
|
||||
`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку HTTP-запросов, поступающих:
|
||||
|
||||
* по пути `/`
|
||||
* с использованием <dfn title="метод HTTP GET"><code>get</code> операции</dfn>
|
||||
* с использованием <dfn title="HTTP-метод GET">операции <code>get</code></dfn>
|
||||
|
||||
/// note | Информация о `@decorator`
|
||||
|
||||
@@ -353,9 +353,9 @@ https://example.com/items/foo
|
||||
|
||||
///
|
||||
|
||||
### Шаг 4: определите **функцию операции пути** { #step-4-define-the-path-operation-function }
|
||||
### Шаг 4: определите **функцию-обработчик пути** { #step-4-define-the-path-operation-function }
|
||||
|
||||
Вот наша «функция операции пути»:
|
||||
Вот наша «**функция-обработчик пути**»:
|
||||
|
||||
* **путь**: `/`.
|
||||
* **операция**: `get`.
|
||||
@@ -365,7 +365,7 @@ https://example.com/items/foo
|
||||
|
||||
Это функция на Python.
|
||||
|
||||
**FastAPI** будет вызывать её каждый раз, когда получает запрос к URL «`/`» с операцией `GET`.
|
||||
**FastAPI** будет вызывать её каждый раз, когда получает HTTP-запрос к URL «`/`» с операцией `GET`.
|
||||
|
||||
В данном случае это асинхронная (`async`) функция.
|
||||
|
||||
@@ -403,7 +403,7 @@ https://example.com/items/foo
|
||||
|
||||
Он переносит тот же **опыт разработчика** при создании приложений с FastAPI на их **развертывание** в облаке. 🎉
|
||||
|
||||
FastAPI Cloud — основной спонсор и источник финансирования для open-source проектов «FastAPI и друзья». ✨
|
||||
FastAPI Cloud — основной спонсор и источник финансирования для open-source проектов *FastAPI и друзья*. ✨
|
||||
|
||||
#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }
|
||||
|
||||
@@ -416,6 +416,6 @@ FastAPI — open-source и основан на стандартах. Вы мож
|
||||
* Импортируйте `FastAPI`.
|
||||
* Создайте экземпляр `app`.
|
||||
* Напишите **декоратор операции пути**, например `@app.get("/")`.
|
||||
* Определите **функцию операции пути**; например, `def root(): ...`.
|
||||
* Определите **функцию-обработчик пути**; например, `def root(): ...`.
|
||||
* Запустите сервер разработки командой `fastapi dev`.
|
||||
* При желании разверните приложение командой `fastapi deploy`.
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
|
||||
В таких случаях обычно возвращают **HTTP статус-код** в диапазоне **400** (от 400 до 499).
|
||||
|
||||
Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно.
|
||||
Они похожи на двухсотые HTTP статус-коды (от 200 до 299). Эти статус-коды "200" означают, что в HTTP-запросе в каком-то смысле был "успех".
|
||||
|
||||
Четырёхсотые статус-коды означают, что ошибка произошла по вине клиента.
|
||||
HTTP статус-коды в диапазоне 400 означают, что произошла ошибка со стороны клиента.
|
||||
|
||||
Помните ли ошибки **"404 Not Found "** (и шутки) ?
|
||||
Помните все эти ошибки **"404 Not Found"** (и шутки)?
|
||||
|
||||
## Использование `HTTPException` { #use-httpexception }
|
||||
|
||||
@@ -31,19 +31,19 @@
|
||||
|
||||
`HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API.
|
||||
|
||||
Поскольку это исключение Python, то его не `возвращают`, а `вызывают`.
|
||||
Поскольку это исключение Python, то его не `return`, а `raise`.
|
||||
|
||||
Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы поднимаете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту.
|
||||
Это также означает, что если вы находитесь внутри вспомогательной функции, которая вызывается внутри вашей *функции-обработчика пути*, и вы вызываете `HTTPException` изнутри этой вспомогательной функции, то остальной код в *функции-обработчике пути* выполняться не будет, запрос сразу завершится, а HTTP-ошибка из `HTTPException` будет отправлена клиенту.
|
||||
|
||||
О том, насколько выгоднее `вызывать` исключение, чем `возвращать` значение, будет рассказано в разделе, посвященном зависимостям и безопасности.
|
||||
Преимущество вызова исключения перед возвратом значения станет более очевидным в разделе о зависимостях и безопасности.
|
||||
|
||||
В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
|
||||
В данном примере, когда клиент запрашивает элемент по несуществующему ID, вызовите исключение со статус-кодом `404`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
|
||||
|
||||
### Возвращаемый ответ { #the-resulting-response }
|
||||
|
||||
Если клиент запросит `http://example.com/items/foo` (`item_id` `"foo"`), то он получит статус-код 200 и ответ в формате JSON:
|
||||
Если клиент запросит `http://example.com/items/foo` (`item_id` `"foo"`), то он получит HTTP статус-код 200 и ответ в формате JSON:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -51,7 +51,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
Но если клиент запросит `http://example.com/items/bar` (несуществующий `item_id` `"bar"`), то он получит статус-код 404 (ошибка "не найдено") и JSON-ответ в виде:
|
||||
Но если клиент запросит `http://example.com/items/bar` (несуществующий `item_id` `"bar"`), то он получит HTTP статус-код 404 (ошибка "не найдено") и JSON-ответ в виде:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -69,13 +69,13 @@
|
||||
|
||||
///
|
||||
|
||||
## Добавление пользовательских заголовков { #add-custom-headers }
|
||||
## Добавление пользовательских HTTP-заголовков { #add-custom-headers }
|
||||
|
||||
В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
|
||||
В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к HTTP-ошибке. Например, для некоторых типов безопасности.
|
||||
|
||||
Скорее всего, вам не потребуется использовать его непосредственно в коде.
|
||||
Скорее всего, вам не потребуется использовать это непосредственно в коде.
|
||||
|
||||
Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки:
|
||||
Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские HTTP-заголовки:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
Вы можете добавить пользовательские обработчики исключений с помощью [тех же утилит обработки исключений из Starlette](https://www.starlette.dev/exceptions/).
|
||||
|
||||
Допустим, у вас есть пользовательское исключение `UnicornException`, которое вы (или используемая вами библиотека) можете `вызвать`.
|
||||
Допустим, у вас есть пользовательское исключение `UnicornException`, которое вы (или используемая вами библиотека) можете вызвать с помощью `raise`.
|
||||
|
||||
И вы хотите обрабатывать это исключение глобально с помощью FastAPI.
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
Но оно будет обработано `unicorn_exception_handler`.
|
||||
|
||||
Таким образом, вы получите чистую ошибку с кодом состояния HTTP `418` и содержимым JSON:
|
||||
Таким образом, вы получите чистую ошибку с HTTP статус-кодом `418` и содержимым JSON:
|
||||
|
||||
```JSON
|
||||
{"message": "Oops! yolo did something. There goes a rainbow..."}
|
||||
@@ -113,17 +113,17 @@
|
||||
|
||||
**FastAPI** имеет некоторые обработчики исключений по умолчанию.
|
||||
|
||||
Эти обработчики отвечают за возврат стандартных JSON-ответов при `вызове` `HTTPException` и при наличии в запросе недопустимых данных.
|
||||
Эти обработчики отвечают за возврат стандартных JSON-ответов при вызове `HTTPException` с помощью `raise` и при наличии в HTTP-запросе недопустимых данных.
|
||||
|
||||
Вы можете переопределить эти обработчики исключений на свои собственные.
|
||||
|
||||
### Переопределение обработчика исключений проверки запроса { #override-request-validation-exceptions }
|
||||
### Переопределение исключений валидации запроса { #override-request-validation-exceptions }
|
||||
|
||||
Когда запрос содержит недопустимые данные, **FastAPI** внутренне вызывает ошибку `RequestValidationError`.
|
||||
Когда HTTP-запрос содержит недопустимые данные, **FastAPI** внутренне вызывает `RequestValidationError`.
|
||||
|
||||
А также включает в себя обработчик исключений по умолчанию.
|
||||
А также включает в себя обработчик исключений по умолчанию для него.
|
||||
|
||||
Чтобы переопределить его, импортируйте `RequestValidationError` и используйте его с `@app.exception_handler(RequestValidationError)` для создания обработчика исключений.
|
||||
Чтобы переопределить его, импортируйте `RequestValidationError` и используйте его с `@app.exception_handler(RequestValidationError)`, чтобы декорировать обработчик исключений.
|
||||
|
||||
Обработчик исключения получит объект `Request` и исключение.
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
вы получите текстовую версию:
|
||||
вы получите текстовую версию с:
|
||||
|
||||
```
|
||||
Validation errors:
|
||||
@@ -171,7 +171,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
|
||||
/// warning | Внимание
|
||||
|
||||
Имейте в виду, что `RequestValidationError` содержит информацию об имени файла и строке, где произошла ошибка валидации, чтобы вы могли при желании отобразить её в логах с релевантными данными.
|
||||
Имейте в виду, что `RequestValidationError` содержит информацию об имени файла и строке, где происходит ошибка валидации, чтобы вы могли при желании отобразить её в логах вместе с релевантной информацией.
|
||||
|
||||
Но это означает, что если вы просто преобразуете её в строку и вернёте эту информацию напрямую, вы можете допустить небольшую утечку информации о своей системе, поэтому здесь код извлекает и показывает каждую ошибку отдельно.
|
||||
|
||||
@@ -179,13 +179,13 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
|
||||
### Используйте тело `RequestValidationError` { #use-the-requestvalidationerror-body }
|
||||
|
||||
Ошибка `RequestValidationError` содержит полученное `тело` с недопустимыми данными.
|
||||
Ошибка `RequestValidationError` содержит `body` (тело запроса), которое она получила с недопустимыми данными.
|
||||
|
||||
Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д.
|
||||
Вы можете использовать его при разработке приложения для логирования тела запроса и его отладки, возврата пользователю и т.д.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
|
||||
|
||||
Теперь попробуйте отправить недействительный элемент, например:
|
||||
Теперь попробуйте отправить недопустимый элемент, например:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -194,7 +194,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
}
|
||||
```
|
||||
|
||||
Вы получите ответ о том, что данные недействительны, содержащий следующее тело:
|
||||
Вы получите ответ о том, что данные недопустимы, содержащий полученное тело запроса:
|
||||
|
||||
```JSON hl_lines="12-15"
|
||||
{
|
||||
@@ -215,7 +215,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
}
|
||||
```
|
||||
|
||||
#### `HTTPException` в FastAPI или в Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
#### `HTTPException` в FastAPI и `HTTPException` в Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
|
||||
**FastAPI** имеет собственный `HTTPException`.
|
||||
|
||||
@@ -227,9 +227,9 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
|
||||
Но когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette.
|
||||
|
||||
Таким образом, если какая-либо часть внутреннего кодa Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.
|
||||
Таким образом, если какая-либо часть внутреннего кода Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.
|
||||
|
||||
В данном примере, чтобы иметь возможность использовать оба `HTTPException` в одном коде, исключения Starlette переименованы в `StarletteHTTPException`:
|
||||
В данном примере, чтобы иметь возможность использовать оба `HTTPException` в одном коде, исключение Starlette переименовано в `StarletteHTTPException`:
|
||||
|
||||
```Python
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
@@ -241,4 +241,4 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
|
||||
|
||||
В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.
|
||||
В этом примере вы просто выводите ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Учебник - Руководство пользователя { #tutorial-user-guide }
|
||||
|
||||
|
||||
В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций.
|
||||
|
||||
Каждый раздел постепенно основывается на предыдущих, но структура разделяет темы, так что вы можете сразу перейти к нужной теме для решения ваших конкретных задач по API.
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
| `title` | `str` | Заголовок API. |
|
||||
| `summary` | `str` | Краткое резюме API. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
|
||||
| `description` | `str` | Краткое описание API. Может быть использован Markdown. |
|
||||
| `version` | `string` | Версия API. Версия вашего собственного приложения, а не OpenAPI. К примеру `2.5.0`. |
|
||||
| `terms_of_service` | `str` | Ссылка к условиям пользования API. Если указано, то это должен быть URL-адрес. |
|
||||
| `contact` | `dict` | Контактная информация для открытого API. Может содержать несколько полей. <details><summary>поля <code>contact</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Идентификационное имя контактного лица/организации.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL указывающий на контактную информацию. ДОЛЖЕН быть в формате URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Email адрес контактного лица/организации. ДОЛЖЕН быть в формате email адреса.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | Информация о лицензии открытого API. Может содержать несколько полей. <details><summary>поля <code>license_info</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБЯЗАТЕЛЬНО</strong> (если установлен параметр <code>license_info</code>). Название лицензии, используемой для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Выражение лицензии [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> взаимоисключающее с полем <code>url</code>. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</td></tr></tbody></table></details> |
|
||||
| `version` | `str` | Версия API. Версия вашего собственного приложения, а не OpenAPI. К примеру `2.5.0`. |
|
||||
| `terms_of_service` | `str` | Ссылка на условия пользования API. Если указано, то это должен быть URL-адрес. |
|
||||
| `contact` | `dict` | Контактная информация для открытого API. Может содержать несколько полей. <details><summary>поля <code>contact</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Идентификационное имя контактного лица/организации.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на контактную информацию. ДОЛЖЕН быть в формате URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Email-адрес контактного лица/организации. ДОЛЖЕН быть в формате email-адреса.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | Информация о лицензии открытого API. Может содержать несколько полей. <details><summary>поля <code>license_info</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБЯЗАТЕЛЬНО</strong> (если установлен параметр <code>license_info</code>). Название лицензии, используемой для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Выражение лицензии [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> является взаимоисключающим с полем <code>url</code>. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</td></tr></tbody></table></details> |
|
||||
|
||||
Вы можете задать их следующим образом:
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
* `name` (**обязательно**): `str`-значение с тем же именем тега, которое вы используете в параметре `tags` в ваших *операциях пути* и `APIRouter`ах.
|
||||
* `description`: `str`-значение с кратким описанием для тега. Может содержать Markdown и будет отображаться в UI документации.
|
||||
* `externalDocs`: `dict`-значение описывающее внешнюю документацию. Включает в себя:
|
||||
* `externalDocs`: `dict`-значение, описывающее внешнюю документацию. Включает в себя:
|
||||
* `description`: `str`-значение с кратким описанием для внешней документации.
|
||||
* `url` (**обязательно**): `str`-значение с URL-адресом для внешней документации.
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Вам необязательно добавлять метаданные для всех используемых тегов
|
||||
Вам необязательно добавлять метаданные для всех используемых тегов.
|
||||
|
||||
///
|
||||
|
||||
@@ -94,11 +94,11 @@
|
||||
|
||||
## URL-адрес OpenAPI { #openapi-url }
|
||||
|
||||
По умолчанию схема OpenAPI отображена по адресу `/openapi.json`.
|
||||
По умолчанию схема OpenAPI отдаётся по адресу `/openapi.json`.
|
||||
|
||||
Но вы можете изменить это с помощью параметра `openapi_url`.
|
||||
|
||||
К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`:
|
||||
К примеру, чтобы задать её отдачу по адресу `/api/v1/openapi.json`:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
|
||||
|
||||
@@ -106,15 +106,15 @@
|
||||
|
||||
## URL-адреса документации { #docs-urls }
|
||||
|
||||
Вы можете изменить конфигурацию двух пользовательских интерфейсов документации, которые включены:
|
||||
Вы можете изменить конфигурацию двух включённых пользовательских интерфейсов документации:
|
||||
|
||||
* **Swagger UI**: отображаемый по адресу `/docs`.
|
||||
* **Swagger UI**: отдаётся по адресу `/docs`.
|
||||
* Вы можете задать его URL с помощью параметра `docs_url`.
|
||||
* Вы можете отключить это с помощью настройки `docs_url=None`.
|
||||
* **ReDoc**: отображаемый по адресу `/redoc`.
|
||||
* **ReDoc**: отдаётся по адресу `/redoc`.
|
||||
* Вы можете задать его URL с помощью параметра `redoc_url`.
|
||||
* Вы можете отключить это с помощью настройки `redoc_url=None`.
|
||||
|
||||
К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc:
|
||||
К примеру, чтобы настроить отдачу Swagger UI по адресу `/documentation` и отключить ReDoc:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Конфигурация операций пути { #path-operation-configuration }
|
||||
# Конфигурация операции пути { #path-operation-configuration }
|
||||
|
||||
Существует несколько параметров, которые вы можете передать вашему *декоратору операций пути* для его настройки.
|
||||
Существует несколько параметров, которые вы можете передать вашему *декоратору операции пути* для его настройки.
|
||||
|
||||
/// warning | Внимание
|
||||
|
||||
Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику пути*.
|
||||
Помните, что эти параметры передаются непосредственно *декоратору операции пути*, а не вашей *функции-обработчику пути*.
|
||||
|
||||
///
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
## Теги { #tags }
|
||||
|
||||
Вы можете добавлять теги к вашим *операциям пути*, добавив параметр `tags` с `list` заполненным `str`-значениями (обычно в нём только одна строка):
|
||||
Вы можете добавлять теги к вашей *операции пути*, передав параметр `tags` с `list` из `str` (обычно в нём только одна строка):
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
|
||||
|
||||
Они будут добавлены в схему OpenAPI и будут использованы в автоматической документации интерфейса:
|
||||
Они будут добавлены в схему OpenAPI и будут использованы автоматическими интерфейсами документации:
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image01.png">
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
## Описание из строк документации { #description-from-docstring }
|
||||
|
||||
Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в <dfn title="многострочная строка, первое выражение внутри функции (не присвоенное какой-либо переменной), используемая для документации">строке документации</dfn> функции, и **FastAPI** прочитает её оттуда.
|
||||
Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в <dfn title="многострочная строка, первое выражение внутри функции (не присвоенное какой-либо переменной), используемое для документации">строке документации</dfn> функции, и **FastAPI** прочитает её оттуда.
|
||||
|
||||
Вы можете использовать [Markdown](https://en.wikipedia.org/wiki/Markdown) в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).
|
||||
|
||||
@@ -94,7 +94,7 @@ OpenAPI указывает, что каждой *операции пути* не
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
|
||||
|
||||
Он будет четко помечен как устаревший в интерактивной документации:
|
||||
Она будет четко помечена как устаревшая в интерактивной документации:
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image04.png">
|
||||
|
||||
|
||||
@@ -80,8 +80,8 @@ q: Annotated[str | None] = None
|
||||
Теперь FastAPI будет:
|
||||
|
||||
* **валидировать** данные, удостоверяясь, что максимальная длина — 50 символов;
|
||||
* показывать **понятную ошибку** клиенту, если данные невалидны;
|
||||
* **документировать** параметр в *операции пути* схемы OpenAPI (он будет показан в **UI автоматической документации**).
|
||||
* отображать **понятную ошибку** клиенту, если данные невалидны;
|
||||
* **документировать** параметр в *операции пути* схемы OpenAPI (он будет отображаться в **UI автоматической документации**).
|
||||
|
||||
## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
|
||||
|
||||
@@ -119,7 +119,7 @@ q: str | None = None
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
Это провалидирует данные, покажет понятную ошибку, если данные невалидны, и задокументирует параметр в *операции пути* схемы OpenAPI.
|
||||
Это провалидирует данные, отобразит понятную ошибку, если данные невалидны, и задокументирует параметр в *операции пути* схемы OpenAPI.
|
||||
|
||||
### `Query` как значение по умолчанию или внутри `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
@@ -141,7 +141,7 @@ q: Annotated[str, Query(default="rick")] = "morty"
|
||||
q: Annotated[str, Query()] = "rick"
|
||||
```
|
||||
|
||||
...или в старой кодовой базе вы увидите:
|
||||
...или в старых кодовых базах вы увидите:
|
||||
|
||||
```Python
|
||||
q: str = Query(default="rick")
|
||||
@@ -153,19 +153,19 @@ q: str = Query(default="rick")
|
||||
|
||||
**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
|
||||
|
||||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||||
|
||||
Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
|
||||
Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор кода, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
|
||||
|
||||
Так как `Annotated` может содержать больше одной аннотации метаданных, теперь вы можете использовать ту же функцию и с другими инструментами, например с [Typer](https://typer.tiangolo.com/). 🚀
|
||||
|
||||
## Больше валидаций { #add-more-validations }
|
||||
## Добавим больше валидаций { #add-more-validations }
|
||||
|
||||
Можно также добавить параметр `min_length`:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## Регулярные выражения { #add-regular-expressions }
|
||||
## Добавим регулярные выражения { #add-regular-expressions }
|
||||
|
||||
Вы можете определить <dfn title="Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</dfn> `pattern`, которому должен соответствовать параметр:
|
||||
|
||||
@@ -173,7 +173,7 @@ q: str = Query(default="rick")
|
||||
|
||||
Данный шаблон регулярного выражения проверяет, что полученное значение параметра:
|
||||
|
||||
* `^`: начинается с следующих символов, до них нет символов.
|
||||
* `^`: начинается со следующих символов, до них нет символов.
|
||||
* `fixedquery`: имеет точное значение `fixedquery`.
|
||||
* `$`: заканчивается здесь, после `fixedquery` нет никаких символов.
|
||||
|
||||
@@ -191,7 +191,7 @@ q: str = Query(default="rick")
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.
|
||||
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным (не обязательным).
|
||||
|
||||
///
|
||||
|
||||
@@ -243,7 +243,7 @@ http://localhost:8000/items/?q=foo&q=bar
|
||||
|
||||
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
|
||||
|
||||
Таким образом, ответ на этот URL будет:
|
||||
Таким образом, HTTP-ответом на этот URL будет:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -276,7 +276,7 @@ http://localhost:8000/items/?q=foo&q=bar
|
||||
http://localhost:8000/items/
|
||||
```
|
||||
|
||||
значение по умолчанию для `q` будет: `["foo", "bar"]`, и ответом будет:
|
||||
значение по умолчанию для `q` будет: `["foo", "bar"]`, и вашим HTTP-ответом будет:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -301,7 +301,7 @@ http://localhost:8000/items/
|
||||
|
||||
///
|
||||
|
||||
## Больше метаданных { #declare-more-metadata }
|
||||
## Объявление дополнительных метаданных { #declare-more-metadata }
|
||||
|
||||
Можно добавить больше информации о параметре.
|
||||
|
||||
@@ -369,7 +369,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
В таких случаях можно использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки, что значение — это `str`).
|
||||
|
||||
Этого можно добиться, используя [`AfterValidator` Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) внутри `Annotated`.
|
||||
Этого можно добиться, используя [Pydantic `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) внутри `Annotated`.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
@@ -377,7 +377,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
///
|
||||
|
||||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="Internet Movie Database - Интернетная база данных фильмов: веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма в <abbr title="Internet Movie Database - Интернет-база данных фильмов: веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -391,7 +391,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
Если вам нужна валидация, требующая общения с каким‑либо **внешним компонентом** — базой данных или другим API — вместо этого используйте **Зависимости FastAPI**, вы познакомитесь с ними позже.
|
||||
|
||||
Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в запросе.
|
||||
Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в HTTP-запросе.
|
||||
|
||||
///
|
||||
|
||||
@@ -429,7 +429,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
Вы можете объявлять дополнительные проверки и метаданные для параметров.
|
||||
|
||||
Общие метаданные и настройки:
|
||||
Общие проверки и метаданные:
|
||||
|
||||
* `alias`
|
||||
* `title`
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Query-параметры { #query-parameters }
|
||||
|
||||
Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
|
||||
Когда вы объявляете параметры функции, которые не являются частью path-параметров, они автоматически интерпретируются как "query"-параметры.
|
||||
|
||||
{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
|
||||
|
||||
Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
|
||||
Query — это набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
|
||||
|
||||
Например, в этом URL-адресе:
|
||||
|
||||
@@ -12,25 +12,25 @@ Query-параметры представляют из себя набор па
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
...параметры запроса такие:
|
||||
...query-параметры такие:
|
||||
|
||||
* `skip`: со значением `0`
|
||||
* `limit`: со значением `10`
|
||||
|
||||
Будучи частью URL-адреса, они "по умолчанию" являются строками.
|
||||
Будучи частью URL-адреса, они "естественным образом" являются строками.
|
||||
|
||||
Но когда вы объявляете их с использованием типов Python (в примере выше, как `int`), они конвертируются в указанный тип данных и проходят проверку на соответствие ему.
|
||||
|
||||
Все те же правила, которые применяются к path-параметрам, также применяются и query-параметрам:
|
||||
Все те же процессы, которые применяются к path-параметрам, также применяются и к query-параметрам:
|
||||
|
||||
* Поддержка от редактора кода (очевидно)
|
||||
* <dfn title="преобразование строки, полученной из HTTP-запроса в данные Python">"Парсинг"</dfn> данных
|
||||
* Проверка на соответствие данных (Валидация)
|
||||
* <dfn title="преобразование строки, полученной из HTTP-запроса, в данные Python">"Парсинг"</dfn> данных
|
||||
* Валидация данных
|
||||
* Автоматическая документация
|
||||
|
||||
## Значения по умолчанию { #defaults }
|
||||
|
||||
Поскольку query-параметры не являются фиксированной частью пути, они могут быть не обязательными и иметь значения по умолчанию.
|
||||
Поскольку query-параметры не являются фиксированной частью пути, они могут быть необязательными и иметь значения по умолчанию.
|
||||
|
||||
В примере выше значения по умолчанию равны `skip=0` и `limit=10`.
|
||||
|
||||
@@ -40,13 +40,13 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
http://127.0.0.1:8000/items/
|
||||
```
|
||||
|
||||
будет таким же, как если перейти используя параметры по умолчанию:
|
||||
будет таким же, как если перейти по:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
Но если вы введёте, например:
|
||||
Но если вы перейдёте, например, по:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=20
|
||||
@@ -55,7 +55,7 @@ http://127.0.0.1:8000/items/?skip=20
|
||||
Значения параметров в вашей функции будут:
|
||||
|
||||
* `skip=20`: потому что вы установили это в URL-адресе
|
||||
* `limit=10`: т.к это было значение по умолчанию
|
||||
* `limit=10`: потому что это было значение по умолчанию
|
||||
|
||||
## Необязательные параметры { #optional-parameters }
|
||||
|
||||
@@ -63,21 +63,21 @@ http://127.0.0.1:8000/items/?skip=20
|
||||
|
||||
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
|
||||
|
||||
В этом случае, параметр `q` будет не обязательным и будет иметь значение `None` по умолчанию.
|
||||
В этом случае параметр функции `q` будет необязательным и будет иметь значение `None` по умолчанию.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Также обратите внимание, что **FastAPI** достаточно умён чтобы заметить, что параметр `item_id` является path-параметром, а `q` нет, поэтому, это параметр запроса.
|
||||
Также обратите внимание, что **FastAPI** достаточно умён, чтобы заметить, что path-параметр `item_id` является path-параметром, а `q` — нет, поэтому это query-параметр.
|
||||
|
||||
///
|
||||
|
||||
## Преобразование типа параметра запроса { #query-parameter-type-conversion }
|
||||
## Преобразование типа query-параметра { #query-parameter-type-conversion }
|
||||
|
||||
Вы также можете объявлять параметры с типом `bool`, которые будут преобразованы соответственно:
|
||||
Вы также можете объявлять типы `bool`, и они будут преобразованы:
|
||||
|
||||
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
|
||||
|
||||
В этом случае, если вы сделаете запрос:
|
||||
В этом случае, если вы перейдёте по:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=1
|
||||
@@ -107,11 +107,12 @@ http://127.0.0.1:8000/items/foo?short=on
|
||||
http://127.0.0.1:8000/items/foo?short=yes
|
||||
```
|
||||
|
||||
или в любом другом варианте написания (в верхнем регистре, с заглавной буквой, и т.п), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool` . В противном случае - `False`.
|
||||
или в любом другом варианте написания (в верхнем регистре, с заглавной буквой и т.п.), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool`. В противном случае — `False`.
|
||||
|
||||
## Смешивание query-параметров и path-параметров { #multiple-path-and-query-parameters }
|
||||
|
||||
Вы можете объявлять несколько query-параметров и path-параметров одновременно, **FastAPI** сам разберётся, что чем является.
|
||||
## Несколько path-параметров и query-параметров { #multiple-path-and-query-parameters }
|
||||
|
||||
Вы можете объявлять несколько path-параметров и query-параметров одновременно, **FastAPI** знает, что чем является.
|
||||
|
||||
И вы не обязаны объявлять их в каком-либо определенном порядке.
|
||||
|
||||
@@ -123,21 +124,21 @@ http://127.0.0.1:8000/items/foo?short=yes
|
||||
|
||||
Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе мы пока что рассмотрели только query-параметры), то он не является обязательным.
|
||||
|
||||
Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.
|
||||
Если вы не хотите задавать конкретное значение, но хотите просто сделать параметр необязательным, установите значение по умолчанию равным `None`.
|
||||
|
||||
Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:
|
||||
|
||||
{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
|
||||
|
||||
Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`.
|
||||
Здесь query-параметр `needy` является обязательным query-параметром с типом данных `str`.
|
||||
|
||||
Если вы откроете в браузере URL-адрес, например:
|
||||
Если вы откроете в браузере URL-адрес вроде:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item
|
||||
```
|
||||
|
||||
...без добавления обязательного параметра `needy`, вы увидите подобного рода ошибку:
|
||||
...без добавления обязательного параметра `needy`, вы увидите ошибку вроде:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -170,18 +171,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
}
|
||||
```
|
||||
|
||||
Конечно, вы можете определить некоторые параметры как обязательные, некоторые — со значением по умолчанию, а некоторые — полностью необязательные:
|
||||
И, конечно, вы можете определить некоторые параметры как обязательные, некоторые — со значением по умолчанию, а некоторые — полностью необязательные:
|
||||
|
||||
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
|
||||
|
||||
В этом примере, у нас есть 3 параметра запроса:
|
||||
В этом случае есть 3 query-параметра:
|
||||
|
||||
* `needy`, обязательный `str`.
|
||||
* `skip`, типа `int` и со значением по умолчанию `0`.
|
||||
* `skip`, `int` со значением по умолчанию `0`.
|
||||
* `limit`, необязательный `int`.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Вы можете использовать класс `Enum` также, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values).
|
||||
Вы можете использовать `Enum` так же, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values).
|
||||
|
||||
///
|
||||
|
||||
@@ -38,13 +38,13 @@ $ pip install python-multipart
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Для объявления тела файла необходимо использовать `File`, поскольку в противном случае параметры будут интерпретироваться как параметры запроса или параметры тела (JSON).
|
||||
Чтобы объявить файлы в теле запроса, необходимо использовать `File`, поскольку иначе параметры будут интерпретироваться как параметры запроса или body-параметры (JSON).
|
||||
|
||||
///
|
||||
|
||||
Файлы будут загружены как данные формы.
|
||||
|
||||
Если вы объявите тип параметра у *функции операции пути* как `bytes`, то **FastAPI** прочитает файл за вас, и вы получите его содержимое в виде `bytes`.
|
||||
Если вы объявите тип параметра у *функции-обработчика пути* как `bytes`, то **FastAPI** прочитает файл за вас, и вы получите его содержимое в виде `bytes`.
|
||||
|
||||
Следует иметь в виду, что все содержимое будет храниться в памяти. Это хорошо подходит для небольших файлов.
|
||||
|
||||
@@ -64,15 +64,15 @@ $ pip install python-multipart
|
||||
* Это означает, что он будет хорошо работать с большими файлами, такими как изображения, видео, большие бинарные файлы и т.д., не потребляя при этом всю память.
|
||||
* Из загруженного файла можно получить метаданные.
|
||||
* Он реализует [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` интерфейс.
|
||||
* Он предоставляет реальный объект Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile), который вы можете передать непосредственно другим библиотекам, которые ожидают файл в качестве объекта.
|
||||
* Он предоставляет реальный объект Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile), который вы можете передать непосредственно другим библиотекам, которые ожидают file-like объект.
|
||||
|
||||
### `UploadFile` { #uploadfile }
|
||||
|
||||
`UploadFile` имеет следующие атрибуты:
|
||||
|
||||
* `filename`: Строка `str` с исходным именем файла, который был загружен (например, `myimage.jpg`).
|
||||
* `content_type`: Строка `str` с типом содержимого (MIME type / media type) (например, `image/jpeg`).
|
||||
* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим файл в качестве объекта.
|
||||
* `content_type`: Строка `str` с типом содержимого (MIME-тип / тип содержимого) (например, `image/jpeg`).
|
||||
* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) ([file-like](https://docs.python.org/3/glossary.html#term-file-like-object) объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим file-like объект.
|
||||
|
||||
`UploadFile` имеет следующие методы `async`. Все они вызывают соответствующие файловые методы (используя внутренний `SpooledTemporaryFile`).
|
||||
|
||||
@@ -85,19 +85,18 @@ $ pip install python-multipart
|
||||
|
||||
Поскольку все эти методы являются `async` методами, вам следует использовать "await" вместе с ними.
|
||||
|
||||
Например, внутри `async` *функции операции пути* можно получить содержимое с помощью:
|
||||
Например, внутри `async` *функции-обработчика пути* можно получить содержимое с помощью:
|
||||
|
||||
```Python
|
||||
contents = await myfile.read()
|
||||
```
|
||||
|
||||
Если вы находитесь внутри обычной `def` *функции операции пути*, можно получить прямой доступ к файлу `UploadFile.file`, например:
|
||||
Если вы находитесь внутри обычной `def` *функции-обработчика пути*, можно получить прямой доступ к файлу `UploadFile.file`, например:
|
||||
|
||||
```Python
|
||||
contents = myfile.file.read()
|
||||
```
|
||||
|
||||
|
||||
/// note | Технические детали `async`
|
||||
|
||||
При использовании методов `async` **FastAPI** запускает файловые методы в пуле потоков и ожидает их.
|
||||
@@ -106,7 +105,7 @@ contents = myfile.file.read()
|
||||
|
||||
/// note | Технические детали Starlette
|
||||
|
||||
**FastAPI** наследует `UploadFile` непосредственно из **Starlette**, но добавляет некоторые детали для совместимости с **Pydantic** и другими частями FastAPI.
|
||||
`UploadFile` из **FastAPI** наследуется непосредственно от `UploadFile` из **Starlette**, но добавляет некоторые необходимые части для совместимости с **Pydantic** и другими частями FastAPI.
|
||||
|
||||
///
|
||||
|
||||
@@ -118,17 +117,17 @@ contents = myfile.file.read()
|
||||
|
||||
/// note | Технические детали
|
||||
|
||||
Данные из форм обычно кодируются с использованием "media type" `application/x-www-form-urlencoded` когда он не включает файлы.
|
||||
Данные из форм обычно кодируются с использованием типа содержимого `application/x-www-form-urlencoded`, когда они не включают файлы.
|
||||
|
||||
Но когда форма включает файлы, она кодируется как `multipart/form-data`. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела.
|
||||
Но когда форма включает файлы, она кодируется как `multipart/form-data`. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела запроса.
|
||||
|
||||
Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке [<abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> web docs for `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
Если вы хотите узнать больше об этих кодировках и полях форм, перейдите к [веб-документации <abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> по `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
|
||||
///
|
||||
|
||||
/// warning | Внимание
|
||||
|
||||
В операции *функции операции пути* можно объявить несколько параметров `File` и `Form`, но нельзя также объявлять поля `Body`, которые предполагается получить в виде JSON, поскольку тело запроса будет закодировано с помощью `multipart/form-data`, а не `application/json`.
|
||||
В *операции пути* можно объявить несколько параметров `File` и `Form`, но нельзя также объявлять поля `Body`, которые предполагается получить в виде JSON, поскольку HTTP-запрос будет иметь тело, закодированное с помощью `multipart/form-data`, а не `application/json`.
|
||||
|
||||
Это не является ограничением **FastAPI**, это часть протокола HTTP.
|
||||
|
||||
@@ -174,4 +173,4 @@ contents = myfile.file.read()
|
||||
|
||||
## Резюме { #recap }
|
||||
|
||||
Используйте `File`, `bytes` и `UploadFile` для работы с файлами, которые будут загружаться и передаваться в виде данных формы.
|
||||
Используйте `File`, `bytes` и `UploadFile`, чтобы объявлять файлы для загрузки в HTTP-запросе, передаваемые как данные формы.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Данные формы { #form-data }
|
||||
|
||||
|
||||
Когда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`.
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Статус-код ответа { #response-status-code }
|
||||
|
||||
Подобно тому, как вы можете задать модель/схему ответа, вы можете объявить HTTP статус-код, используемый для ответа, с помощью параметра `status_code` в любой из *операций пути*:
|
||||
Подобно тому, как вы можете задать модель ответа, вы можете объявить HTTP статус-код, используемый для ответа, с помощью параметра `status_code` в любой из *операций пути*:
|
||||
|
||||
* `@app.get()`
|
||||
* `@app.post()`
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
Это позволит:
|
||||
|
||||
* Возвращать указанный код статуса в ответе.
|
||||
* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательских интерфейсах):
|
||||
* Возвращать указанный статус-код в ответе.
|
||||
* Документировать его как статус-код ответа в OpenAPI схеме (а значит, и в пользовательских интерфейсах):
|
||||
|
||||
<img src="/img/tutorial/response-status-code/image01.png">
|
||||
|
||||
@@ -47,26 +47,26 @@ FastAPI знает об этом и создаст документацию Open
|
||||
|
||||
///
|
||||
|
||||
В протоколе HTTP числовой код состояния из 3 цифр отправляется как часть ответа.
|
||||
В протоколе HTTP числовой статус-код из 3 цифр отправляется как часть ответа.
|
||||
|
||||
У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
|
||||
У статус-кодов есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
|
||||
|
||||
Кратко:
|
||||
|
||||
* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
|
||||
* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими статус-кодами не могут иметь тела.
|
||||
* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
|
||||
* `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
|
||||
* `200` – это статус-код по умолчанию, который означает, что все прошло "OK".
|
||||
* Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
|
||||
* Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
|
||||
* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
|
||||
* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими статус-кодами могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
|
||||
* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
|
||||
* Пример – код `404` для статуса "Not Found".
|
||||
* Для общих ошибок со стороны клиента можно просто использовать код `400`.
|
||||
* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из этих кодов статуса.
|
||||
* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из этих статус-кодов.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с [<abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
|
||||
Чтобы узнать больше о HTTP статус-кодах и о том, для чего каждый из них предназначен, ознакомьтесь с [<abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
|
||||
|
||||
///
|
||||
|
||||
@@ -76,7 +76,7 @@ FastAPI знает об этом и создаст документацию Open
|
||||
|
||||
{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
|
||||
|
||||
`201` – это код статуса "Создано".
|
||||
`201` – это статус-код для "Created".
|
||||
|
||||
Но вам не обязательно запоминать, что означает каждый из этих кодов.
|
||||
|
||||
@@ -84,7 +84,7 @@ FastAPI знает об этом и создаст документацию Open
|
||||
|
||||
{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
|
||||
|
||||
Они содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса:
|
||||
Они существуют только для удобства, содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора статус-кода:
|
||||
|
||||
<img src="/img/tutorial/response-status-code/image02.png">
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Объявление примеров данных запроса { #declare-request-example-data }
|
||||
# Объявление примеров данных HTTP-запроса { #declare-request-example-data }
|
||||
|
||||
Вы можете объявлять примеры данных, которые ваше приложение может получать.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
Эта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.
|
||||
|
||||
Вы можете использовать атрибут `model_config`, который принимает `dict`, как описано в [Документация Pydantic: Конфигурация](https://docs.pydantic.dev/latest/api/config/).
|
||||
Вы можете использовать атрибут `model_config`, который принимает `dict`, как описано в [документации Pydantic: Конфигурация](https://docs.pydantic.dev/latest/api/config/).
|
||||
|
||||
Вы можете задать `"json_schema_extra"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) добавил поддержку `examples`, который является частью стандарта **JSON Schema**.
|
||||
OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) добавил поддержку `examples`, которое является частью стандарта **JSON Schema**.
|
||||
|
||||
До этого поддерживалось только ключевое слово `example` с одним примером. Оно всё ещё поддерживается в OpenAPI 3.1.0, но помечено как устаревшее и не является частью стандарта JSON Schema. Поэтому рекомендуется мигрировать `example` на `examples`. 🤓
|
||||
|
||||
@@ -80,13 +80,13 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
|
||||
|
||||
Ещё до того как **JSON Schema** поддержала `examples`, в OpenAPI была поддержка другого поля, также называемого `examples`.
|
||||
|
||||
Эти **специфические для OpenAPI** `examples` находятся в другой секции спецификации OpenAPI. Они находятся в **подробностях для каждой операции пути (обработчика пути)**, а не внутри каждого объекта Schema.
|
||||
Эти **специфические для OpenAPI** `examples` находятся в другой секции спецификации OpenAPI. Они находятся в **подробностях каждой *операции пути***, а не внутри каждой JSON Schema.
|
||||
|
||||
И Swagger UI уже какое‑то время поддерживает именно это поле `examples`. Поэтому вы можете использовать его, чтобы **отобразить** разные **примеры в UI документации**.
|
||||
|
||||
Структура этого специфичного для OpenAPI поля `examples` — это `dict` с **несколькими примерами** (вместо `list`), каждый с дополнительной информацией, которая также будет добавлена в **OpenAPI**.
|
||||
|
||||
Это не помещается внутрь каждого объекта Schema в OpenAPI, это находится снаружи, непосредственно на уровне самой *операции пути*.
|
||||
Это не помещается внутрь каждой JSON Schema, содержащейся в OpenAPI, это находится снаружи, непосредственно на уровне самой *операции пути*.
|
||||
|
||||
### Использование параметра `openapi_examples` { #using-the-openapi-examples-parameter }
|
||||
|
||||
|
||||
@@ -186,9 +186,9 @@ oauth2_scheme(some, parameters)
|
||||
|
||||
## Что он делает { #what-it-does }
|
||||
|
||||
Он будет искать в запросе HTTP-заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.
|
||||
Он будет искать в HTTP-запросе HTTP-заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.
|
||||
|
||||
Если заголовок `Authorization` отсутствует или его значение не содержит токен `Bearer `, он сразу ответит ошибкой со статус-кодом 401 (`UNAUTHORIZED`).
|
||||
Если HTTP-заголовок `Authorization` отсутствует или его значение не содержит токен `Bearer `, он сразу ответит ошибкой со статус-кодом 401 (`UNAUTHORIZED`).
|
||||
|
||||
Вам даже не нужно проверять наличие токена, чтобы вернуть ошибку. Вы можете быть уверены: если ваша функция была выполнена, в этом токене будет `str`.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
Точно так же, как мы используем Pydantic для объявления тел запросов, мы можем использовать его где угодно:
|
||||
|
||||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
|
||||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:16] *}
|
||||
|
||||
## Создать зависимость `get_current_user` { #create-a-get-current-user-dependency }
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
То, как устроена эта система зависимостей, позволяет иметь разные зависимости, которые возвращают модель `User`.
|
||||
То, как устроена эта система зависимостей, позволяет иметь разные зависимости (разные "dependables"), которые все возвращают модель `User`.
|
||||
|
||||
Мы не ограничены наличием только одной зависимости, которая может возвращать такой тип данных.
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4
|
||||
|
||||
## Установка `PyJWT` { #install-pyjwt }
|
||||
|
||||
Нам необходимо установить `pyjwt` для генерации и проверки JWT-токенов на языке Python.
|
||||
Нам необходимо установить `PyJWT` для генерации и проверки JWT-токенов на языке Python.
|
||||
|
||||
Убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md), активируйте его, а затем установите `pyjwt`:
|
||||
|
||||
@@ -42,7 +42,7 @@ $ pip install pyjwt
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Дополнительная информация
|
||||
/// note | Примечание
|
||||
|
||||
Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.
|
||||
|
||||
@@ -110,9 +110,9 @@ pwdlib также поддерживает алгоритм хешировани
|
||||
|
||||
///
|
||||
|
||||
Создайте служебную функцию для хэширования пароля, поступающего от пользователя.
|
||||
Создайте вспомогательную функцию для хэширования пароля, поступающего от пользователя.
|
||||
|
||||
А затем создайте другую — для проверки соответствия полученного пароля и хранимого хэша.
|
||||
А затем создайте другую вспомогательную функцию — для проверки соответствия полученного пароля и хранимого хэша.
|
||||
|
||||
И еще одну — для аутентификации и возврата пользователя.
|
||||
|
||||
@@ -120,15 +120,15 @@ pwdlib также поддерживает алгоритм хешировани
|
||||
|
||||
Когда `authenticate_user` вызывается с именем пользователя, которого нет в базе данных, мы все равно запускаем `verify_password` с использованием фиктивного хэша.
|
||||
|
||||
Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая тайминговые атаки (атака по времени), с помощью которых можно было бы перечислять существующие имена пользователей.
|
||||
Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая **тайминговые атаки** (атаки по времени), с помощью которых можно было бы перечислять существующие имена пользователей.
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
|
||||
|
||||
///
|
||||
|
||||
## Работа с JWT токенами { #handle-jwt-tokens }
|
||||
## Работа с JWT-токенами { #handle-jwt-tokens }
|
||||
|
||||
Импортируйте установленные модули.
|
||||
|
||||
@@ -154,7 +154,7 @@ $ openssl rand -hex 32
|
||||
|
||||
Определите Pydantic-модель, которая будет использоваться для формирования ответа на запрос на получение токена.
|
||||
|
||||
Создайте служебную функцию для генерации нового токена доступа.
|
||||
Создайте вспомогательную функцию для генерации нового токена доступа.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
|
||||
|
||||
@@ -172,7 +172,7 @@ $ openssl rand -hex 32
|
||||
|
||||
Создайте `timedelta` со временем истечения срока действия токена.
|
||||
|
||||
Создайте реальный токен доступа JWT и верните его
|
||||
Создайте реальный токен доступа JWT и верните его.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
|
||||
|
||||
@@ -188,13 +188,13 @@ JWT может использоваться и для других целей,
|
||||
|
||||
Затем вы могли бы добавить права доступа к этой сущности, например "управлять" (для автомобиля) или "редактировать" (для блога).
|
||||
|
||||
Затем вы могли бы передать этот JWT-токен пользователю (или боту), и они использовали бы его для выполнения определенных действий (управление автомобилем или редактирование запись в блоге), даже не имея учетной записи, просто используя JWT-токен, сгенерированный вашим API.
|
||||
Затем вы могли бы передать этот JWT-токен пользователю (или боту), и они использовали бы его для выполнения определенных действий (управление автомобилем или редактирование записи в блоге), даже не имея учетной записи, просто используя JWT-токен, сгенерированный вашим API.
|
||||
|
||||
Используя эти идеи, JWT можно применять для гораздо более сложных сценариев.
|
||||
|
||||
В отдельных случаях несколько сущностей могут иметь один и тот же идентификатор, скажем, `foo` (пользователь `foo`, автомобиль `foo` и запись в блоге `foo`).
|
||||
|
||||
Поэтому, чтобы избежать коллизий идентификаторов, при создании JWT-токена для пользователя можно добавить префикс `username` к значению ключа `sub`. Таким образом, в данном примере значение `sub` было бы `username:johndoe`.
|
||||
Поэтому, чтобы избежать коллизий идентификаторов, при создании JWT-токена для пользователя можно добавить префикс `username:` к значению ключа `sub`. Таким образом, в данном примере значение `sub` могло бы быть: `username:johndoe`.
|
||||
|
||||
Важно помнить, что ключ `sub` должен иметь уникальный идентификатор для всего приложения и представлять собой строку.
|
||||
|
||||
@@ -238,7 +238,7 @@ Password: `secret`
|
||||
|
||||
<img src="/img/tutorial/security/image10.png">
|
||||
|
||||
/// note | Техническая информация
|
||||
/// note | Примечание
|
||||
|
||||
Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ OAuth2 определяет, что при использовании "password
|
||||
|
||||
А ваши модели баз данных могут использовать любые другие имена.
|
||||
|
||||
Но для логин-операции пути нам нужно использовать именно эти имена, чтобы быть совместимыми со спецификацией (и иметь возможность, например, использовать встроенную систему документации API).
|
||||
Но для *операции пути* входа в систему нам нужно использовать именно эти имена, чтобы быть совместимыми со спецификацией (и иметь возможность, например, использовать встроенную систему документации API).
|
||||
|
||||
В спецификации также указано, что `username` и `password` должны передаваться в виде данных формы (так что никакого JSON здесь нет).
|
||||
|
||||
@@ -88,7 +88,7 @@ OAuth2 определяет, что при использовании "password
|
||||
|
||||
Теперь получим данные о пользователе из (ненастоящей) базы данных, используя `username` из поля формы.
|
||||
|
||||
Если такого пользователя нет, то мы возвращаем ошибку "Incorrect username or password" (неверное имя пользователя или пароль).
|
||||
Если такого пользователя нет, то мы возвращаем ошибку "Incorrect username or password".
|
||||
|
||||
Для ошибки используем исключение `HTTPException`:
|
||||
|
||||
@@ -137,12 +137,12 @@ UserInDB(
|
||||
```
|
||||
|
||||
/// note | Примечание
|
||||
Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user-in-dict).
|
||||
Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user-in-model-dump).
|
||||
///
|
||||
|
||||
## Возврат токена { #return-the-token }
|
||||
|
||||
Ответ операции пути `/token` должен быть объектом JSON.
|
||||
Ответ эндпоинта `token` должен быть объектом JSON.
|
||||
|
||||
В нём должен быть `token_type`. В нашем случае, поскольку мы используем токены типа "Bearer", тип токена должен быть `bearer`.
|
||||
|
||||
@@ -151,7 +151,7 @@ UserInDB(
|
||||
В этом простом примере мы намеренно поступим небезопасно и вернём тот же `username` в качестве токена.
|
||||
|
||||
/// tip | Подсказка
|
||||
В следующей главе вы увидите реальную защищённую реализацию с хешированием паролей и токенами <abbr title="JSON Web Tokens – JSON веб-токены">JWT</abbr>.
|
||||
В следующей главе вы увидите реальную защищённую реализацию с хешированием паролей и токенами <abbr title="JSON Web Tokens - JSON веб-токены">JWT</abbr>.
|
||||
|
||||
Но пока давайте сосредоточимся на необходимых нам деталях.
|
||||
///
|
||||
@@ -266,8 +266,8 @@ UserInDB(
|
||||
|
||||
Теперь у вас есть инструменты для реализации полноценной системы безопасности на основе `username` и `password` для вашего API.
|
||||
|
||||
Используя эти средства, можно сделать систему безопасности совместимой с любой базой данных и с любой пользовательской или моделью данных.
|
||||
Используя эти средства, можно сделать систему безопасности совместимой с любой базой данных и с любой моделью пользователя или моделью данных.
|
||||
|
||||
Единственная деталь, которой не хватает, — система пока ещё не "защищена" по-настоящему.
|
||||
|
||||
В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title="JSON Web Tokens – JSON веб-токены">JWT</abbr>.
|
||||
В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title="JSON Web Tokens - JSON веб-токены">JWT</abbr>.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SQL (реляционные) базы данных { #sql-relational-databases }
|
||||
|
||||
**FastAPI** не требует использовать SQL (реляционную) базу данных. Но вы можете использовать любую базу данных, которую хотите.
|
||||
**FastAPI** не требует использовать SQL (реляционную) базу данных. Но вы можете использовать **любую базу данных**, которую хотите.
|
||||
|
||||
Здесь мы рассмотрим пример с использованием [SQLModel](https://sqlmodel.tiangolo.com/).
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title="Object Relational Mapper - Объектно-реляционный маппер: термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах">"ORMs"</abbr>), FastAPI ничего не навязывает. 😎
|
||||
Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title="Object Relational Mapper - Объектно-реляционный маппер: красивый термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах">"ORMs"</abbr>), FastAPI ничего не навязывает. 😎
|
||||
|
||||
///
|
||||
|
||||
@@ -119,7 +119,7 @@ $ pip install sqlmodel
|
||||
|
||||
Так как каждая модель SQLModel также является моделью Pydantic, вы можете использовать её в тех же **аннотациях типов**, в которых используете модели Pydantic.
|
||||
|
||||
Например, если вы объявите параметр типа `Hero`, он будет прочитан из **JSON body (тела запроса)**.
|
||||
Например, если вы объявите параметр типа `Hero`, он будет прочитан из **JSON-тела запроса**.
|
||||
|
||||
Аналогично вы можете объявить её как **тип возвращаемого значения** функции, и тогда форма данных отобразится в автоматически сгенерированном UI документации API.
|
||||
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
Вы можете предоставлять статические файлы автоматически из директории, используя `StaticFiles`.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Если вам нужно разместить фронтенд, используйте вместо этого `app.frontend()`, подробнее читайте в разделе [Фронтенд](frontend.md).
|
||||
|
||||
`app.frontend()` использует `StaticFiles` под капотом, с несколькими дополнительными преимуществами для фронтендов, такими как обработка маршрутизации на стороне клиента.
|
||||
|
||||
///
|
||||
|
||||
## Использование `StaticFiles` { #use-staticfiles }
|
||||
|
||||
* Импортируйте `StaticFiles`.
|
||||
@@ -21,8 +29,7 @@
|
||||
|
||||
"Монтирование" означает добавление полноценного "независимого" приложения на определённый путь, которое затем обрабатывает все подпути.
|
||||
|
||||
Это отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым.
|
||||
OpenAPI и документация из вашего главного приложения не будут содержать ничего из примонтированного приложения, и т.д.
|
||||
Это отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым. OpenAPI и документация из вашего главного приложения не будут содержать ничего из примонтированного приложения, и т.д.
|
||||
|
||||
Вы можете прочитать больше об этом в [Расширенном руководстве пользователя](../advanced/index.md).
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ $ pip install httpx
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
|
||||
Так как этот файл находится в том же пакете, для импорта объекта `app` из модуля `main` (`main.py`) Вы можете использовать относительный импорт:
|
||||
|
||||
{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
|
||||
|
||||
@@ -113,7 +113,7 @@ $ pip install httpx
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
Предположим, что в файле `main.py` с приложением **FastAPI** есть несколько **операций пути**.
|
||||
Предположим, что теперь в файле `main.py` с приложением **FastAPI** есть несколько других **операций пути**.
|
||||
|
||||
В нём описана операция `GET`, которая может вернуть ошибку.
|
||||
|
||||
@@ -125,20 +125,20 @@ $ pip install httpx
|
||||
|
||||
### Расширенный файл тестов { #extended-testing-file }
|
||||
|
||||
Теперь обновим файл `test_main.py`, добавив в него тестов:
|
||||
Теперь можно обновить файл `test_main.py`, добавив в него расширенные тесты:
|
||||
|
||||
{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
|
||||
|
||||
|
||||
Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
|
||||
Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поиском (Google) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
|
||||
|
||||
Затем Вы просто применяете найденные ответы в тестах.
|
||||
|
||||
Например:
|
||||
|
||||
* Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL.
|
||||
* Чтобы передать *path*-параметр или *query*-параметр, добавьте его непосредственно в URL.
|
||||
* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.
|
||||
* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.
|
||||
* Если же Вам необходимо отправить *данные формы* вместо JSON, то используйте параметр `data` вместо `json`.
|
||||
* Для передачи *HTTP-заголовков*, передайте объект `dict` через параметр `headers`.
|
||||
* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.
|
||||
|
||||
|
||||
@@ -811,7 +811,7 @@ $ cd ~/code/prisoner-of-azkaban
|
||||
|
||||
$ python main.py
|
||||
|
||||
// Error importing sirius, it's not installed 😱
|
||||
// Ошибка при импорте sirius, он не установлен 😱
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1, in <module>
|
||||
import sirius
|
||||
|
||||
Reference in New Issue
Block a user