-# О проекте
+# О проекте { #about }
-FastAPI: внутреннее устройство, повлиявшие технологии и всё такое прочее. 🤓
+О FastAPI, его дизайне, источниках вдохновения и многом другом. 🤓
-# Дополнительные статус коды
+# Дополнительные статус-коды { #additional-status-codes }
-Ð\9fо Ñ\83молÑ\87аниÑ\8e **FastAPI** возвÑ\80аÑ\89аеÑ\82 ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`.
+Ð\9fо Ñ\83молÑ\87аниÑ\8e **FastAPI** бÑ\83деÑ\82 возвÑ\80аÑ\89аÑ\82Ñ\8c ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`.
-Он будет использовать код статуса по умолчанию или тот, который вы укажете в вашей *операции пути*.
+Он будет использовать статус-код по умолчанию или тот, который вы укажете в вашей *операции пути*.
-## Дополнительные статус коды
+## Дополнительные статус-коды { #additional-status-codes_1 }
-Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е возвÑ\80аÑ\89аÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\8bй Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81 код помимо оÑ\81новного, вÑ\8b можеÑ\82е Ñ\81делаÑ\82Ñ\8c Ñ\8dÑ\82о, возвÑ\80аÑ\89аÑ\8f обÑ\8aекÑ\82 `Response` напÑ\80Ñ\8fмÑ\83Ñ\8e, как `JSONResponse`, и Ñ\83Ñ\81Ñ\82анавливаÑ\8f нÑ\83жнÑ\8bй Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81 код напрямую.
+Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е возвÑ\80аÑ\89аÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\8bе Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-кодÑ\8b помимо оÑ\81новного, вÑ\8b можеÑ\82е Ñ\81делаÑ\82Ñ\8c Ñ\8dÑ\82о, возвÑ\80аÑ\89аÑ\8f `Response` напÑ\80Ñ\8fмÑ\83Ñ\8e, напÑ\80имеÑ\80 `JSONResponse`, и Ñ\83Ñ\81Ñ\82анавливаÑ\8f дополниÑ\82елÑ\8cнÑ\8bй Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-код напрямую.
-Например, скажем, вы хотите создать *операцию пути*, которая позволяет обновлять элементы и возвращает HTTP-код 200 "OK" при успешном выполнении.
+Например, предположим, что вы хотите иметь *операцию пути*, которая позволяет обновлять элементы и возвращает HTTP статус-код 200 «OK» при успешном выполнении.
-Но вы также хотите, чтобы она принимала новые элементы. И если элемент ранее не существовал, он создаётся, и возвращался HTTP-код 201 "Created".
+Но вы также хотите, чтобы она принимала новые элементы. И если элементы ранее не существовали, она создаёт их и возвращает HTTP статус-код 201 «Created».
-Чтобы реализовать это, импортируйте `JSONResponse` и возвращайте ваш контент напрямую, устанавливая нужный `status_code`:
+Чтобы добиться этого, импортируйте `JSONResponse` и верните туда свой контент напрямую, установив нужный вам `status_code`:
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
/// warning | Внимание
-Когда вы возвращаете объект `Response` напрямую, как в примере выше, он будет возвращён как есть.
+Когда вы возвращаете `Response` напрямую, как в примере выше, он будет возвращён как есть.
-Он не будет сериализован при помощи модели и т.д.
+Он не будет сериализован с помощью модели и т.п.
-Убедитесь, что в нём содержатся именно те данные, которые вы хотите, и что значения являются валидным JSON (если вы используете `JSONResponse`).
+Убедитесь, что в нём именно те данные, которые вы хотите, и что значения являются валидным JSON (если вы используете `JSONResponse`).
///
Вы также можете использовать `from starlette.responses import JSONResponse`.
-**FastAPI** предоставляет тот же `starlette.responses` через `fastapi.responses` просто для вашего удобства, как разработчика. Но большинство доступных Response-классов поступают напрямую из Starlette. То же самое касается и `status`.
+**FastAPI** предоставляет тот же `starlette.responses` через `fastapi.responses` просто для вашего удобства как разработчика. Но большинство доступных Response-классов приходят напрямую из Starlette. То же самое со `status`.
///
-## OpenAPI и документация API
+## OpenAPI и документация API { #openapi-and-api-docs }
-Если вы возвращаете дополнительные коды статусов и ответы напрямую, они не будут включены в схему OpenAPI (документацию API), потому что FastAPI не может заранее знать, что вы собираетесь вернуть.
+Если вы возвращаете дополнительные статус-коды и ответы напрямую, они не будут включены в схему OpenAPI (документацию API), потому что у FastAPI нет способа заранее знать, что вы собираетесь вернуть.
-Но вы можете задокументировать это в вашем коде, используя: [Дополнительные ответы в OpenAPI](additional-responses.md){.internal-link target=_blank}.
+Но вы можете задокументировать это в своём коде, используя: [Дополнительные ответы](additional-responses.md){.internal-link target=_blank}.
-# Асинхронное тестирование
+# Асинхронное тестирование { #async-tests }
Вы уже видели как тестировать **FastAPI** приложение, используя имеющийся класс `TestClient`. К этому моменту вы видели только как писать тесты в синхронном стиле без использования `async` функций.
Давайте рассмотрим, как мы можем это реализовать.
-## pytest.mark.anyio
+## pytest.mark.anyio { #pytest-mark-anyio }
Если мы хотим вызывать асинхронные функции в наших тестах, то наши тестовые функции должны быть асинхронными. AnyIO предоставляет для этого отличный плагин, который позволяет нам указывать, какие тестовые функции должны вызываться асинхронно.
-## HTTPX
+## HTTPX { #httpx }
Даже если **FastAPI** приложение использует обычные функции `def` вместо `async def`, это все равно `async` приложение 'под капотом'.
`TestClient` основан на <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>, и, к счастью, мы можем использовать его (`HTTPX`) напрямую для тестирования API.
-## Пример
+## Пример { #example }
В качестве простого примера, давайте рассмотрим файловую структуру, схожую с описанной в [Большие приложения](../tutorial/bigger-applications.md){.internal-link target=_blank} и [Тестирование](../tutorial/testing.md){.internal-link target=_blank}:
{* ../../docs_src/async_tests/test_main.py *}
-## Запуск тестов
+## Запуск тестов { #run-it }
Вы можете запустить свои тесты как обычно:
</div>
-## Подробнее
+## Подробнее { #in-detail }
Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно:
///
-## Вызов других асинхронных функций
+## Вызов других асинхронных функций { #other-asynchronous-function-calls }
Теперь тестовая функция стала асинхронной, поэтому внутри нее вы можете вызывать также и другие `async` функции, не связанные с отправлением запросов в ваше FastAPI приложение. Как если бы вы вызывали их в любом другом месте вашего кода.
-# Расширенное руководство пользователя
+# Расширенное руководство пользователя { #advanced-user-guide }
-## Дополнительные возможности
+## Дополнительные возможности { #additional-features }
Основное [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**.
В следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности.
-/// tip
+/// tip | Совет
Следующие разделы **не обязательно являются "продвинутыми"**.
///
-## Сначала прочитайте Учебник - Руководство пользователя
+## Сначала прочитайте Учебник - Руководство пользователя { #read-the-tutorial-first }
Вы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank}.
-# Response - Изменение cтатус кода
+# Response - Изменение статус-кода { #response-change-status-code }
-Вы, вероятно, уже читали о том, что можно установить [Состояние ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}.
+Вы, вероятно, уже читали о том, что можно установить [статус-код ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}.
-Ð\9dо в некоÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вам нÑ\83жно веÑ\80нÑ\83Ñ\82Ñ\8c код Ñ\81оÑ\81Ñ\82оÑ\8fниÑ\8f, оÑ\82лиÑ\87нÑ\8bй оÑ\82 Ñ\83Ñ\81Ñ\82ановленного по умолчанию.
+Ð\9dо в некоÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 нÑ\83жно веÑ\80нÑ\83Ñ\82Ñ\8c дÑ\80Ñ\83гой Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-код, оÑ\82лиÑ\87нÑ\8bй оÑ\82 знаÑ\87ениÑ\8f по умолчанию.
-## Пример использования
+## Пример использования { #use-case }
-Ð\9dапÑ\80имеÑ\80, пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о вÑ\8b Ñ\85оÑ\82иÑ\82е возвÑ\80аÑ\89аÑ\82Ñ\8c HTTP код Ñ\81оÑ\81Ñ\82оÑ\8fниÑ\8f "OK" `200` по Ñ\83молÑ\87аниÑ\8e.
+Ð\9dапÑ\80имеÑ\80, пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о вÑ\8b Ñ\85оÑ\82иÑ\82е по Ñ\83молÑ\87аниÑ\8e возвÑ\80аÑ\89аÑ\82Ñ\8c HTTP Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-код «OK» `200`.
-Но если данные не существовали, вы хотите создать их и вернуть HTTP код состояния "CREATED" `201`.
+Но если данные не существовали, вы хотите создать их и вернуть HTTP статус-код «CREATED» `201`.
При этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`.
Для таких случаев вы можете использовать параметр `Response`.
-## Использование параметра `Response`
+## Использование параметра `Response` { #use-a-response-parameter }
-Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (так же как для cookies и headers).
+Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (как и для cookies и HTTP-заголовков).
И затем вы можете установить `status_code` в этом *временном* объекте ответа.
И если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.
-**FastAPI** будет использовать этот *временный* ответ для извлечения кода состояния (а также cookies и headers) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`.
+**FastAPI** будет использовать этот *временный* ответ для извлечения статус-кода (а также cookies и HTTP-заголовков) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`.
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `Response` в завиÑ\81имоÑ\81Ñ\82Ñ\8fÑ\85 и Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c код Ñ\81оÑ\81Ñ\82оÑ\8fниÑ\8f в ниÑ\85. Но помните, что последнее установленное значение будет иметь приоритет.
+Ð\92Ñ\8b Ñ\82акже можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `Response` в завиÑ\81имоÑ\81Ñ\82Ñ\8fÑ\85 и Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c в ниÑ\85 Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-код. Но помните, что последнее установленное значение будет иметь приоритет.
+# Cookies в ответе { #response-cookies }
-# Cookies в ответе
+## Использование параметра `Response` { #use-a-response-parameter }
-## Использование параметра `Response`
-
-Вы можете объявить параметр типа `Response` в вашей функции эндпоинта.
+Вы можете объявить параметр типа `Response` в вашей функции-обработчике пути.
Затем установить cookies в этом временном объекте ответа.
Если вы указали `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.
-**FastAPI** извлечет cookies (а также заголовки и коды состояния) из временного ответа и включит их в окончательный ответ, содержащий ваше возвращаемое значение, отфильтрованное через `response_model`.
+**FastAPI** извлечет cookies (а также HTTP-заголовки и статус-код) из временного ответа и включит их в окончательный ответ, содержащий ваше возвращаемое значение, отфильтрованное через `response_model`.
-Вы также можете объявить параметр типа Response в зависимостях и устанавливать cookies (и заголовки) там.
+Вы также можете объявить параметр типа `Response` в зависимостях и устанавливать cookies (и HTTP-заголовки) там.
-## Возвращение `Response` напрямую
+## Возвращение `Response` напрямую { #return-a-response-directly }
-Вы также можете установить cookies, если возвращаете `Response` напрямую в вашем коде.
+Вы также можете установить Cookies, если возвращаете `Response` напрямую в вашем коде.
-Для этого создайте объект `Response`, как описано в разделе [Возвращение ответа напрямую](response-directly.md){.target=_blank}.
+Для этого создайте объект `Response`, как описано в разделе [Возвращение ответа напрямую](response-directly.md){.internal-link target=_blank}.
Затем установите cookies и верните этот объект:
{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *}
-/// tip | Примечание
-Имейте в виду, что если вы возвращаете ответ напрямую, вместо использования параметра `Response`, **FastAPI** отправит его без дополнительной обработки.
+/// tip | Совет
+
+Имейте в виду, что если вы возвращаете ответ напрямую, вместо использования параметра `Response`, FastAPI вернёт его напрямую.
-УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о ваÑ\88и даннÑ\8bе имеÑ\8eÑ\82 коÑ\80Ñ\80екÑ\82нÑ\8bй Ñ\82ип. Ð\9dапÑ\80имеÑ\80, они должнÑ\8b бÑ\8bÑ\82Ñ\8c Ñ\81овмеÑ\81Ñ\82имÑ\8b Ñ\81 JSON, еÑ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83ете `JSONResponse`.
+УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о ваÑ\88и даннÑ\8bе имеÑ\8eÑ\82 коÑ\80Ñ\80екÑ\82нÑ\8bй Ñ\82ип. Ð\9dапÑ\80имеÑ\80, они должнÑ\8b бÑ\8bÑ\82Ñ\8c Ñ\81овмеÑ\81Ñ\82имÑ\8b Ñ\81 JSON, еÑ\81ли вÑ\8b возвÑ\80аÑ\89аете `JSONResponse`.
Также убедитесь, что вы не отправляете данные, которые должны были быть отфильтрованы через `response_model`.
+
///
-### Дополнительная информация
+### Дополнительная информация { #more-info }
/// note | Технические детали
+
Вы также можете использовать `from starlette.responses import Response` или `from starlette.responses import JSONResponse`.
**FastAPI** предоставляет `fastapi.responses`, которые являются теми же объектами, что и `starlette.responses`, просто для удобства. Однако большинство доступных типов ответов поступает непосредственно из **Starlette**.
-Для установки заголовков и cookies `Response` используется часто, поэтому **FastAPI** также предоставляет его через `fastapi.responses`.
+И так как `Response` часто используется для установки HTTP-заголовков и cookies, **FastAPI** также предоставляет его как `fastapi.Response`.
+
///
Чтобы увидеть все доступные параметры и настройки, ознакомьтесь с <a href="https://www.starlette.io/responses/#set-cookie" class="external-link" target="_blank">документацией Starlette</a>.
-# Возврат ответа напрямую
+# Возврат ответа напрямую { #return-a-response-directly }
Когда вы создаёте **FastAPI** *операцию пути*, вы можете возвращать из неё любые данные: `dict`, `list`, Pydantic-модель, модель базы данных и т.д.
Но вы можете возвращать `JSONResponse` напрямую из ваших *операций пути*.
-Это может быть полезно, например, если нужно вернуть пользовательские заголовки или куки.
+Это может быть полезно, например, если нужно вернуть пользовательские HTTP-заголовки или cookie.
-## Возврат `Response`
+## Возврат `Response` { #return-a-response }
На самом деле, вы можете возвращать любой объект `Response` или его подкласс.
Это даёт вам большую гибкость. Вы можете возвращать любые типы данных, переопределять любые объявления или валидацию данных и т.д.
-## Использование `jsonable_encoder` в `Response`
+## Использование `jsonable_encoder` в `Response` { #using-the-jsonable-encoder-in-a-response }
Поскольку **FastAPI** не изменяет объект `Response`, который вы возвращаете, вы должны убедиться, что его содержимое готово к отправке.
///
-## Возврат пользовательского `Response`
+## Возврат пользовательского `Response` { #returning-a-custom-response }
Пример выше показывает все необходимые части, но он пока не очень полезен, так как вы могли бы просто вернуть `item` напрямую, и **FastAPI** поместил бы его в `JSONResponse`, преобразовав в `dict` и т.д. Всё это происходит по умолчанию.
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
-## Примечания
+## Примечания { #notes }
Когда вы возвращаете объект `Response` напрямую, его данные не валидируются, не преобразуются (не сериализуются) и не документируются автоматически.
-# Веб-сокеты
+# Веб-сокеты { #websockets }
Вы можете использовать <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">веб-сокеты</a> в **FastAPI**.
-## Установка `WebSockets`
+## Установка `websockets` { #install-websockets }
-Убедитесь, что [виртуальная среда](../virtual-environments.md){.internal-link target=_blank} создана, активируйте её и установите `websockets`:
+Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его и установили `websockets` (библиотека Python, упрощающая работу с протоколом "WebSocket"):
<div class="termy">
</div>
-## Клиент WebSockets
+## Клиент WebSockets { #websockets-client }
-### РабоÑ\87ее пÑ\80иложение
+### Ð\92 пÑ\80одакÑ\88н { #in-production }
-СкоÑ\80ее вÑ\81его, в ваÑ\88ей Ñ\80еалÑ\8cной пÑ\80одÑ\83кÑ\82овой Ñ\81иÑ\81Ñ\82еме еÑ\81Ñ\82Ñ\8c Ñ\84Ñ\80онÑ\82енд, Ñ\80еализованнÑ\8bй пÑ\80и помоÑ\89и Ñ\81овÑ\80еменнÑ\8bÑ\85 Ñ\84Ñ\80еймвоÑ\80ков React, Vue.js или Angular.
+Ð\92 пÑ\80одакÑ\88н Ñ\83 ваÑ\81, веÑ\80оÑ\8fÑ\82но, еÑ\81Ñ\82Ñ\8c Ñ\84Ñ\80онÑ\82енд, Ñ\81озданнÑ\8bй Ñ\81 помоÑ\89Ñ\8cÑ\8e Ñ\81овÑ\80еменного Ñ\84Ñ\80еймвоÑ\80ка вÑ\80оде React, Vue.js или Angular.
-Ð\98 навеÑ\80нÑ\8fка длÑ\8f взаимодейÑ\81Ñ\82виÑ\8f Ñ\81 бекендом Ñ\87еÑ\80ез веб-Ñ\81океÑ\82Ñ\8b вÑ\8b бÑ\83деÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81Ñ\80едÑ\81Ñ\82ва фронтенда.
+Ð\98 длÑ\8f взаимодейÑ\81Ñ\82виÑ\8f Ñ\81 бекендом по WebSocket вÑ\8b, Ñ\81коÑ\80ее вÑ\81его, бÑ\83деÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b ваÑ\88его фронтенда.
-Также у вас может быть нативное мобильное приложение, коммуницирующее непосредственно с веб-сокетами на бекенд-сервере.
+Также у вас может быть нативное мобильное приложение, которое напрямую, нативным кодом, взаимодействует с вашим WebSocket-бекендом.
-Либо вы можете сделать какой-либо другой способ взаимодействия с веб-сокетами.
+Либо у вас может быть любой другой способ взаимодействия с WebSocket-эндпоинтом.
---
-Но для этого примера мы воспользуемся очень простым HTML документом с небольшими вставками JavaScript кода.
+Но для этого примера мы воспользуемся очень простым HTML‑документом с небольшим JavaScript, всё внутри одной длинной строки.
-Конечно же это неоптимально, и на практике так делать не стоит.
+Конечно же, это неоптимально, и вы бы не использовали это в продакшн.
-В реальных приложениях стоит воспользоваться одним из вышеупомянутых способов.
+В продакшн у вас был бы один из вариантов выше.
-Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб-сокетов и получить рабочий код:
+Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код:
{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
-## Создание `websocket`
+## Создание `websocket` { #create-a-websocket }
Создайте `websocket` в своем **FastAPI** приложении:
///
-## Ожидание и отправка сообщений
+## Ожидание и отправка сообщений { #await-for-messages-and-send-messages }
Через эндпоинт веб-сокета вы можете получать и отправлять сообщения.
Вы можете получать и отправлять двоичные, текстовые и JSON данные.
-## Проверка в действии
+## Проверка в действии { #try-it }
Если ваш файл называется `main.py`, то запустите приложение командой:
И все они будут использовать одно и то же веб-сокет соединение.
-## Использование `Depends` и не только
+## Использование `Depends` и не только { #using-depends-and-others }
Вы можете импортировать из `fastapi` и использовать в эндпоинте вебсокета:
///
-### Веб-сокеты с зависимостями: проверка в действии
+### Веб-сокеты с зависимостями: проверка в действии { #try-the-websockets-with-dependencies }
Если ваш файл называется `main.py`, то запустите приложение командой:
<img src="/img/tutorial/websockets/image05.png">
-## Обработка отключений и работа с несколькими клиентами
+## Обработка отключений и работа с несколькими клиентами { #handling-disconnections-and-multiple-clients }
Если веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере:
Client #1596980209979 left the chat
```
-/// tip | Примечание
+/// tip | Подсказка
Приложение выше - это всего лишь простой минимальный пример, демонстрирующий обработку и передачу сообщений нескольким веб-сокет соединениям.
///
-## Дополнительная информация
+## Дополнительная информация { #more-info }
Для более глубокого изучения темы воспользуйтесь документацией Starlette:
-# Альтернативы, источники вдохновения и сравнения
+# Альтернативы, источники вдохновения и сравнения { #alternatives-inspiration-and-comparisons }
-Что вдохновило на создание **FastAPI**, сравнение его с альтернативами и чему он научился у них.
+Что вдохновило **FastAPI**, сравнение с альтернативами и чему он у них научился.
-## Введение
+## Введение { #intro }
-**FastAPI** не существовал бы, если б не было более ранних работ других людей.
+**FastAPI** не существовал бы без предыдущих работ других людей.
-Ð\9eни Ñ\81оздали болÑ\8cÑ\88ое колиÑ\87еÑ\81Ñ\82во инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе вдоÑ\85новили менÑ\8f на Ñ\81оздание **FastAPI**.
+Ð\91Ñ\8bло Ñ\81оздано множеÑ\81Ñ\82во инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе вдоÑ\85новили на его поÑ\8fвление.
-Я всячески избегал создания нового фреймворка в течение нескольких лет.
-Сначала я пытался собрать все нужные функции, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов.
+Я несколько лет избегал создания нового фреймворка. Сначала пытался закрыть все возможности, которые сейчас предоставляет **FastAPI**, с помощью множества разных фреймворков, плагинов и инструментов.
-Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти функции сразу.
-Взять самые лучшие идеи из предыдущих инструментов и, используя новые возможности Python (которых не было до версии 3.6, то есть подсказки типов), объединить их.
+Но в какой-то момент не осталось другого варианта, кроме как создать что-то, что включает все эти возможности, взяв лучшие идеи из прежних инструментов и совместив их максимально удачным образом, используя возможности языка, которых прежде не было (аннотации типов в Python 3.6+).
-## Предшествующие инструменты
+## Предшествующие инструменты { #previous-tools }
-### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a>
+### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a> { #django }
-Это самый популярный Python-фреймворк, и он пользуется доверием.
-Он используется для создания проектов типа Instagram.
+Это самый популярный Python-фреймворк, ему широко доверяют. Он используется для построения систем вроде Instagram.
-Django довольно тесно связан с реляционными базами данных (такими как MySQL или PostgreSQL), потому использовать NoSQL базы данных (например, Couchbase, MongoDB, Cassandra и т.п.) в качестве основного хранилища данных - непросто.
+Он относительно тесно связан с реляционными базами данных (например, MySQL или PostgreSQL), поэтому использовать NoSQL-базу данных (например, Couchbase, MongoDB, Cassandra и т. п.) в качестве основного хранилища не очень просто.
-Он был создан для генерации HTML-страниц на сервере, а не для создания API, используемых современными веб-интерфейсами (React, Vue.js, Angular и т.п.) или другими системами (например, <abbr title="Интернет вещей">IoT</abbr>) взаимодействующими с сервером.
+Он был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами <abbr title="Internet of Things – Интернет вещей">IoT</abbr>), которые с ним общаются.
-### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a>
+### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a> { #django-rest-framework }
-Фреймворк Django REST был создан, как гибкий инструментарий для создания веб-API на основе Django.
+Django REST Framework был создан как гибкий набор инструментов для построения веб-API поверх Django, чтобы улучшить его возможности в части API.
-DRF использовался многими компаниями, включая Mozilla, Red Hat и Eventbrite.
+Он используется многими компаниями, включая Mozilla, Red Hat и Eventbrite.
-ÐÑ\82о бÑ\8bл один из пеÑ\80вÑ\8bÑ\85 пÑ\80имеÑ\80ов **авÑ\82омаÑ\82иÑ\87еÑ\81кого докÑ\83менÑ\82иÑ\80ованиÑ\8f API** и Ñ\8dÑ\82о бÑ\8bла одна из пеÑ\80вÑ\8bÑ\85 идей, вдоÑ\85новивÑ\88иÑ\85 на Ñ\81оздание **FastAPI**.
+ÐÑ\82о бÑ\8bл один из пеÑ\80вÑ\8bÑ\85 пÑ\80имеÑ\80ов **авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ии API**, и именно Ñ\8dÑ\82а идеÑ\8f одной из пеÑ\80вÑ\8bÑ\85 вдоÑ\85новила на «поиÑ\81к» **FastAPI**.
/// note | Заметка
-Django REST Framework был создан Tom Christie.
-Он же создал Starlette и Uvicorn, на которых основан **FastAPI**.
+Django REST Framework был создан Томом Кристи. Он же создал Starlette и Uvicorn, на которых основан **FastAPI**.
///
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\94олжно бÑ\8bÑ\82Ñ\8c авÑ\82омаÑ\82иÑ\87еÑ\81кое Ñ\81оздание докÑ\83менÑ\82аÑ\86ии API Ñ\81 полÑ\8cзоваÑ\82елÑ\8cÑ\81ким веб-инÑ\82еÑ\80Ñ\84ейÑ\81ом.
+Ð\9dалиÑ\87ие полÑ\8cзоваÑ\82елÑ\8cÑ\81кого веб-инÑ\82еÑ\80Ñ\84ейÑ\81а Ñ\81 авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ией API.
///
-### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a>
+### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a> { #flask }
-Flask - это "микрофреймворк", в нём нет интеграции с базами данных и многих других вещей, которые предустановлены в Django.
+Flask — это «микрофреймворк», он не включает интеграции с базами данных и многие другие вещи, которые в Django идут «из коробки».
-Ð\95го пÑ\80оÑ\81Ñ\82оÑ\82а и гибкоÑ\81Ñ\82Ñ\8c даÑ\8eÑ\82 Ñ\88иÑ\80окие возможноÑ\81Ñ\82и, Ñ\82акие как иÑ\81полÑ\8cзование баз даннÑ\8bÑ\85 NoSQL в качестве основной системы хранения данных.
+ÐÑ\82а пÑ\80оÑ\81Ñ\82оÑ\82а и гибкоÑ\81Ñ\82Ñ\8c позволÑ\8fеÑ\82, напÑ\80имеÑ\80, иÑ\81полÑ\8cзоваÑ\82Ñ\8c NoSQL-базÑ\8b в качестве основной системы хранения данных.
-Ð\9eн оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82, его изÑ\83Ñ\87ение инÑ\82Ñ\83иÑ\82ивно понÑ\8fÑ\82но, Ñ\85оÑ\82Ñ\8f в некоÑ\82оÑ\80Ñ\8bÑ\85 меÑ\81Ñ\82аÑ\85 документация довольно техническая.
+Ð\9eн оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82, его оÑ\82ноÑ\81иÑ\82елÑ\8cно легко инÑ\82Ñ\83иÑ\82ивно оÑ\81воиÑ\82Ñ\8c, Ñ\85оÑ\82Ñ\8f меÑ\81Ñ\82ами документация довольно техническая.
-Flask часто используется и для приложений, которым не нужна база данных, настройки прав доступа для пользователей и прочие из множества функций, предварительно встроенных в Django.
-Хотя многие из этих функций могут быть добавлены с помощью плагинов.
+Его также часто используют для приложений, которым не нужна база данных, управление пользователями или многие другие функции, предварительно встроенные в Django. Хотя многие из этих возможностей можно добавить плагинами.
-Такое Ñ\80азделение на Ñ\87аÑ\81Ñ\82и и Ñ\82о, Ñ\87Ñ\82о Ñ\8dÑ\82о "микÑ\80оÑ\84Ñ\80еймвоÑ\80к", коÑ\82оÑ\80Ñ\8bй можно Ñ\80аÑ\81Ñ\88иÑ\80иÑ\82Ñ\8c, добавлÑ\8fÑ\8f необÑ\85одимÑ\8bе возможноÑ\81Ñ\82и, бÑ\8bло клÑ\8eÑ\87евой оÑ\81обенноÑ\81Ñ\82Ñ\8cÑ\8e, коÑ\82оÑ\80Ñ\83Ñ\8e Ñ\8f Ñ\85оÑ\82ел сохранить.
+Такое Ñ\80азбиение на Ñ\87аÑ\81Ñ\82и и Ñ\82о, Ñ\87Ñ\82о Ñ\8dÑ\82о «микÑ\80оÑ\84Ñ\80еймвоÑ\80к», коÑ\82оÑ\80Ñ\8bй можно Ñ\80аÑ\81Ñ\88иÑ\80Ñ\8fÑ\82Ñ\8c Ñ\80овно под нÑ\83ждÑ\8b, â\80\94 клÑ\8eÑ\87еваÑ\8f оÑ\81обенноÑ\81Ñ\82Ñ\8c, коÑ\82оÑ\80Ñ\83Ñ\8e Ñ\85оÑ\82елоÑ\81Ñ\8c сохранить.
-Простота Flask, показалась мне подходящей для создания API.
-Но ещё нужно было найти "Django REST Framework" для Flask.
+С учётом простоты Flask он казался хорошим вариантом для создания API. Следующим было найти «Django REST Framework» для Flask.
-/// check | Ð\98деи длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-ÐÑ\82о бÑ\83деÑ\82 микÑ\80оÑ\84Ñ\80еймвоÑ\80к. Ð\9a немÑ\83 легко бÑ\83деÑ\82 добавиÑ\82Ñ\8c необÑ\85одимÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b и Ñ\87аÑ\81Ñ\82и.
+Ð\91Ñ\8bÑ\82Ñ\8c микÑ\80о-Ñ\84Ñ\80еймвоÑ\80ком. Ð\9eблегÑ\87иÑ\82Ñ\8c комбиниÑ\80ование необÑ\85одимÑ\8bÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов и компоненÑ\82ов.
-Ð\94олжна бÑ\8bÑ\82Ñ\8c пÑ\80оÑ\81Ñ\82аÑ\8f и лÑ\91гкаÑ\8f в иÑ\81полÑ\8cзовании Ñ\81иÑ\81Ñ\82ема маÑ\80Ñ\88Ñ\80Ñ\83Ñ\82изаÑ\86ии запÑ\80оÑ\81ов.
+Ð\98меÑ\82Ñ\8c пÑ\80оÑ\81Ñ\82Ñ\83Ñ\8e и Ñ\83добнÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 маÑ\80Ñ\88Ñ\80Ñ\83Ñ\82изаÑ\86ии.
///
-### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a>
+### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a> { #requests }
-На самом деле **FastAPI** не является альтернативой **Requests**.
-Их область применения очень разная.
+**FastAPI** на самом деле не альтернатива **Requests**. Их области применения очень различны.
-Ð\92 пÑ\80инÑ\86ипе, можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c Requests *внÑ\83Ñ\82Ñ\80и* приложения FastAPI.
+Ð\9eбÑ\8bÑ\87но Requests иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 даже внÑ\83Ñ\82Ñ\80и приложения FastAPI.
-Ð\9dо вÑ\81Ñ\91 же Ñ\8f иÑ\81полÑ\8cзовал в FastAPI некоÑ\82оÑ\80Ñ\8bе идеи из Requests.
+Ð\98 вÑ\81Ñ\91 же **FastAPI** во многом вдоÑ\85новлÑ\8fлÑ\81Ñ\8f Requests.
-**Requests** - это библиотека для взаимодействия с API в качестве клиента,
-в то время как **FastAPI** - это библиотека для *создания* API (то есть сервера).
+**Requests** — это библиотека для взаимодействия с API (как клиент), а **FastAPI** — библиотека для создания API (как сервер).
-Они, так или иначе, диаметрально противоположны и дополняют друг друга.
+Они, в каком-то смысле, находятся на противоположных концах и дополняют друг друга.
-Requests имеет очень простой и понятный дизайн, очень прост в использовании и имеет разумные значения по умолчанию.
-И в то же время он очень мощный и настраиваемый.
+Requests имеет очень простой и понятный дизайн, им очень легко пользоваться, есть разумные значения по умолчанию. И при этом он очень мощный и настраиваемый.
-Ð\92оÑ\82 поÑ\87емÑ\83 на оÑ\84иÑ\86иалÑ\8cном Ñ\81айÑ\82е напиÑ\81ано:
+Ð\98менно поÑ\8dÑ\82омÑ\83 на оÑ\84иÑ\86иалÑ\8cном Ñ\81айÑ\82е Ñ\81казано:
-> Requests - один из самых загружаемых пакетов Python всех времен
+> Requests — один из самых загружаемых Python-пакетов всех времён
-
-Использовать его очень просто. Например, чтобы выполнить запрос `GET`, Вы бы написали:
+Пользоваться им очень просто. Например, чтобы сделать запрос `GET`, вы бы написали:
```Python
response = requests.get("http://example.com/some/url")
```
-Ð\9fÑ\80оÑ\82ивоположнаÑ\8f *опеÑ\80аÑ\86иÑ\8f пÑ\83Ñ\82и* в FastAPI можеÑ\82 вÑ\8bглÑ\8fдеÑ\82Ñ\8c Ñ\81ледÑ\83Ñ\8eÑ\89им обÑ\80азом:
+СооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89аÑ\8f в FastAPI API-опеÑ\80аÑ\86иÑ\8f пÑ\83Ñ\82и могла бÑ\8b вÑ\8bглÑ\8fдеÑ\82Ñ\8c Ñ\82ак:
```Python hl_lines="1"
@app.get("/some/url")
return {"message": "Hello World"}
```
-Ð\93лÑ\8fдиÑ\82е, как поÑ\85оже `requests.get(...)` и `@app.get(...)`.
+Ð\9fоÑ\81моÑ\82Ñ\80иÑ\82е, наÑ\81колÑ\8cко поÑ\85ожи `requests.get(...)` и `@app.get(...)`.
-/// check | Ð\98деи длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-* Ð\94олжен бÑ\8bть простой и понятный API.
-* Ð\9dÑ\83жно иÑ\81полÑ\8cзоваÑ\82Ñ\8c названиÑ\8f HTTP-меÑ\82одов (опеÑ\80аÑ\86ий) длÑ\8f Ñ\83пÑ\80оÑ\89ениÑ\8f пониманиÑ\8f пÑ\80оиÑ\81Ñ\85одÑ\8fÑ\89его.
-* Ð\94олжнÑ\8b бÑ\8bÑ\82Ñ\8c Ñ\80азÑ\83мнÑ\8bе наÑ\81Ñ\82Ñ\80ойки по Ñ\83молÑ\87аниÑ\8e и Ñ\88иÑ\80окие возможноÑ\81Ñ\82и иÑ\85 каÑ\81Ñ\82омизаÑ\86ии.
+* Ð\98меть простой и понятный API.
+* Ð\98Ñ\81полÑ\8cзоваÑ\82Ñ\8c названиÑ\8f HTTP-меÑ\82одов (опеÑ\80аÑ\86ий) напÑ\80Ñ\8fмÑ\83Ñ\8e, пÑ\80оÑ\81Ñ\82Ñ\8bм и инÑ\82Ñ\83иÑ\82ивнÑ\8bм обÑ\80азом.
+* Ð\98меÑ\82Ñ\8c Ñ\80азÑ\83мнÑ\8bе знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e, но и моÑ\89нÑ\8bе наÑ\81Ñ\82Ñ\80ойки.
///
-### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a>
+### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a> { #swagger-openapi }
-Главной функцией, которую я хотел унаследовать от Django REST Framework, была автоматическая документация API.
+Главной возможностью, которую хотелось взять из Django REST Framework, была автоматическая документация API.
-Ð\9dо поÑ\82ом Ñ\8f обнаÑ\80Ñ\83жил, Ñ\87Ñ\82о Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 Ñ\81Ñ\82андаÑ\80Ñ\82 докÑ\83менÑ\82иÑ\80ованиÑ\8f API, иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\89ий JSON (или YAML, Ñ\80аÑ\81Ñ\88иÑ\80ение JSON) под названием Swagger.
+Ð\97аÑ\82ем Ñ\8f обнаÑ\80Ñ\83жил, Ñ\87Ñ\82о еÑ\81Ñ\82Ñ\8c Ñ\81Ñ\82андаÑ\80Ñ\82 длÑ\8f докÑ\83менÑ\82иÑ\80ованиÑ\8f API Ñ\81 иÑ\81полÑ\8cзованием JSON (или YAML â\80\94 Ñ\80аÑ\81Ñ\88иÑ\80ениÑ\8f JSON), под названием Swagger.
-И к нему уже был создан пользовательский веб-интерфейс.
-Таким образом, возможность генерировать документацию Swagger для API позволила бы использовать этот интерфейс.
+И уже существовал веб-интерфейс для Swagger API. Поэтому возможность генерировать документацию Swagger для API позволила бы автоматически использовать этот веб-интерфейс.
В какой-то момент Swagger был передан Linux Foundation и переименован в OpenAPI.
-Ð\92оÑ\82 поÑ\87емÑ\83, когда говоÑ\80Ñ\8fÑ\82 о веÑ\80Ñ\81ии 2.0, обÑ\8bÑ\87но говоÑ\80Ñ\8fÑ\82 "Swagger", а длÑ\8f веÑ\80Ñ\81ии 3+ "OpenAPI".
+Ð\92оÑ\82 поÑ\87емÑ\83, говоÑ\80Ñ\8f о веÑ\80Ñ\81ии 2.0, обÑ\8bÑ\87но говоÑ\80Ñ\8fÑ\82 «Swagger», а о веÑ\80Ñ\81ии 3+ â\80\94 «OpenAPI».
-/// check | Ð\98деи длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\98Ñ\81полÑ\8cзоваÑ\82Ñ\8c оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8bе Ñ\81Ñ\82андаÑ\80Ñ\82Ñ\8b длÑ\8f Ñ\81пеÑ\86иÑ\84икаÑ\86ий API вмеÑ\81Ñ\82о Ñ\81амоделÑ\8cнÑ\8bÑ\85 Ñ\81Ñ\85ем.
+Ð\98Ñ\81полÑ\8cзоваÑ\82Ñ\8c оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8bй Ñ\81Ñ\82андаÑ\80Ñ\82 длÑ\8f Ñ\81пеÑ\86иÑ\84икаÑ\86ий API вмеÑ\81Ñ\82о Ñ\81амоделÑ\8cной Ñ\81Ñ\85емÑ\8b.
-СовмеÑ\81Ñ\82имоÑ\81Ñ\82Ñ\8c Ñ\81 оÑ\81нованнÑ\8bми на Ñ\81Ñ\82андаÑ\80Ñ\82аÑ\85 полÑ\8cзоваÑ\82елÑ\8cÑ\81кими инÑ\82еÑ\80Ñ\84ейÑ\81ами:
+Ð\98 инÑ\82егÑ\80иÑ\80оваÑ\82Ñ\8c оÑ\81нованнÑ\8bе на Ñ\81Ñ\82андаÑ\80Ñ\82аÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b полÑ\8cзоваÑ\82елÑ\8cÑ\81кого инÑ\82еÑ\80Ñ\84ейÑ\81а:
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>
-Они были выбраны за популярность и стабильность.
-Но сделав беглый поиск, Вы можете найти десятки альтернативных пользовательских интерфейсов для OpenAPI, которые Вы можете использовать с **FastAPI**.
+Эти два инструмента выбраны за популярность и стабильность, но даже при беглом поиске можно найти десятки альтернативных интерфейсов для OpenAPI (которые можно использовать с **FastAPI**).
///
-### REST фреймворки для Flask
+### REST-фреймворки для Flask { #flask-rest-frameworks }
-Существует несколько REST фреймворков для Flask, но потратив время и усилия на их изучение, я обнаружил, что многие из них не обновляются или заброшены и имеют нерешённые проблемы из-за которых они непригодны к использованию.
+Существует несколько REST-фреймворков для Flask, но, вложив время и усилия в исследование, я обнаружил, что многие из них прекращены или заброшены, с несколькими нерешёнными Issue (тикет\обращение), из-за которых они непригодны.
-### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a>
+### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
-Одной из основных функций, необходимых системам API, является "<abbr title="также называют маршаллингом или преобразованием">сериализация</abbr>" данных, то есть преобразование данных из кода (Python) во что-то, что может быть отправлено по сети.
-Например, превращение объекта содержащего данные из базы данных в объект JSON, конвертация объекта `datetime` в строку и т.п.
+Одна из основных возможностей, нужных системам API, — «<abbr title="также называемая маршаллингом или преобразованием">сериализация</abbr>» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п.
-Еще одна важная функция, необходимая API — проверка данных, позволяющая убедиться, что данные действительны и соответствуют заданным параметрам.
-Как пример, можно указать, что ожидаются данные типа `int`, а не какая-то произвольная строка.
-Это особенно полезно для входящих данных.
+Ещё одна важная возможность, востребованная API, — валидация данных: убеждаться, что данные валидны с учётом заданных параметров. Например, что какое-то поле — `int`, а не произвольная строка. Это особенно полезно для входящих данных.
-Ð\91ез Ñ\81иÑ\81Ñ\82емÑ\8b пÑ\80овеÑ\80ки даннÑ\8bÑ\85 Ð\92ам пÑ\80иÑ\88лоÑ\81Ñ\8c бÑ\8b пÑ\80опиÑ\81Ñ\8bваÑ\82Ñ\8c вÑ\81е пÑ\80овеÑ\80ки вÑ\80Ñ\83Ñ\87нÑ\83Ñ\8e.
+Ð\91ез Ñ\81иÑ\81Ñ\82емÑ\8b валидаÑ\86ии даннÑ\8bÑ\85 вам пÑ\80иÑ\88лоÑ\81Ñ\8c бÑ\8b вÑ\8bполнÑ\8fÑ\82Ñ\8c вÑ\81е пÑ\80овеÑ\80ки вÑ\80Ñ\83Ñ\87нÑ\83Ñ\8e в коде.
-Именно для обеспечения этих функций и была создана Marshmallow.
-Это отличная библиотека и я много раз пользовался ею раньше.
+Именно для этих возможностей и был создан Marshmallow. Это отличная библиотека, я много ей пользовался раньше.
-Но она была создана до того, как появились подсказки типов Python.
-Итак, чтобы определить каждую <abbr title="Формат данных">схему</abbr>,
-Вам нужно использовать определенные утилиты и классы, предоставляемые Marshmallow.
+Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой <abbr title="описание того, как данные должны быть сформированы">схемы</abbr> нужно использовать специальные утилиты и классы, предоставляемые Marshmallow.
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\98Ñ\81полÑ\8cзоваÑ\82Ñ\8c код пÑ\80огÑ\80аммÑ\8b длÑ\8f авÑ\82омаÑ\82иÑ\87еÑ\81кого Ñ\81озданиÑ\8f "Ñ\81Ñ\85ем", опÑ\80еделÑ\8fÑ\8eÑ\89иÑ\85 Ñ\82ипÑ\8b даннÑ\8bÑ\85 и иÑ\85 пÑ\80овеÑ\80кÑ\83.
+Ð\98Ñ\81полÑ\8cзоваÑ\82Ñ\8c код длÑ\8f авÑ\82омаÑ\82иÑ\87еÑ\81кого опÑ\80еделениÑ\8f «Ñ\81Ñ\85ем», задаÑ\8eÑ\89иÑ\85 Ñ\82ипÑ\8b даннÑ\8bÑ\85 и иÑ\85 валидаÑ\86иÑ\8e.
///
-### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a>
+### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
-Ð\94Ñ\80Ñ\83гаÑ\8f немаловажнаÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f API - <abbr title="Ñ\87Ñ\82ение и пÑ\80еобÑ\80азование даннÑ\8bÑ\85 в обÑ\8aекÑ\82Ñ\8b Python">паÑ\80Ñ\81инг</abbr> даннÑ\8bÑ\85 из вÑ\85одÑ\8fÑ\89иÑ\85 запросов.
+Ð\95Ñ\89Ñ\91 одна важнаÑ\8f возможноÑ\81Ñ\82Ñ\8c длÑ\8f API â\80\94 <abbr title="Ñ\87Ñ\82ение и пÑ\80еобÑ\80азование даннÑ\8bÑ\85 в обÑ\8aекÑ\82Ñ\8b Python">паÑ\80Ñ\81инг</abbr> даннÑ\8bÑ\85 из вÑ\85одÑ\8fÑ\89иÑ\85 HTTP-запросов.
-Webargs - это инструмент, который был создан для этого и поддерживает несколько фреймворков, включая Flask.
+Webargs — это инструмент, созданный для этого поверх нескольких фреймворков, включая Flask.
-Ð\94лÑ\8f пÑ\80овеÑ\80ки даннÑ\8bÑ\85 он иÑ\81полÑ\8cзÑ\83еÑ\82 Marshmallow и Ñ\81оздан Ñ\82еми же авÑ\82оÑ\80ами.
+Ð\9eн иÑ\81полÑ\8cзÑ\83еÑ\82 Marshmallow длÑ\8f валидаÑ\86ии даннÑ\8bÑ\85. Ð\98 Ñ\81оздан Ñ\82еми же Ñ\80азÑ\80абоÑ\82Ñ\87иками.
-ÐÑ\82о пÑ\80евоÑ\81Ñ\85однÑ\8bй инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82 и Ñ\8f Ñ\82оже Ñ\87аÑ\81Ñ\82о полÑ\8cзовалÑ\81Ñ\8f им до **FastAPI**.
+ÐÑ\82о оÑ\82лиÑ\87нÑ\8bй инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82, и Ñ\8f Ñ\82оже много им полÑ\8cзовалÑ\81Ñ\8f до поÑ\8fвлениÑ\8f **FastAPI**.
/// info | Информация
-Webargs бы создан разработчиками Marshmallow.
+Webargs был создан теми же разработчиками, что и Marshmallow.
///
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\94олжна бÑ\8bÑ\82Ñ\8c авÑ\82омаÑ\82иÑ\87еÑ\81каÑ\8f пÑ\80овеÑ\80ка вÑ\85однÑ\8bÑ\85 даннÑ\8bÑ\85.
+Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e валидаÑ\86иÑ\8e вÑ\85одÑ\8fÑ\89иÑ\85 даннÑ\8bÑ\85 HTTP-запÑ\80оÑ\81а.
///
-### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a>
+### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a> { #apispec }
-Marshmallow и Webargs оÑ\81Ñ\83Ñ\89еÑ\81Ñ\82влÑ\8fÑ\8eÑ\82 пÑ\80овеÑ\80кÑ\83, анализ и Ñ\81еÑ\80иализаÑ\86иÑ\8e даннÑ\8bÑ\85 как плагины.
+Marshmallow и Webargs пÑ\80едоÑ\81Ñ\82авлÑ\8fÑ\8eÑ\82 валидаÑ\86иÑ\8e, паÑ\80Ñ\81инг и Ñ\81еÑ\80иализаÑ\86иÑ\8e как плагины.
-Но документации API всё ещё не было. Тогда был создан APISpec.
+Но документации всё ещё не было. Тогда появился APISpec.
-ÐÑ\82о плагин длÑ\8f множеÑ\81Ñ\82ва Ñ\84Ñ\80еймвоÑ\80ков, в Ñ\82ом Ñ\87иÑ\81ле и длÑ\8f Starlette.
+ÐÑ\82о плагин длÑ\8f многиÑ\85 Ñ\84Ñ\80еймвоÑ\80ков (еÑ\81Ñ\82Ñ\8c плагин и длÑ\8f Starlette).
-Он работает так - Вы записываете определение схем, используя формат YAML, внутри докстринга каждой функции, обрабатывающей маршрут.
+Он работает так: вы пишете определение схемы в формате YAML внутри докстринга каждой функции, обрабатывающей маршрут.
-Используя эти докстринги, он генерирует схему OpenAPI.
+И он генерирует схемы OpenAPI.
-Так Ñ\8dÑ\82о Ñ\80абоÑ\82аеÑ\82 длÑ\8f Flask, Starlette, Responder и Ñ\82.п.
+Так Ñ\8dÑ\82о Ñ\80абоÑ\82аеÑ\82 во Flask, Starlette, Responder и Ñ\82. д.
-Ð\9dо Ñ\82епеÑ\80Ñ\8c Ñ\83 наÑ\81 возникаеÑ\82 новаÑ\8f пÑ\80облема - налиÑ\87ие поÑ\81Ñ\82оÑ\80оннего микÑ\80о-Ñ\81инÑ\82акÑ\81иÑ\81а внÑ\83Ñ\82Ñ\80и кода Python (болÑ\8cÑ\88ие YAML).
+Ð\9dо Ñ\83 наÑ\81 Ñ\81нова возникаеÑ\82 пÑ\80облема: поÑ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f микÑ\80о-Ñ\81инÑ\82акÑ\81иÑ\81 внÑ\83Ñ\82Ñ\80и Ñ\81Ñ\82Ñ\80оки Python (болÑ\8cÑ\88ой YAML).
-Редактор кода не особо может помочь в такой парадигме.
-А изменив какие-то параметры или схемы для Marshmallow можно забыть отредактировать докстринг с YAML и сгенерированная схема становится недействительной.
+Редактор кода мало чем может помочь. И если мы изменим параметры или схемы Marshmallow и забудем также изменить YAML в докстринге, сгенерированная схема устареет.
/// info | Информация
-APISpec тоже был создан авторами Marshmallow.
+APISpec был создан теми же разработчиками, что и Marshmallow.
///
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\9dеобÑ\85одима поддеÑ\80жка оÑ\82кÑ\80Ñ\8bÑ\82ого Ñ\81Ñ\82андаÑ\80Ñ\82а длÑ\8f API - OpenAPI.
+Ð\9fоддеÑ\80жкÑ\83 оÑ\82кÑ\80Ñ\8bÑ\82ого Ñ\81Ñ\82андаÑ\80Ñ\82а длÑ\8f API â\80\94 OpenAPI.
///
-### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a>
+### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a> { #flask-apispec }
-Это плагин для Flask, который связан с Webargs, Marshmallow и APISpec.
+Это плагин для Flask, который связывает Webargs, Marshmallow и APISpec.
-Ð\9eн полÑ\83Ñ\87аеÑ\82 инÑ\84оÑ\80маÑ\86иÑ\8e оÑ\82 Webargs и Marshmallow, а заÑ\82ем иÑ\81полÑ\8cзÑ\83еÑ\82 APISpec длÑ\8f авÑ\82омаÑ\82иÑ\87еÑ\81кого Ñ\81озданиÑ\8f Ñ\81Ñ\85емÑ\8b OpenAPI.
+Ð\9eн иÑ\81полÑ\8cзÑ\83еÑ\82 инÑ\84оÑ\80маÑ\86иÑ\8e из Webargs и Marshmallow, Ñ\87Ñ\82обÑ\8b авÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80оваÑ\82Ñ\8c Ñ\81Ñ\85емÑ\8b OpenAPI Ñ\81 помоÑ\89Ñ\8cÑ\8e APISpec.
-Это отличный, но крайне недооценённый инструмент.
-Он должен быть более популярен, чем многие плагины для Flask.
-Возможно, это связано с тем, что его документация слишком скудна и абстрактна.
+Отличный и недооценённый инструмент. Он заслуживает большей популярности, чем многие плагины для Flask. Возможно, из-за слишком краткой и абстрактной документации.
-Ð\9eн избавил оÑ\82 необÑ\85одимоÑ\81Ñ\82и пиÑ\81аÑ\82Ñ\8c Ñ\87Ñ\83жеÑ\80однÑ\8bй Ñ\81инÑ\82акÑ\81иÑ\81 YAML внÑ\83Ñ\82Ñ\80и докÑ\81Ñ\82Ñ\80ингов.
+ÐÑ\82о Ñ\80еÑ\88ило пÑ\80облемÑ\83 необÑ\85одимоÑ\81Ñ\82и пиÑ\81аÑ\82Ñ\8c YAML (еÑ\89Ñ\91 один Ñ\81инÑ\82акÑ\81иÑ\81) в докÑ\81Ñ\82Ñ\80ингаÑ\85 Python.
-Такое Ñ\81оÑ\87еÑ\82ание Flask, Flask-apispec, Marshmallow и Webargs бÑ\8bло моим лÑ\8eбимÑ\8bм Ñ\81Ñ\82еком пÑ\80и поÑ\81Ñ\82Ñ\80оении бÑ\8dкенда до поÑ\8fвления **FastAPI**.
+Ð\9aомбинаÑ\86иÑ\8f Flask, Flask-apispec Ñ\81 Marshmallow и Webargs бÑ\8bла моим лÑ\8eбимÑ\8bм бÑ\8dкенд-Ñ\81Ñ\82еком до Ñ\81оздания **FastAPI**.
-Ð\98Ñ\81полÑ\8cзование Ñ\8dÑ\82ого Ñ\81Ñ\82ека пÑ\80ивело к Ñ\81озданиÑ\8e неÑ\81колÑ\8cкиÑ\85 генеÑ\80аÑ\82оÑ\80ов пÑ\80оекÑ\82ов. Я и некоÑ\82оÑ\80Ñ\8bе дÑ\80Ñ\83гие командÑ\8b до Ñ\81иÑ\85 поÑ\80 иÑ\81полÑ\8cзÑ\83ем иÑ\85:
+Ð\95го иÑ\81полÑ\8cзование пÑ\80ивело к Ñ\81озданиÑ\8e неÑ\81колÑ\8cкиÑ\85 full-stack генеÑ\80аÑ\82оÑ\80ов на Flask. ÐÑ\82о оÑ\81новнÑ\8bе Ñ\81Ñ\82еки, коÑ\82оÑ\80Ñ\8bе Ñ\8f (и неÑ\81колÑ\8cко внеÑ\88ниÑ\85 команд) иÑ\81полÑ\8cзовали до Ñ\81иÑ\85 поÑ\80:
* <a href="https://github.com/tiangolo/full-stack" class="external-link" target="_blank">https://github.com/tiangolo/full-stack</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchbase</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchdb" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchdb</a>
-ÐÑ\82и генеÑ\80аÑ\82оÑ\80Ñ\8b пÑ\80оекÑ\82ов Ñ\82акже Ñ\81Ñ\82али оÑ\81новой длÑ\8f [Ð\93енеÑ\80аÑ\82оÑ\80ов пÑ\80оекÑ\82ов Ñ\81 **FastAPI**](project-generation.md){.internal-link target=_blank}.
+Ð\98 Ñ\8dÑ\82и же full-stack генеÑ\80аÑ\82оÑ\80Ñ\8b Ñ\81Ñ\82али оÑ\81новой длÑ\8f [Ð\93енеÑ\80аÑ\82оÑ\80ов пÑ\80оекÑ\82ов **FastAPI**](project-generation.md){.internal-link target=_blank}.
/// info | Информация
-Как ни странно, но Flask-apispec тоже создан авторами Marshmallow.
+Flask-apispec был создан теми же разработчиками, что и Marshmallow.
///
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-СÑ\85ема OpenAPI должна Ñ\81оздаваÑ\82Ñ\8cÑ\81Ñ\8f авÑ\82омаÑ\82иÑ\87еÑ\81ки и иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82оÑ\82 же код, коÑ\82оÑ\80Ñ\8bй оÑ\81Ñ\83Ñ\89еÑ\81Ñ\82влÑ\8fеÑ\82 Ñ\81еÑ\80иализаÑ\86иÑ\8e и пÑ\80овеÑ\80кÑ\83 даннÑ\8bÑ\85.
+Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e генеÑ\80аÑ\86иÑ\8e Ñ\81Ñ\85емÑ\8b OpenAPI из Ñ\82ого же кода, коÑ\82оÑ\80Ñ\8bй опÑ\80еделÑ\8fеÑ\82 Ñ\81еÑ\80иализаÑ\86иÑ\8e и валидаÑ\86иÑ\8e.
///
-### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (и <a href="https://angular.io/" class="external-link" target="_blank">Angular</a>)
+### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (и <a href="https://angular.io/" class="external-link" target="_blank">Angular</a>) { #nestjs-and-angular }
-Ð\97деÑ\81Ñ\8c даже не иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f Python. NestJS - Ñ\8dÑ\82оÑ\82 Ñ\84Ñ\80еймвоÑ\80к напиÑ\81аннÑ\8bй на JavaScript (TypeScript), оÑ\81нованнÑ\8bй на NodeJS и вдохновлённый Angular.
+ÐÑ\82о даже не Python. NestJS â\80\94 Ñ\8dÑ\82о JavaScript/TypeScript-Ñ\84Ñ\80еймвоÑ\80к на NodeJS, вдохновлённый Angular.
-Ð\9eн позволÑ\8fеÑ\82 полÑ\83Ñ\87иÑ\82Ñ\8c неÑ\87Ñ\82о поÑ\85ожее на Ñ\82о, Ñ\87Ñ\82о можно Ñ\81делаÑ\82Ñ\8c Ñ\81 помоÑ\89Ñ\8cÑ\8e Flask-apispec.
+Ð\9eн доÑ\81Ñ\82игаеÑ\82 Ñ\87его-Ñ\82о оÑ\82Ñ\87аÑ\81Ñ\82и поÑ\85ожего на Ñ\82о, Ñ\87Ñ\82о можно Ñ\81делаÑ\82Ñ\8c Ñ\81 Flask-apispec.
-В него встроена система внедрения зависимостей, ещё одна идея взятая от Angular.
-Однако требуется предварительная регистрация "внедрений" (как и во всех других известных мне системах внедрения зависимостей), что увеличивает количество и повторяемость кода.
+В нём встроена система внедрения зависимостей, вдохновлённая Angular 2. Требуется предварительная регистрация «инжектируемых» компонентов (как и во всех известных мне системах внедрения зависимостей), что добавляет многословности и повторяемости кода.
-Так как паÑ\80амеÑ\82Ñ\80Ñ\8b в нÑ\91м опиÑ\81Ñ\8bваÑ\8eÑ\82Ñ\81Ñ\8f Ñ\81 помоÑ\89Ñ\8cÑ\8e Ñ\82ипов TypeScript (аналогиÑ\87но подÑ\81казкам Ñ\82ипов в Python), поддеÑ\80жка Ñ\80едакÑ\82оÑ\80а Ñ\80абоÑ\82аеÑ\82 доволÑ\8cно Ñ\85оÑ\80оÑ\88о.
+Ð\9fоÑ\81колÑ\8cкÑ\83 паÑ\80амеÑ\82Ñ\80Ñ\8b опиÑ\81Ñ\8bваÑ\8eÑ\82Ñ\81Ñ\8f Ñ\81 помоÑ\89Ñ\8cÑ\8e Ñ\82ипов TypeScript (аналог анноÑ\82аÑ\86ий Ñ\82ипов в Python), поддеÑ\80жка Ñ\80едакÑ\82оÑ\80а веÑ\81Ñ\8cма Ñ\85оÑ\80оÑ\88а.
-Но поскольку данные из TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на подсказки типов для определения проверки данных, сериализации и документации.
-Из-за этого и некоторых дизайнерских решений, для валидации, сериализации и автоматической генерации схем, приходится во многих местах добавлять декораторы.
-Таким образом, это становится довольно многословным.
+Но так как данные о типах TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на типы для одновременного определения валидации, сериализации и документации. Из‑за этого и некоторых проектных решений для получения валидации, сериализации и автоматической генерации схем приходится добавлять декораторы во многих местах. В итоге это становится довольно многословным.
-Кроме того, он не очень хорошо справляется с вложенными моделями.
-Если в запросе имеется объект JSON, внутренние поля которого, в свою очередь, являются вложенными объектами JSON, это не может быть должным образом задокументировано и проверено.
+Он плохо справляется с вложенными моделями. Если JSON-тело запроса — это объект JSON, содержащий внутренние поля, которые сами являются вложенными объектами JSON, это нельзя как следует задокументировать и провалидировать.
-/// check | Ð\98деи длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\9dÑ\83жно иÑ\81полÑ\8cзоваÑ\82Ñ\8c подÑ\81казки Ñ\82ипов, Ñ\87Ñ\82об воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f поддеÑ\80жкой Ñ\80едакÑ\82оÑ\80а кода.
+Ð\98Ñ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82ипÑ\8b Python длÑ\8f оÑ\82лиÑ\87ной поддеÑ\80жки в Ñ\80едакÑ\82оÑ\80е кода.
-Ð\9dÑ\83жна моÑ\89наÑ\8f Ñ\81иÑ\81Ñ\82ема внедÑ\80ениÑ\8f завиÑ\81имоÑ\81Ñ\82ей. Ð\9dеобÑ\85одим Ñ\81поÑ\81об длÑ\8f Ñ\83менÑ\8cÑ\88ениÑ\8f повÑ\82оÑ\80ов кода.
+Ð\98меÑ\82Ñ\8c моÑ\89нÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 внедÑ\80ениÑ\8f завиÑ\81имоÑ\81Ñ\82ей. Ð\9dайÑ\82и Ñ\81поÑ\81об минимизиÑ\80оваÑ\82Ñ\8c повÑ\82оÑ\80ение кода.
///
-### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a>
+### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a> { #sanic }
-Sanic был одним из первых чрезвычайно быстрых Python-фреймворков основанных на `asyncio`.
-Он был сделан очень похожим на Flask.
+Это был один из первых чрезвычайно быстрых Python-фреймворков на основе `asyncio`. Он был сделан очень похожим на Flask.
/// note | Технические детали
-Ð\92 нÑ\91м иÑ\81полÑ\8cзован <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a> вмеÑ\81Ñ\82о Ñ\81Ñ\82андаÑ\80Ñ\82ного Ñ\86икла Ñ\81обÑ\8bÑ\82ий `asyncio`, Ñ\87то и сделало его таким быстрым.
+Ð\9eн иÑ\81полÑ\8cзовал <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a> вмеÑ\81Ñ\82о Ñ\81Ñ\82андаÑ\80Ñ\82ного Ñ\86икла `asyncio` в Python. Ðто и сделало его таким быстрым.
-Он явно вдохновил создателей Uvicorn и Starlette, которые в настоящее время быстрее Sanic в открытых бенчмарках.
+Он явно вдохновил Uvicorn и Starlette, которые сейчас быстрее Sanic в открытых бенчмарках.
///
-/// check | Ð\98деи длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\94олжна бÑ\8bÑ\82Ñ\8c Ñ\81Ñ\83маÑ\81Ñ\88едÑ\88аÑ\8f пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c.
+Ð\9fоиÑ\81к Ñ\81поÑ\81оба доÑ\81Ñ\82иÑ\87Ñ\8c Ñ\81Ñ\83маÑ\81Ñ\88едÑ\88ей пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и.
-Ð\94лÑ\8f Ñ\8dÑ\82ого **FastAPI** оÑ\81нован на Starlette, Ñ\81амом бÑ\8bÑ\81Ñ\82Ñ\80ом из доÑ\81Ñ\82Ñ\83пнÑ\8bÑ\85 Ñ\84Ñ\80еймвоÑ\80ков (по замеÑ\80ам незаинÑ\82еÑ\80еÑ\81ованнÑ\8bÑ\85 лиÑ\86).
+Ð\98менно поÑ\8dÑ\82омÑ\83 **FastAPI** оÑ\81нован на Starlette, Ñ\82ак как Ñ\8dÑ\82о Ñ\81амÑ\8bй бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bй доÑ\81Ñ\82Ñ\83пнÑ\8bй Ñ\84Ñ\80еймвоÑ\80к (по даннÑ\8bм Ñ\81Ñ\82оÑ\80онниÑ\85 бенÑ\87маÑ\80ков).
///
-### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a>
+### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a> { #falcon }
-Falcon - ещё один высокопроизводительный Python-фреймворк.
-В нём минимум функций и он создан, чтоб быть основой для других фреймворков, например, Hug.
+Falcon — ещё один высокопроизводительный Python-фреймворк, он минималистичен и служит основой для других фреймворков, таких как Hug.
-Функции в нём получают два параметра - "запрос к серверу" и "ответ сервера".
-Затем Вы "читаете" часть запроса и "пишите" часть ответа.
-Из-за такой конструкции невозможно объявить параметры запроса и тела сообщения со стандартными подсказками типов Python в качестве параметров функции.
+Он спроектирован так, что функции получают два параметра: «request» и «response». Затем вы «читаете» части из запроса и «пишете» части в ответ. Из‑за такого дизайна невозможно объявить параметры запроса и тело запроса стандартными аннотациями типов Python как параметры функции.
-Таким образом, и валидацию данных, и их сериализацию, и документацию нужно прописывать вручную.
-Либо эти функции должны быть встроены во фреймворк, сконструированный поверх Falcon, как в Hug.
-Такая же особенность присутствует и в других фреймворках, вдохновлённых идеей Falcon, использовать только один объект запроса и один объект ответа.
+Поэтому валидация данных, сериализация и документация должны выполняться в коде вручную, не автоматически. Либо должны быть реализованы во фреймворке поверх Falcon, как в Hug. Та же особенность есть и в других фреймворках, вдохновлённых дизайном Falcon — с одним объектом запроса и одним объектом ответа в параметрах.
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\9dайдиÑ\82е Ñ\81поÑ\81обÑ\8b добиÑ\82Ñ\8cÑ\81Ñ\8f оÑ\82лиÑ\87ной пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и.
+Ð\9fоиÑ\81к Ñ\81поÑ\81обов полÑ\83Ñ\87иÑ\82Ñ\8c оÑ\82лиÑ\87нÑ\83Ñ\8e пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c.
-Ð\9eбÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80Ñ\8b `оÑ\82веÑ\82а Ñ\81еÑ\80веÑ\80а` в Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85, как в Hug.
+Ð\92меÑ\81Ñ\82е Ñ\81 Hug (Ñ\82ак как Hug оÑ\81нован на Falcon) вдоÑ\85новило **FastAPI** обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `response` в Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85.
-Хотя в FastAPI это необязательно и используется в основном для установки заголовков, куки и альтернативных кодов состояния.
+Хотя в FastAPI это необязательно, и используется в основном для установки HTTP-заголовков, cookie и альтернативных статус-кодов.
///
-### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a>
+### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a> { #molten }
-Molten мне попался на начальной стадии написания **FastAPI**. В нём были похожие идеи:
+Я обнаружил Molten на ранних этапах создания **FastAPI**. И у него были очень похожие идеи:
-* Ð\98Ñ\81полÑ\8cзование подÑ\81казок Ñ\82ипов.
-* Валидация и документация исходя из этих подсказок.
+* Ð\9eÑ\81нован на анноÑ\82аÑ\86иÑ\8fÑ\85 Ñ\82ипов Python.
+* Валидация и документация из этих типов.
* Система внедрения зависимостей.
-В нём не используются сторонние библиотеки (такие, как Pydantic) для валидации, сериализации и документации.
-Поэтому переиспользовать эти определения типов непросто.
+Он не использует стороннюю библиотеку для валидации, сериализации и документации, такую как Pydantic, — у него своя. Поэтому такие определения типов данных будет сложнее переиспользовать.
-Также требуется более подробная конфигурация и используется стандарт WSGI, который не предназначен для использования с высокопроизводительными инструментами, такими как Uvicorn, Starlette и Sanic, в отличие от ASGI.
+Требуются более многословные конфигурации. И так как он основан на WSGI (вместо ASGI), он не предназначен для использования преимуществ высокой производительности инструментов вроде Uvicorn, Starlette и Sanic.
-Его система внедрения зависимостей требует предварительной регистрации, и зависимости определяются, как объявления типов.
-Из-за этого невозможно объявить более одного "компонента" (зависимости), который предоставляет определенный тип.
+Система внедрения зависимостей требует предварительной регистрации зависимостей, а зависимости разрешаются по объявленным типам. Поэтому невозможно объявить более одного «компонента», предоставляющего определённый тип.
-Маршруты объявляются в единственном месте с использованием функций, объявленных в других местах (вместо использования декораторов, в которые могут быть обёрнуты функции, обрабатывающие конкретные ресурсы).
-Это больше похоже на Django, чем на Flask и Starlette.
-Он разделяет в коде вещи, которые довольно тесно связаны.
+Маршруты объявляются в одном месте, используя функции, объявленные в других местах (вместо декораторов, которые можно разместить прямо над функцией, обрабатывающей эндпоинт). Это ближе к тому, как это делает Django, чем Flask (и Starlette). Это разделяет в коде вещи, которые довольно тесно связаны.
-/// check | Ð\98деÑ\8f длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Определить дополнительные проверки типов данных, используя значения атрибутов модели "по умолчанию".
-Это улучшает помощь редактора и раньше это не было доступно в Pydantic.
+Определять дополнительные проверки типов данных, используя значение «по умолчанию» атрибутов модели. Это улучшает поддержку в редакторе кода, и раньше этого не было в Pydantic.
-ФакÑ\82иÑ\87еÑ\81ки Ñ\8dÑ\82о подÑ\82олкнÑ\83ло на обновление Pydantic длÑ\8f поддеÑ\80жки одинакового Ñ\81Ñ\82илÑ\8f пÑ\80овеÑ\80ок (Ñ\82епеÑ\80Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\84Ñ\83нкÑ\86ионал Ñ\83же доÑ\81Ñ\82Ñ\83пен в Pydantic).
+ФакÑ\82иÑ\87еÑ\81ки Ñ\8dÑ\82о вдоÑ\85новило на обновление Ñ\87аÑ\81Ñ\82ей Pydantic, Ñ\87Ñ\82обÑ\8b поддеÑ\80живаÑ\82Ñ\8c Ñ\82акой же Ñ\81Ñ\82илÑ\8c обÑ\8aÑ\8fвлениÑ\8f валидаÑ\86ии (вÑ\81Ñ\8f Ñ\8dÑ\82а Ñ\84Ñ\83нкÑ\86ионалÑ\8cноÑ\81Ñ\82Ñ\8c Ñ\82епеÑ\80Ñ\8c Ñ\83же еÑ\81Ñ\82Ñ\8c в Pydantic).
///
-### <a href="https://github.com/hugapi/hug" class="external-link" target="_blank">Hug</a>
+### <a href="https://github.com/hugapi/hug" class="external-link" target="_blank">Hug</a> { #hug }
-Hug был одним из первых фреймворков, реализовавших объявление параметров API с использованием подсказок типов Python.
-Эта отличная идея была использована и другими инструментами.
+Hug был одним из первых фреймворков, реализовавших объявление типов параметров API с использованием аннотаций типов Python. Это была отличная идея, которая вдохновила и другие инструменты.
-Ð\9fÑ\80и обÑ\8aÑ\8fвлении паÑ\80амеÑ\82Ñ\80ов вмеÑ\81Ñ\82о Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bÑ\85 Ñ\82ипов Python иÑ\81полÑ\8cзовалиÑ\81Ñ\8c Ñ\81обÑ\81Ñ\82веннÑ\8bе Ñ\82ипÑ\8b, но вÑ\81Ñ\91 же Ñ\8dÑ\82о бÑ\8bл огÑ\80омнÑ\8bй Ñ\88аг впеÑ\80ед.
+Ð\9eн иÑ\81полÑ\8cзовал Ñ\81обÑ\81Ñ\82веннÑ\8bе Ñ\82ипÑ\8b в обÑ\8aÑ\8fвлениÑ\8fÑ\85 вмеÑ\81Ñ\82о Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bÑ\85 Ñ\82ипов Python, но Ñ\8dÑ\82о вÑ\81Ñ\91 Ñ\80авно бÑ\8bл огÑ\80омнÑ\8bй Ñ\88аг впеÑ\80Ñ\91д.
-ÐÑ\82о Ñ\82акже бÑ\8bл один из пеÑ\80вÑ\8bÑ\85 Ñ\84Ñ\80еймвоÑ\80ков, генеÑ\80иÑ\80овавÑ\88иÑ\85 полнÑ\83Ñ\8e API-Ñ\81Ñ\85емÑ\83 в Ñ\84оÑ\80маÑ\82е JSON.
+Ð\9eн Ñ\82акже бÑ\8bл одним из пеÑ\80вÑ\8bÑ\85 Ñ\84Ñ\80еймвоÑ\80ков, генеÑ\80иÑ\80овавÑ\88иÑ\85 Ñ\81обÑ\81Ñ\82веннÑ\83Ñ\8e Ñ\81Ñ\85емÑ\83, опиÑ\81Ñ\8bваÑ\8eÑ\89Ñ\83Ñ\8e веÑ\81Ñ\8c API в JSON.
-Данная схема не придерживалась стандартов вроде OpenAPI и JSON Schema.
-Поэтому было бы непросто совместить её с другими инструментами, такими как Swagger UI.
-Но опять же, это была очень инновационная идея.
+Он не был основан на стандартах вроде OpenAPI и JSON Schema. Поэтому интегрировать его с другими инструментами, такими как Swagger UI, было бы непросто. Но, опять же, это была очень инновационная идея.
-Ð\95Ñ\89Ñ\91 Ñ\83 него еÑ\81Ñ\82Ñ\8c инÑ\82еÑ\80еÑ\81наÑ\8f и необÑ\8bÑ\87наÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f: иÑ\81полÑ\8cзÑ\83Ñ\8f один и Ñ\82оÑ\82 же Ñ\84Ñ\80еймвоÑ\80к можно Ñ\81оздаваÑ\82Ñ\8c и API, и <abbr title="Ð\98нÑ\82еÑ\80Ñ\84ейÑ\81 командной Ñ\81Ñ\82Ñ\80оки">CLI</abbr>.
+У него еÑ\81Ñ\82Ñ\8c инÑ\82еÑ\80еÑ\81наÑ\8f и необÑ\8bÑ\87наÑ\8f оÑ\81обенноÑ\81Ñ\82Ñ\8c: Ñ\81 помоÑ\89Ñ\8cÑ\8e одного и Ñ\82ого же Ñ\84Ñ\80еймвоÑ\80ка можно Ñ\81оздаваÑ\82Ñ\8c и API, и CLI.
-Ð\9fоÑ\81колÑ\8cкÑ\83 он оÑ\81нован на WSGI, Ñ\81Ñ\82аÑ\80ом Ñ\81Ñ\82андаÑ\80Ñ\82е длÑ\8f Ñ\81инÑ\85Ñ\80оннÑ\8bÑ\85 веб-Ñ\84Ñ\80еймвоÑ\80ков, он не можеÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 веб-Ñ\81океÑ\82ами и дÑ\80Ñ\83гими моднÑ\8bми Ñ\88Ñ\82Ñ\83ками, но вÑ\81Ñ\91 Ñ\80авно обладаеÑ\82 вÑ\8bÑ\81окой пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8cÑ\8e.
+Так как он оÑ\81нован на пÑ\80едÑ\8bдÑ\83Ñ\89ем Ñ\81Ñ\82андаÑ\80Ñ\82е длÑ\8f Ñ\81инÑ\85Ñ\80оннÑ\8bÑ\85 веб-Ñ\84Ñ\80еймвоÑ\80ков Python (WSGI), он не можеÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 WebSocket и пÑ\80оÑ\87им, Ñ\85оÑ\82Ñ\8f Ñ\82акже демонÑ\81Ñ\82Ñ\80иÑ\80Ñ\83еÑ\82 вÑ\8bÑ\81окÑ\83Ñ\8e пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c.
/// info | Информация
-Hug создан Timothy Crosley, автором <a href="https://github.com/timothycrosley/isort" class="external-link" target="_blank">`isort`</a>, отличного инструмента для автоматической сортировки импортов в Python-файлах.
+Hug был создан Тимоти Кросли, тем же автором <a href="https://github.com/timothycrosley/isort" class="external-link" target="_blank">`isort`</a>, отличного инструмента для автоматической сортировки импортов в файлах Python.
///
-/// check | Идеи для **FastAPI**
+/// check | Идеи, вдохновившие **FastAPI**
-Hug повлиÑ\8fл на Ñ\81оздание некоÑ\82оÑ\80Ñ\8bÑ\85 Ñ\87аÑ\81Ñ\82ей APIStar и бÑ\8bл одним из инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе Ñ\8f Ñ\81Ñ\87ел наиболее многообеÑ\89аÑ\8eÑ\89ими, наряду с APIStar.
+Hug вдоÑ\85новил Ñ\87аÑ\81Ñ\82и APIStar и бÑ\8bл одним из наиболее многообеÑ\89аÑ\8eÑ\89иÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе Ñ\8f наÑ\88Ñ\91л, наряду с APIStar.
-Hug наÑ\82олкнÑ\83л на мÑ\8bÑ\81ли иÑ\81полÑ\8cзоваÑ\82Ñ\8c в **FastAPI** подÑ\81казки Ñ\82ипов Python длÑ\8f авÑ\82омаÑ\82иÑ\87еÑ\81кого Ñ\81озданиÑ\8f Ñ\81Ñ\85емÑ\8b, опÑ\80еделÑ\8fÑ\8eÑ\89ей API и его паÑ\80амеÑ\82Ñ\80Ñ\8b.
+Hug помог вдоÑ\85новиÑ\82Ñ\8c **FastAPI** иÑ\81полÑ\8cзоваÑ\82Ñ\8c анноÑ\82аÑ\86ии Ñ\82ипов Python длÑ\8f обÑ\8aÑ\8fвлениÑ\8f паÑ\80амеÑ\82Ñ\80ов и авÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80оваÑ\82Ñ\8c Ñ\81Ñ\85емÑ\83, опÑ\80еделÑ\8fÑ\8eÑ\89Ñ\83Ñ\8e API.
-Hug вдоÑ\85новил **FastAPI** обÑ\8aÑ\8fвиÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `оÑ\82веÑ\82а` в Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85 длÑ\8f Ñ\83Ñ\81Ñ\82ановки заголовков и кÑ\83ки.
+Hug вдоÑ\85новил **FastAPI** обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `response` в Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85 длÑ\8f Ñ\83Ñ\81Ñ\82ановки HTTP-заголовков и cookie.
///
-### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5)
+### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5) { #apistar-0-5 }
-Непосредственно перед тем, как принять решение о создании **FastAPI**, я обнаружил **APIStar**.
-В нем было почти все, что я искал и у него был отличный дизайн.
+Прямо перед решением строить **FastAPI** я нашёл сервер **APIStar**. В нём было почти всё, что я искал, и отличный дизайн.
-Это была одна из первых реализаций фреймворка, использующего подсказки типов для объявления параметров и запросов, которые я когда-либо видел (до NestJS и Molten).
-Я нашёл его примерно в то же время, что и Hug, но APIStar использовал стандарт OpenAPI.
+Это была одна из первых реализаций фреймворка, использующего аннотации типов Python для объявления параметров и запросов (до NestJS и Molten), которые я видел. Я обнаружил его примерно в то же время, что и Hug. Но APIStar использовал стандарт OpenAPI.
-Ð\92 нÑ\91м бÑ\8bли авÑ\82омаÑ\82иÑ\87еÑ\81кие пÑ\80овеÑ\80ка и Ñ\81еÑ\80иализаÑ\86иÑ\8f даннÑ\8bÑ\85 и генеÑ\80аÑ\86иÑ\8f Ñ\81Ñ\85емÑ\8b OpenAPI оÑ\81нованнÑ\8bе на подÑ\81казкаÑ\85 типов в нескольких местах.
+Ð\92 нÑ\91м бÑ\8bли авÑ\82омаÑ\82иÑ\87еÑ\81кие валидаÑ\86иÑ\8f даннÑ\8bÑ\85, Ñ\81еÑ\80иализаÑ\86иÑ\8f даннÑ\8bÑ\85 и генеÑ\80аÑ\86иÑ\8f Ñ\81Ñ\85емÑ\8b OpenAPI на оÑ\81нове Ñ\82еÑ\85 же анноÑ\82аÑ\86ий типов в нескольких местах.
-Ð\9fÑ\80и опÑ\80еделении Ñ\81Ñ\85емÑ\8b Ñ\82ела Ñ\81ообÑ\89ениÑ\8f не иÑ\81полÑ\8cзовалиÑ\81Ñ\8c подÑ\81казки Ñ\82ипов, как в Pydantic, Ñ\8dÑ\82о болÑ\8cÑ\88е поÑ\85оже на Marshmallow, поÑ\8dÑ\82омÑ\83 помоÑ\89Ñ\8c Ñ\80едакÑ\82оÑ\80а бÑ\8bла недоÑ\81Ñ\82аÑ\82оÑ\87но Ñ\85оÑ\80оÑ\88ей, но вÑ\81Ñ\91 же APIStar бÑ\8bл лучшим доступным вариантом.
+Ð\9eпÑ\80еделение Ñ\81Ñ\85емÑ\8b Ñ\82ела запÑ\80оÑ\81а не иÑ\81полÑ\8cзовало Ñ\82е же анноÑ\82аÑ\86ии Ñ\82ипов Python, как в Pydantic, â\80\94 Ñ\8dÑ\82о бÑ\8bло ближе к Marshmallow, поÑ\8dÑ\82омÑ\83 поддеÑ\80жка Ñ\80едакÑ\82оÑ\80а бÑ\8bла бÑ\8b Ñ\85Ñ\83же, но вÑ\81Ñ\91 Ñ\80авно APIStar оÑ\81Ñ\82авалÑ\81Ñ\8f лучшим доступным вариантом.
-Ð\9dа Ñ\82оÑ\82 моменÑ\82 Ñ\83 него бÑ\8bли лÑ\83Ñ\87Ñ\88ие показаÑ\82ели пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и (пÑ\80оигÑ\80Ñ\8bваÑ\8eÑ\89ие только Starlette).
+Ð\9dа Ñ\82оÑ\82 моменÑ\82 Ñ\83 него бÑ\8bли лÑ\83Ñ\87Ñ\88ие показаÑ\82ели в бенÑ\87маÑ\80каÑ\85 (его пÑ\80евоÑ\81Ñ\85одил только Starlette).
-Ð\98знаÑ\87алÑ\8cно Ñ\83 него не бÑ\8bло авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ии API длÑ\8f веб-инÑ\82еÑ\80Ñ\84ейÑ\81а, но я знал, что могу добавить к нему Swagger UI.
+СнаÑ\87ала Ñ\83 него не бÑ\8bло вебâ\80\91UI длÑ\8f авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ии API, но я знал, что могу добавить к нему Swagger UI.
-В APIStar была система внедрения зависимостей, которая тоже требовала предварительную регистрацию компонентов, как и ранее описанные инструменты.
-Но, тем не менее, это была отличная штука.
+У него была система внедрения зависимостей. Она требовала предварительной регистрации компонентов, как и другие инструменты, обсуждавшиеся выше. Но всё же это была отличная возможность.
-Я не смог использовать его в полноценном проекте, так как были проблемы со встраиванием <abbr title="Авторизация и соответствующие допуски к операциям пути (эндпоинтам)">функций безопасности</abbr> в схему OpenAPI, из-за которых невозможно было встроить все функции, применяемые в генераторах проектов на основе Flask-apispec.
-Я добавил в свой список задач создание пул-реквеста, добавляющего эту функциональность.
+Мне так и не удалось использовать его в полном проекте, поскольку не было интеграции с системой безопасности, поэтому я не мог заменить все возможности, которые имел с full-stack генераторами на основе Flask-apispec. В моём бэклоге было создать пулл-реквест (запрос на изменение), добавляющий эту функциональность.
-Ð\92 далÑ\8cнейÑ\88ем фокус проекта сместился.
+Ð\97аÑ\82ем фокус проекта сместился.
-ÐÑ\82о болÑ\8cÑ\88е не бÑ\8bл API-Ñ\84Ñ\80еймвоÑ\80к, Ñ\82ак как авÑ\82оÑ\80 Ñ\81оÑ\81Ñ\80едоÑ\82оÑ\87ился на Starlette.
+ÐÑ\82о пеÑ\80еÑ\81Ñ\82ал бÑ\8bÑ\82Ñ\8c веб-Ñ\84Ñ\80еймвоÑ\80к длÑ\8f API, Ñ\82ак как авÑ\82оÑ\80Ñ\83 нÑ\83жно бÑ\8bло Ñ\81оÑ\81Ñ\80едоÑ\82оÑ\87иÑ\82Ñ\8cся на Starlette.
-Ð\9dÑ\8bне APIStar - Ñ\8dÑ\82о набоÑ\80 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов длÑ\8f пÑ\80овеÑ\80ки Ñ\81пеÑ\86иÑ\84икаÑ\86ий OpenAPI.
+СейÑ\87аÑ\81 APIStar â\80\94 Ñ\8dÑ\82о набоÑ\80 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов длÑ\8f валидаÑ\86ии Ñ\81пеÑ\86иÑ\84икаÑ\86ий OpenAPI, а не веб-Ñ\84Ñ\80еймвоÑ\80к.
/// info | Информация
-APIStar был создан Tom Christie. Тот самый парень, который создал:
+APIStar был создан Томом Кристи. Тем самым человеком, который создал:
* Django REST Framework
* Starlette (на котором основан **FastAPI**)
-* Uvicorn (используемый в Starlette и **FastAPI**)
+* Uvicorn (используется Starlette и **FastAPI**)
///
-/// check | Ð\98деи длÑ\8f **FastAPI**
+/// check | Ð\92доÑ\85новило **FastAPI** на
-Ð\92оплоÑ\89ение.
+СÑ\83Ñ\89еÑ\81Ñ\82вование.
-Ð\9cне казалоÑ\81Ñ\8c блеÑ\81Ñ\82Ñ\8fÑ\89ей идеей обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c множеÑ\81Ñ\82во Ñ\84Ñ\83нкÑ\86ий (пÑ\80овеÑ\80ка даннÑ\8bÑ\85, Ñ\81еÑ\80иализаÑ\86иÑ\8f, докÑ\83менÑ\82аÑ\86иÑ\8f) Ñ\81 помоÑ\89Ñ\8cÑ\8e одниÑ\85 и Ñ\82еÑ\85 же Ñ\82ипов Python, коÑ\82оÑ\80Ñ\8bе пÑ\80и Ñ\8dÑ\82ом обеÑ\81пеÑ\87иваÑ\8eÑ\82 еÑ\89Ñ\91 и помоÑ\89Ñ\8c Ñ\80едакÑ\82оÑ\80а кода.
+Ð\98деÑ\8f обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c Ñ\81Ñ\80азÑ\83 неÑ\81колÑ\8cко веÑ\89ей (валидаÑ\86иÑ\8e даннÑ\8bÑ\85, Ñ\81еÑ\80иализаÑ\86иÑ\8e и докÑ\83менÑ\82аÑ\86иÑ\8e) Ñ\81 помоÑ\89Ñ\8cÑ\8e одниÑ\85 и Ñ\82еÑ\85 же Ñ\82ипов Python, коÑ\82оÑ\80Ñ\8bе одновÑ\80еменно обеÑ\81пеÑ\87иваÑ\8eÑ\82 оÑ\82лиÑ\87нÑ\83Ñ\8e поддеÑ\80жкÑ\83 в Ñ\80едакÑ\82оÑ\80е кода, показалаÑ\81Ñ\8c мне блеÑ\81Ñ\82Ñ\8fÑ\89ей.
-После долгих поисков среди похожих друг на друга фреймворков и сравнения их различий, APIStar стал самым лучшим выбором.
+После долгих поисков похожего фреймворка и тестирования множества альтернатив APIStar был лучшим доступным вариантом.
-Но APIStar перестал быть фреймворком для создания веб-сервера, зато появился Starlette, новая и лучшая основа для построения подобных систем.
-Это была последняя капля, сподвигнувшая на создание **FastAPI**.
+Затем APIStar перестал существовать как сервер, а был создан Starlette — новая и лучшая основа для такой системы. Это стало окончательным вдохновением для создания **FastAPI**.
-Я считаю **FastAPI** "духовным преемником" APIStar, улучившим его возможности благодаря урокам, извлечённым из всех упомянутых выше инструментов.
+Я считаю **FastAPI** «духовным преемником» APIStar, который улучшает и расширяет возможности, систему типов и другие части, опираясь на уроки от всех этих предыдущих инструментов.
///
-## Что используется в **FastAPI**
+## Что используется в **FastAPI** { #used-by-fastapi }
+
+### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> { #pydantic }
-### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
+Pydantic — это библиотека для определения валидации данных, сериализации и документации (с использованием JSON Schema) на основе аннотаций типов Python.
-Pydantic - это библиотека для валидации данных, сериализации и документирования (используя JSON Schema), основываясь на подсказках типов Python, что делает его чрезвычайно интуитивным.
+Благодаря этому он чрезвычайно интуитивен.
-Его можно сравнить с Marshmallow, хотя в бенчмарках Pydantic быстрее, чем Marshmallow.
-И он основан на тех же подсказках типов, которые отлично поддерживаются редакторами кода.
+Его можно сравнить с Marshmallow. Хотя в бенчмарках он быстрее Marshmallow. И поскольку он основан на тех же аннотациях типов Python, поддержка в редакторе кода отличная.
-/// check | **FastAPI** использует Pydantic
+/// check | **FastAPI** использует его для
-Ð\94лÑ\8f пÑ\80овеÑ\80ки данных, сериализации данных и автоматической документации моделей (на основе JSON Schema).
+Ð\9eбÑ\80абоÑ\82ки вÑ\81ей валидаÑ\86ии данных, сериализации данных и автоматической документации моделей (на основе JSON Schema).
-Затем **FastAPI** берёт эти схемы JSON и помещает их в схему OpenAPI, не касаясь других вещей, которые он делает.
+Затем **FastAPI** берёт эти данные JSON Schema и помещает их в OpenAPI, помимо всех прочих функций.
///
-### <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a>
+### <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> { #starlette }
-Starlette - это легковесный <abbr title="Новый стандарт построения асинхронных веб-сервисов Python">ASGI</abbr> фреймворк/набор инструментов, который идеален для построения высокопроизводительных асинхронных сервисов.
+Starlette — это лёгкий <abbr title="Новый стандарт построения асинхронных веб-сервисов Python">ASGI</abbr> фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов.
-Starlette очень простой и интуитивный.
-Он разработан таким образом, чтобы быть легко расширяемым и иметь модульные компоненты.
+Он очень простой и интуитивный. Спроектирован так, чтобы его было легко расширять, и чтобы компоненты были модульными.
В нём есть:
* Впечатляющая производительность.
-* Поддержка веб-сокетов.
-* Фоновые задачи.
-* Ð\9eбÑ\80абоÑ\82ка Ñ\81обÑ\8bÑ\82ий пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е и Ñ\84иниÑ\88е пÑ\80иложения.
-* ТеÑ\81Ñ\82овÑ\8bй клиенÑ\82 на оÑ\81нове HTTPX.
-* Поддержка CORS, сжатие GZip, статические файлы, потоковая передача данных.
-* Поддержка сессий и куки.
+* Поддержка WebSocket.
+* Фоновые задачи, выполняемые в том же процессе.
+* СобÑ\8bÑ\82иÑ\8f запÑ\83Ñ\81ка и завеÑ\80Ñ\88ения.
+* ТеÑ\81Ñ\82овÑ\8bй клиенÑ\82 на базе HTTPX.
+* CORS, GZip, статические файлы, потоковые ответы.
+* Поддержка сессий и cookie.
* 100% покрытие тестами.
-* 100% аннотированный код.
-* Несколько жёстких зависимостей.
+* 100% кодовой базы с аннотациями типов.
+* Мало жёстких зависимостей.
+
+В настоящее время Starlette — самый быстрый из протестированных Python-фреймворков. Его превосходит только Uvicorn, который не фреймворк, а сервер.
-В настоящее время Starlette показывает самую высокую скорость среди Python-фреймворков в тестовых замерах.
-Быстрее только Uvicorn, который является сервером, а не фреймворком.
+Starlette предоставляет весь базовый функционал веб-микрофреймворка.
-Starlette обеспечивает весь функционал микрофреймворка, но не предоставляет автоматическую валидацию данных, сериализацию и документацию.
+Но он не предоставляет автоматическую валидацию данных, сериализацию или документацию.
-**FastAPI** добавляет эти функции используя подсказки типов Python и Pydantic.
-Ещё **FastAPI** добавляет систему внедрения зависимостей, утилиты безопасности, генерацию схемы OpenAPI и т.д.
+Это одна из главных вещей, которые **FastAPI** добавляет поверх, всё на основе аннотаций типов Python (с использованием Pydantic). Плюс система внедрения зависимостей, утилиты безопасности, генерация схемы OpenAPI и т. д.
/// note | Технические детали
-ASGI - это новый "стандарт" разработанный участниками команды Django.
-Он пока что не является "стандартом в Python" (то есть принятым PEP), но процесс принятия запущен.
+ASGI — это новый «стандарт», разрабатываемый участниками core-команды Django. Он всё ещё не является «стандартом Python» (PEP), хотя процесс идёт.
-Тем не менее он уже используется в качестве "стандарта" несколькими инструментами.
-Это значительно улучшает совместимость, поскольку Вы можете переключиться с Uvicorn на любой другой ASGI-сервер (например, Daphne или Hypercorn) или Вы можете добавить ASGI-совместимые инструменты, такие как `python-socketio`.
+Тем не менее его уже используют как «стандарт» несколько инструментов. Это сильно улучшает совместимость: вы можете заменить Uvicorn на любой другой ASGI-сервер (например, Daphne или Hypercorn) или добавить совместимые с ASGI инструменты, такие как `python-socketio`.
///
-/// check | **FastAPI** использует Starlette
+/// check | **FastAPI** использует его для
-Ð\92 каÑ\87еÑ\81Ñ\82ве Ñ\8fдÑ\80а веб-Ñ\81еÑ\80виÑ\81а длÑ\8f обÑ\80абоÑ\82ки запÑ\80оÑ\81ов, добавив некоÑ\82оÑ\80Ñ\8bе Ñ\84Ñ\83нкÑ\86ии Ñ\81веÑ\80Ñ\85Ñ\83.
+Ð\9eбÑ\80абоÑ\82ки вÑ\81еÑ\85 оÑ\81новнÑ\8bÑ\85 веб-Ñ\87аÑ\81Ñ\82ей. Ð\94обавлÑ\8fÑ\8f возможноÑ\81Ñ\82и повеÑ\80Ñ\85.
-Класс `FastAPI` наследуется напрямую от класса `Starlette`.
+Класс `FastAPI` напрямую наследуется от класса `Starlette`.
-Таким образом, всё что Вы могли делать со Starlette, Вы можете делать с **FastAPI**, по сути это прокачанный Starlette.
+Так что всё, что вы можете сделать со Starlette, вы можете сделать напрямую с **FastAPI**, по сути это «Starlette на стероидах».
///
-### <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>
+### <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a> { #uvicorn }
-Uvicorn - это молниеносный ASGI-сервер, построенный на uvloop и httptools.
+Uvicorn — молниеносный ASGI-сервер, построенный на uvloop и httptools.
-Uvicorn является сервером, а не фреймворком.
-Например, он не предоставляет инструментов для маршрутизации запросов по ресурсам.
-Для этого нужна надстройка, такая как Starlette (или **FastAPI**).
+Это не веб-фреймворк, а сервер. Например, он не предоставляет инструменты для маршрутизации по путям. Это предоставляет сверху фреймворк, такой как Starlette (или **FastAPI**).
-Ð\9eн Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f в каÑ\87еÑ\81Ñ\82ве Ñ\81еÑ\80веÑ\80а для Starlette и **FastAPI**.
+ÐÑ\82о Ñ\80екомендÑ\83емÑ\8bй Ñ\81еÑ\80веÑ\80 для Starlette и **FastAPI**.
-/// check | **FastAPI** рекомендует его
+/// check | **FastAPI** рекомендует его как
-Ð\9aак оÑ\81новной Ñ\81еÑ\80веÑ\80 длÑ\8f запÑ\83Ñ\81ка пÑ\80иложениÑ\8f **FastAPI**.
+Ð\9eÑ\81новной веб-Ñ\81еÑ\80веÑ\80 длÑ\8f запÑ\83Ñ\81ка пÑ\80иложений **FastAPI**.
-Ð\92Ñ\8b можеÑ\82е обÑ\8aединиÑ\82Ñ\8c его Ñ\81 Gunicorn, Ñ\87Ñ\82обÑ\8b иметь асинхронный многопроцессный сервер.
+Также вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c опÑ\86иÑ\8e командной Ñ\81Ñ\82Ñ\80оки `--workers`, Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87ить асинхронный многопроцессный сервер.
-УзнаÑ\82Ñ\8c болÑ\8cÑ\88е деÑ\82алей можно в Ñ\80азделе [Развёртывание](deployment/index.md){.internal-link target=_blank}.
+Ð\9fодÑ\80обнее Ñ\81м. Ñ\80аздел [Развёртывание](deployment/index.md){.internal-link target=_blank}.
///
-## ТеÑ\81Ñ\82овÑ\8bе замеÑ\80Ñ\8b и Ñ\81коÑ\80оÑ\81Ñ\82Ñ\8c
+## Ð\91енÑ\87маÑ\80ки и Ñ\81коÑ\80оÑ\81Ñ\82Ñ\8c { #benchmarks-and-speed }
-Чтобы понять, сравнить и увидеть разницу между Uvicorn, Starlette и FastAPI, ознакомьтесь с разделом [Тестовые замеры](benchmarks.md){.internal-link target=_blank}.
+Чтобы понять, сравнить и увидеть разницу между Uvicorn, Starlette и FastAPI, см. раздел о [Бенчмарках](benchmarks.md){.internal-link target=_blank}.
-# Конкурентность и async / await
+# Конкурентность и async / await { #concurrency-and-async-await }
-Ð\97деÑ\81Ñ\8c пÑ\80иведена подÑ\80обнаÑ\8f инÑ\84оÑ\80маÑ\86иÑ\8f об иÑ\81полÑ\8cзовании Ñ\81инÑ\82акÑ\81иÑ\81а `async def` пÑ\80и напиÑ\81ании *Ñ\84Ñ\83нкÑ\86ий обÑ\80абоÑ\82ки пÑ\83Ñ\82и*, а Ñ\82акже Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80енÑ\8b оÑ\81новÑ\8b аÑ\81инÑ\85Ñ\80онного пÑ\80огÑ\80аммиÑ\80ованиÑ\8f, конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82и и паÑ\80аллелизма.
+Ð\9fодÑ\80обноÑ\81Ñ\82и о Ñ\81инÑ\82акÑ\81иÑ\81е `async def` длÑ\8f *Ñ\84Ñ\83нкÑ\86ий-обÑ\80абоÑ\82Ñ\87иков пÑ\83Ñ\82и* и немного Ñ\84она об аÑ\81инÑ\85Ñ\80онном коде, конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82и и паÑ\80аллелизме.
-## Нет времени?<a name="in-a-hurry"></a>
+## Нет времени? { #in-a-hurry }
-<abbr title="too long; didn't read (основная мысль)"><strong>TL;DR:</strong></abbr>
+<abbr title="too long; didn't read – слишком длинно; не читал"><strong>TL;DR:</strong></abbr>
-Ð\94опÑ\83Ñ\81Ñ\82им, вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Ñ\81Ñ\82оÑ\80онÑ\8eÑ\8e библиоÑ\82екÑ\83, коÑ\82оÑ\80аÑ\8f Ñ\82Ñ\80ебÑ\83еÑ\82 вÑ\8bзова Ñ\81 клÑ\8eÑ\87евÑ\8bм Ñ\81ловом `await`:
+Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Ñ\81Ñ\82оÑ\80онние библиоÑ\82еки, коÑ\82оÑ\80Ñ\8bе нÑ\83жно вÑ\8bзÑ\8bваÑ\82Ñ\8c Ñ\81 `await`, напÑ\80имеÑ\80:
```Python
results = await some_library()
```
-Ð\92 Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и* необÑ\85одимо обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c Ñ\81 иÑ\81полÑ\8cзованием Ñ\81инÑ\82акÑ\81иÑ\81а `async def`:
+Тогда обÑ\8aÑ\8fвлÑ\8fйÑ\82е *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87ики пÑ\83Ñ\82и* Ñ\81 `async def`, напÑ\80имеÑ\80:
```Python hl_lines="2"
@app.get('/')
return results
```
-/// note
+/// note | Примечание
-`await` можно использовать только внутри функций, объявленных с использованием `async def`.
+`await` можно использовать только внутри функций, объявленных с `async def`.
///
---
-Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует
-(с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await`
-(что относится сейчас к большинству библиотек для работы с базами данных), то
-объявляйте *функции обработки пути* обычным образом с помощью `def`, например:
+Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т.д.) и не поддерживает использование `await` (сейчас это относится к большинству библиотек для БД), тогда объявляйте *функции-обработчики пути* как обычно, просто с `def`, например:
```Python hl_lines="2"
@app.get('/')
---
-Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно,
-ожидать ответа, используйте `async def`.
+Если вашему приложению (по какой-то причине) не нужно ни с чем взаимодействовать и ждать ответа, используйте `async def`, даже если внутри не нужен `await`.
---
-Ð\95Ñ\81ли вÑ\8b не Ñ\83веÑ\80енÑ\8b, иÑ\81полÑ\8cзÑ\83йÑ\82е обÑ\8bÑ\87нÑ\8bй Ñ\81инÑ\82акÑ\81иÑ\81 `def`.
+Ð\95Ñ\81ли вÑ\8b пÑ\80оÑ\81Ñ\82о не Ñ\83веÑ\80енÑ\8b, иÑ\81полÑ\8cзÑ\83йÑ\82е обÑ\8bÑ\87нÑ\8bй `def`.
---
-**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях обработки пути*
-и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно.
+**Примечание**: вы можете смешивать `def` и `async def` в *функциях-обработчиках пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо.
-В любом из описанных случаев FastAPI работает асинхронно и очень быстро.
+В любом из случаев выше FastAPI всё равно работает асинхронно и очень быстро.
-Ð\9eднако пÑ\80идеÑ\80живаÑ\8fÑ\81Ñ\8c Ñ\83казаннÑ\8bÑ\85 Ñ\81овеÑ\82ов, можно полÑ\83Ñ\87иÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\83Ñ\8e опÑ\82имизаÑ\86иÑ\8e производительности.
+Ð\9dо Ñ\81ледÑ\83Ñ\8f Ñ\8dÑ\82им Ñ\88агам, он Ñ\81можеÑ\82 вÑ\8bполниÑ\82Ñ\8c некоÑ\82оÑ\80Ñ\8bе опÑ\82имизаÑ\86ии производительности.
-## Технические подробности
+## Технические подробности { #technical-details }
-Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**.
+Современные версии Python поддерживают **«асинхронный код»** с помощью **«сопрограмм»** (coroutines) и синтаксиса **`async` и `await`**.
-Ð\9dиже Ñ\80азбеÑ\80Ñ\91м Ñ\8dÑ\82Ñ\83 Ñ\84Ñ\80азÑ\83 по Ñ\87аÑ\81Ñ\82Ñ\8fм:
+РазбеÑ\80Ñ\91м Ñ\8dÑ\82Ñ\83 Ñ\84Ñ\80азÑ\83 по Ñ\87аÑ\81Ñ\82Ñ\8fм в Ñ\80азделаÑ\85 ниже:
* **Асинхронный код**
* **`async` и `await`**
* **Сопрограммы**
-## Асинхронный код
+## Асинхронный код { #asynchronous-code }
-Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖,
-что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝.
+Асинхронный код значит, что в языке 💬 есть способ сказать компьютеру/программе 🤖, что в некоторый момент кода ему 🤖 придётся подождать, пока *что-то ещё* где-то в другом месте завершится. Назовём это *что-то ещё* «медленный файл» 📝.
-И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач.
+И пока мы ждём завершения работы с «медленныи файлом» 📝, компьютер может заняться другой работой.
-Ð\9dо пÑ\80и каждой возможноÑ\81Ñ\82и компÑ\8cÑ\8eÑ\82еÑ\80 / пÑ\80огÑ\80амма ð\9f¤\96 бÑ\83деÑ\82 возвÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f обÑ\80аÑ\82но. Ð\9dапÑ\80имеÑ\80, еÑ\81ли он ð\9f¤\96 опÑ\8fÑ\82Ñ\8c окажеÑ\82Ñ\81Ñ\8f в Ñ\80ежиме ожиданиÑ\8f, или когда законÑ\87иÑ\82 вÑ\81Ñ\8e Ñ\80абоÑ\82Ñ\83. Ð\92 Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае компÑ\8cÑ\8eÑ\82еÑ\80 ð\9f¤\96 пÑ\80овеÑ\80Ñ\8fеÑ\82, не завеÑ\80Ñ\88ена ли какаÑ\8f-нибÑ\83дÑ\8c из Ñ\82екÑ\83Ñ\89иÑ\85 задаÑ\87.
+Ð\97аÑ\82ем компÑ\8cÑ\8eÑ\82еÑ\80/пÑ\80огÑ\80амма ð\9f¤\96 бÑ\83деÑ\82 возвÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f каждÑ\8bй Ñ\80аз, когда поÑ\8fвиÑ\82Ñ\81Ñ\8f возможноÑ\81Ñ\82Ñ\8c (пока Ñ\81нова где-Ñ\82о идÑ\91Ñ\82 ожидание), или когда ð\9f¤\96 завеÑ\80Ñ\88иÑ\82 вÑ\81Ñ\8e Ñ\82екÑ\83Ñ\89Ñ\83Ñ\8e Ñ\80абоÑ\82Ñ\83. Ð\98 он ð\9f¤\96 пÑ\80овеÑ\80иÑ\82, не завеÑ\80Ñ\88илаÑ\81Ñ\8c ли какаÑ\8f-либо из задаÑ\87, коÑ\82оÑ\80Ñ\8bÑ\85 он ждал, и Ñ\81делаеÑ\82 Ñ\82о, Ñ\87Ñ\82о нÑ\83жно.
-Ð\9fоÑ\82ом он ð\9f¤\96 беÑ\80Ñ\91Ñ\82 пеÑ\80вÑ\83Ñ\8e вÑ\8bполненнÑ\83Ñ\8e задаÑ\87Ñ\83 (допÑ\83Ñ\81Ñ\82им, наÑ\88 "медленнÑ\8bй Ñ\84айл" ð\9f\93\9d) и пÑ\80одолжаеÑ\82 Ñ\80абоÑ\82Ñ\83, пÑ\80оизводÑ\8f Ñ\81 ней необÑ\85одимÑ\8bе дейÑ\81Ñ\82вия.
+Ð\94алее он ð\9f¤\96 возÑ\8cмÑ\91Ñ\82 пеÑ\80вÑ\83Ñ\8e завеÑ\80Ñ\88ивÑ\88Ñ\83Ñ\8eÑ\81Ñ\8f задаÑ\87Ñ\83 (Ñ\81кажем, наÑ\88 «медленнÑ\8bй Ñ\84айл» ð\9f\93\9d) и пÑ\80одолжиÑ\82 делаÑ\82Ñ\8c Ñ\81 ней Ñ\82о, Ñ\87Ñ\82о Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81я.
-Ð\92Ñ\8bÑ\88еÑ\83помÑ\8fнÑ\83Ñ\82ое "Ñ\87Ñ\82о-Ñ\82о еÑ\89Ñ\91", завеÑ\80Ñ\88ениÑ\8f коÑ\82оÑ\80ого пÑ\80иÑ\85одиÑ\82Ñ\81Ñ\8f ожидаÑ\82Ñ\8c, обÑ\8bÑ\87но оÑ\82ноÑ\81иÑ\82Ñ\81Ñ\8f к доÑ\81Ñ\82аÑ\82оÑ\87но "медленнÑ\8bм" опеÑ\80аÑ\86иÑ\8fм <abbr title="Ð\92вода-вÑ\8bвода">I/O</abbr> (по Ñ\81Ñ\80авнениÑ\8e Ñ\81о Ñ\81коÑ\80оÑ\81Ñ\82Ñ\8cÑ\8e Ñ\80абоÑ\82Ñ\8b пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а и опеÑ\80аÑ\82ивной памÑ\8fÑ\82и), напÑ\80имеÑ\80:
+ÐÑ\82о «ожидание Ñ\87его-Ñ\82о еÑ\89Ñ\91» обÑ\8bÑ\87но оÑ\82ноÑ\81иÑ\82Ñ\81Ñ\8f к опеÑ\80аÑ\86иÑ\8fм <abbr title="Input and Output â\80\93 Ð\92вод/вÑ\8bвод">I/O</abbr>, коÑ\82оÑ\80Ñ\8bе оÑ\82ноÑ\81иÑ\82елÑ\8cно «медленнÑ\8bе» (по Ñ\81Ñ\80авнениÑ\8e Ñ\81о Ñ\81коÑ\80оÑ\81Ñ\82Ñ\8cÑ\8e пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а и опеÑ\80аÑ\82ивной памÑ\8fÑ\82и), напÑ\80имеÑ\80 ожидание:
-* оÑ\82пÑ\80авка даннÑ\8bÑ\85 оÑ\82 клиенÑ\82а по сети
-* получение клиентом данных, отправленных вашей программой по сети
-* чтение системой содержимого файла с диска и передача этих данных программе
-* запись на диск данных, которые программа передала системе
-* обÑ\80аÑ\89ение к Ñ\83далÑ\91нномÑ\83 API
-* ожидание завеÑ\80Ñ\88ениÑ\8f опеÑ\80аÑ\86ии Ñ\81 базой данных
-* полÑ\83Ñ\87ение результатов запроса к базе данных
-* и т. д.
+* оÑ\82пÑ\80авки даннÑ\8bÑ\85 клиенÑ\82ом по сети
+* получения клиентом данных, отправленных вашей программой по сети
+* чтения системой содержимого файла на диске и передачи этих данных вашей программе
+* записи на диск содержимого, которое ваша программа передала системе
+* опеÑ\80аÑ\86ии Ñ\83далÑ\91нного API
+* завеÑ\80Ñ\88ениÑ\8f опеÑ\80аÑ\86ии базÑ\8b данных
+* возвÑ\80аÑ\82а результатов запроса к базе данных
+* и т.д.
-Поскольку в основном время тратится на ожидание выполнения операций <abbr title="Ввода-вывода">I/O</abbr>,
-их обычно называют операциями, <abbr title="I/O bound">ограниченными скоростью ввода-вывода</abbr>.
+Поскольку основное время выполнения уходит на ожидание операций <abbr title="Input and Output – Ввод/вывод">I/O</abbr>, их называют операциями, «ограниченными вводом-выводом» (I/O bound).
-Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и,
-будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу.
+Это называется «асинхронным», потому что компьютеру/программе не нужно «синхронизироваться» с медленной задачей, простаивая и выжидая точный момент её завершения, чтобы забрать результат и продолжить работу.
-Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд),
-пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться,
-забрать результаты выполнения и начать их обрабатывать.
+Вместо этого, в «асинхронной» системе, уже завершившаяся задача может немного подождать (несколько микросекунд) в очереди, пока компьютер/программа завершит то, чем занимался, и затем вернётся, чтобы забрать результаты и продолжить работу с ними.
-"Синхронное" исполнение (в противовес "асинхронному") также называют <abbr title="sequential">"последовательным"</abbr>,
-потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче,
-даже если в процессе приходится ждать.
+Для «синхронного» (в противоположность «асинхронному») исполнения часто используют термин «последовательный», потому что компьютер/программа выполняет все шаги по порядку, прежде чем переключиться на другую задачу, даже если эти шаги включают ожидание.
-### Конкурентность и бургеры
+### Конкурентность и бургеры { #concurrency-and-burgers }
-ТоÑ\82 **аÑ\81инÑ\85Ñ\80оннÑ\8bй** код, о коÑ\82оÑ\80ом идÑ\91Ñ\82 Ñ\80еÑ\87Ñ\8c вÑ\8bÑ\88е, иногда назÑ\8bваÑ\8eÑ\82 **"конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8cÑ\8e"**. Ð\9eна оÑ\82лиÑ\87аеÑ\82Ñ\81Ñ\8f оÑ\82 **"паÑ\80аллелизма"**.
+Та идеÑ\8f **аÑ\81инÑ\85Ñ\80онного** кода, опиÑ\81аннаÑ\8f вÑ\8bÑ\88е, иногда Ñ\82акже назÑ\8bваеÑ\82Ñ\81Ñ\8f **«конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8cÑ\8e»**. Ð\9eна оÑ\82лиÑ\87аеÑ\82Ñ\81Ñ\8f оÑ\82 **«паÑ\80аллелизма»**.
-Ð\94а, **конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c** и **паÑ\80аллелизм** подÑ\80азÑ\83меваÑ\8eÑ\82, Ñ\87Ñ\82о Ñ\80азнÑ\8bе веÑ\89и пÑ\80оиÑ\81Ñ\85одÑ\8fÑ\82 пÑ\80имеÑ\80но в одно вÑ\80емÑ\8f.
+Ð\98 **конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c**, и **паÑ\80аллелизм** оÑ\82ноÑ\81Ñ\8fÑ\82Ñ\81Ñ\8f к «Ñ\80азнÑ\8bм веÑ\89ам, пÑ\80оиÑ\81Ñ\85одÑ\8fÑ\89им пÑ\80имеÑ\80но одновÑ\80еменно».
-Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное.
+Но различия между *конкурентностью* и *параллелизмом* довольно существенные.
-Чтобы это понять, представьте такую картину:
+Чтобы их увидеть, представьте следующую историю про бургеры:
-### Конкурентные бургеры
+### Конкурентные бургеры { #concurrent-burgers }
-<!-- The gender neutral cook emoji "🧑🍳" does not render well in browsers. In the meantime, I'm using a mix of male "👨🍳" and female "👩🍳" cooks. -->
+Вы идёте со своей возлюбленной за фастфудом, вы стоите в очереди, пока кассир принимает заказы у людей перед вами. 😍
-Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами.
+<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
-Ð\9aогда наконеÑ\86 подÑ\85одиÑ\82 оÑ\87еÑ\80едÑ\8c, вÑ\8b заказÑ\8bваеÑ\82е паÑ\80оÑ\87кÑ\83 Ñ\81амÑ\8bÑ\85 вкÑ\83Ñ\81нÑ\8bÑ\85 и навоÑ\80оÑ\87еннÑ\8bÑ\85 бÑ\83Ñ\80геÑ\80ов ð\9f\8d\94, один длÑ\8f Ñ\81воей возлÑ\8eбленной ð\9f\98\8d, а дÑ\80Ñ\83гой Ñ\81ебе.
+Ð\9dаконеÑ\86 ваÑ\88а оÑ\87еÑ\80едÑ\8c: вÑ\8b заказÑ\8bваеÑ\82е 2 оÑ\87енÑ\8c «навоÑ\80оÑ\87еннÑ\8bÑ\85» бÑ\83Ñ\80геÑ\80а â\80\94 длÑ\8f ваÑ\88ей возлÑ\8eбленной и длÑ\8f Ñ\81ебÑ\8f. ð\9f\8d\94ð\9f\8d\94
-Отдаёте деньги 💸.
+<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
-Кассир 💁 что-то говорит поварам на кухне 👨🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔
-(но пока они заняты бургерами предыдущих клиентов).
+Кассир говорит что-то повару на кухне, чтобы они знали, что нужно приготовить ваши бургеры (хотя сейчас они готовят бургеры для предыдущих клиентов).
-Кассир 💁 отдаёт вам чек с номером заказа.
+<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
-В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍
-(поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨).
+Вы платите. 💸
-Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время,
-восхищаясь её великолепием, красотой и умом ✨😍✨.
+Кассир выдаёт вам номер вашей очереди.
-Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете,
-какой номер горит над прилавком, и не подошла ли уже ваша очередь.
+<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
-Ð\98 воÑ\82 наконеÑ\86 наÑ\81Ñ\82аÑ\91Ñ\82 Ñ\8dÑ\82оÑ\82 моменÑ\82, и вÑ\8b идÑ\91Ñ\82е к Ñ\81Ñ\82ойке, Ñ\87Ñ\82обÑ\8b забÑ\80аÑ\82Ñ\8c бÑ\83Ñ\80геÑ\80Ñ\8b ð\9f\8d\94 и веÑ\80нÑ\83Ñ\82Ñ\8cÑ\81Ñ\8f за Ñ\81Ñ\82олик.
+Ð\9fока вÑ\8b ждÑ\91Ñ\82е, вÑ\8b вмеÑ\81Ñ\82е Ñ\81о Ñ\81воей возлÑ\8eбленной идÑ\91Ñ\82е и вÑ\8bбиÑ\80аеÑ\82е Ñ\81Ñ\82олик, Ñ\81адиÑ\82еÑ\81Ñ\8c и долго болÑ\82аеÑ\82е (ваÑ\88и бÑ\83Ñ\80геÑ\80Ñ\8b оÑ\87енÑ\8c «навоÑ\80оÑ\87еннÑ\8bе», поÑ\8dÑ\82омÑ\83 им нÑ\83жно вÑ\80емÑ\8f на пÑ\80игоÑ\82овление).
-Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨.
+Сидя за столиком со своей возлюбленной в ожидании бургеров, вы можете провести это время, восхищаясь тем, какая она классная, милая и умная ✨😍✨.
+
+<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
+
+Пока вы ждёте и разговариваете, время от времени вы поглядываете на номер на табло, чтобы понять, не подошла ли уже ваша очередь.
+
+И вот в какой-то момент ваша очередь наступает. Вы подходите к стойке, забираете свои бургеры и возвращаетесь к столику.
+
+<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
+
+Вы со своей возлюбленной едите бургеры и отлично проводите время. ✨
+
+<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
+
+/// info | Информация
+
+Прекрасные иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
+
+///
---
-Ð\90 Ñ\82епеÑ\80Ñ\8c пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о в Ñ\8dÑ\82ой неболÑ\8cÑ\88ой иÑ\81Ñ\82оÑ\80ии вÑ\8b компÑ\8cÑ\8eÑ\82еÑ\80 / программа 🤖.
+Ð\9fÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о в Ñ\8dÑ\82ой иÑ\81Ñ\82оÑ\80ии вÑ\8b â\80\94 компÑ\8cÑ\8eÑ\82еÑ\80/программа 🤖.
-В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете.
-Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного.
+Пока вы стоите в очереди, вы просто бездействуете 😴, ждёте своей очереди и не делаете ничего особо «продуктивного». Но очередь движется быстро, потому что кассир только принимает заказы (а не готовит их), так что это нормально.
-Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д.
+Когда приходит ваша очередь, вы выполняете действительно «продуктивную» работу: просматриваете меню, решаете, чего хотите, учитываете выбор своей возлюбленной, платите, проверяете, что дали правильную купюру/карту, что сумма списана корректно, что в заказе верные позиции и т.д.
-И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸,
-поскольку теперь нужно ждать 🕙, когда заказ приготовят.
+Но затем, хотя у вас ещё нет бургеров, ваша «работа» с кассиром поставлена «на паузу» ⏸, потому что нужно подождать 🕙, пока бургеры будут готовы.
-Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание
-на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень
-"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍.
+Но, отойдя от стойки и сев за столик с номерком, вы можете переключить 🔀 внимание на свою возлюбленную и «поработать» ⏯ 🤓 над этим. Снова очень «продуктивно» — флирт с вашей возлюбленной 😍.
-Ð\92 какой-Ñ\82о моменÑ\82 каÑ\81Ñ\81иÑ\80 ð\9f\92\81 помеÑ\81Ñ\82иÑ\82 на Ñ\82абло ваÑ\88 номеÑ\80, подÑ\80азÑ\83меваÑ\8f, Ñ\87Ñ\82о бÑ\83Ñ\80геÑ\80Ñ\8b гоÑ\82овÑ\8b ð\9f\8d\94, но вÑ\8b не Ñ\81Ñ\82анеÑ\82е подÑ\81какиваÑ\82Ñ\8c как Ñ\83малиÑ\88Ñ\91ннÑ\8bй, лиÑ\88Ñ\8c Ñ\82олÑ\8cко Ñ\83видев на Ñ\8dкÑ\80ане Ñ\81воÑ\8e оÑ\87еÑ\80едÑ\8c. Ð\92Ñ\8b Ñ\83веÑ\80енÑ\8b, Ñ\87Ñ\82о ваÑ\88и бÑ\83Ñ\80геÑ\80Ñ\8b ð\9f\8d\94 никÑ\82о не Ñ\83Ñ\82аÑ\89иÑ\82, ведÑ\8c Ñ\83 ваÑ\81 Ñ\81вой номеÑ\80ок, а Ñ\83 дÑ\80Ñ\83гиÑ\85 Ñ\81вой.
+Ð\9fоÑ\82ом каÑ\81Ñ\81иÑ\80 ð\9f\92\81 «говоÑ\80иÑ\82»: «Я законÑ\87ил делаÑ\82Ñ\8c бÑ\83Ñ\80геÑ\80Ñ\8b», â\80\94 вÑ\8bводÑ\8f ваÑ\88 номеÑ\80 на Ñ\82абло, но вÑ\8b не подпÑ\80Ñ\8bгиваеÑ\82е как Ñ\81Ñ\83маÑ\81Ñ\88едÑ\88ий в Ñ\82Ñ\83 же Ñ\81екÑ\83ндÑ\83, как Ñ\82олÑ\8cко номеÑ\80 Ñ\81менилÑ\81Ñ\8f на ваÑ\88. Ð\92Ñ\8b знаеÑ\82е, Ñ\87Ñ\82о ваÑ\88и бÑ\83Ñ\80геÑ\80Ñ\8b никÑ\82о не Ñ\83кÑ\80адÑ\91Ñ\82, поÑ\82омÑ\83 Ñ\87Ñ\82о Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c номеÑ\80 ваÑ\88ей оÑ\87еÑ\80еди, а Ñ\83 дÑ\80Ñ\83гиÑ\85 â\80\94 иÑ\85.
-Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓),
-и мило улыбнувшись, скажете, что идёте забирать заказ ⏸.
+Поэтому вы дожидаетесь, пока ваша возлюбленная закончит историю (завершится текущая работа ⏯ / выполняемая задача 🤓), мягко улыбаетесь и говорите, что идёте за бургерами ⏸.
-И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹.
-В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
+Затем вы идёте к стойке 🔀, к исходной задаче, которая теперь завершена ⏯, забираете бургеры, благодарите и несёте их к столику. На этом шаг/задача взаимодействия со стойкой завершён ⏹. Это, в свою очередь, создаёт новую задачу — «есть бургеры» 🔀 ⏯, но предыдущая «получить бургеры» — завершена ⏹.
-### Параллельные бургеры
+### Параллельные бургеры { #parallel-burgers }
-Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры".
+Теперь представим, что это не «Конкурентные бургеры», а «Параллельные бургеры».
-Ð\98 воÑ\82 вÑ\8b идÑ\91Ñ\82е Ñ\81о Ñ\81воей возлÑ\8eбленной ð\9f\98\8d оÑ\82ведаÑ\82Ñ\8c паÑ\80аллелÑ\8cного Ñ\84аÑ\81Ñ\82Ñ\84Ñ\83да ð\9f\8d\94.
+Ð\92Ñ\8b идÑ\91Ñ\82е Ñ\81о Ñ\81воей возлÑ\8eбленной за паÑ\80аллелÑ\8cнÑ\8bм Ñ\84аÑ\81Ñ\82Ñ\84Ñ\83дом.
-Ð\92Ñ\8b Ñ\81Ñ\82ановиÑ\82еÑ\81Ñ\8c в оÑ\87еÑ\80едÑ\8c пока неÑ\81колÑ\8cко (пÑ\83Ñ\81Ñ\82Ñ\8c бÑ\83деÑ\82 8) каÑ\81Ñ\81иÑ\80ов, коÑ\82оÑ\80Ñ\8bе по Ñ\81овмеÑ\81Ñ\82иÑ\82елÑ\8cÑ\81Ñ\82вÑ\83 еÑ\89Ñ\91 и поваÑ\80Ñ\8b ð\9f\91©â\80\8dð\9f\8d³ð\9f\91¨â\80\8dð\9f\8d³ð\9f\91©â\80\8dð\9f\8d³ð\9f\91¨â\80\8dð\9f\8d³ð\9f\91©â\80\8dð\9f\8d³ð\9f\91¨â\80\8dð\9f\8d³ð\9f\91©â\80\8dð\9f\8d³ð\9f\91¨â\80\8dð\9f\8d³, пÑ\80инимаÑ\8eÑ\82 заказÑ\8b Ñ\83 поÑ\81еÑ\82иÑ\82елей перед вами.
+Ð\92Ñ\8b Ñ\81Ñ\82оиÑ\82е в оÑ\87еÑ\80еди, пока неÑ\81колÑ\8cко (Ñ\81кажем, 8) каÑ\81Ñ\81иÑ\80ов, коÑ\82оÑ\80Ñ\8bе одновÑ\80еменно Ñ\8fвлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f поваÑ\80ами, пÑ\80инимаÑ\8eÑ\82 заказÑ\8b Ñ\83 лÑ\8eдей перед вами.
-При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый
-из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ.
+Все перед вами ждут, пока их бургеры будут готовы, не отходя от стойки, потому что каждый из 8 кассиров сразу идёт готовить бургер перед тем, как принять следующий заказ.
-Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе.
+<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
-Ð\9dи о Ñ\87Ñ\91м не жалеÑ\8f, Ñ\80аÑ\81плаÑ\87иваеÑ\82еÑ\81Ñ\8c ð\9f\92¸.
+Ð\9dаконеÑ\86 ваÑ\88а оÑ\87еÑ\80едÑ\8c: вÑ\8b заказÑ\8bваеÑ\82е 2 оÑ\87енÑ\8c «навоÑ\80оÑ\87еннÑ\8bÑ\85» бÑ\83Ñ\80геÑ\80а â\80\94 длÑ\8f ваÑ\88ей возлÑ\8eбленной и длÑ\8f Ñ\81ебÑ\8f.
-Ð\98 каÑ\81Ñ\81иÑ\80 Ñ\83Ñ\85одиÑ\82 на кÑ\83Ñ\85нÑ\8e ð\9f\91¨â\80\8dð\9f\8d³.
+Ð\92Ñ\8b плаÑ\82иÑ\82е ð\9f\92¸.
-Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет.
+<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
-Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь,
-у вас не получается уделять должного внимание своей даме сердца 😞.
+Кассир уходит на кухню.
-Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨🍳. Приходится ждать 🕙 у стойки,
-когда кассир/повар 👨🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой.
+Вы ждёте, стоя у стойки 🕙, чтобы никто не забрал ваши бургеры раньше вас, так как никаких номерков нет.
-Наконец кассир/повар 👨🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой.
+<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
-Ð\92Ñ\8b Ñ\81коÑ\80ее забиÑ\80аеÑ\82е заказ ð\9f\8d\94 и идÑ\91Ñ\82е Ñ\81 возлÑ\8eбленной ð\9f\98\8d за Ñ\81Ñ\82олик.
+Так как вÑ\8b Ñ\81о Ñ\81воей возлÑ\8eбленной занÑ\8fÑ\82Ñ\8b Ñ\82ем, Ñ\87Ñ\82обÑ\8b никÑ\82о не вÑ\81Ñ\82ал пеÑ\80ед вами и не забÑ\80ал ваÑ\88и бÑ\83Ñ\80геÑ\80Ñ\8b, как Ñ\82олÑ\8cко они поÑ\8fвÑ\8fÑ\82Ñ\81Ñ\8f, вÑ\8b не можеÑ\82е Ñ\83делиÑ\82Ñ\8c внимание Ñ\81воей возлÑ\8eбленной. ð\9f\98\9e
-Там вÑ\8b пÑ\80оÑ\81Ñ\82о едиÑ\82е Ñ\8dÑ\82и бÑ\83Ñ\80геÑ\80Ñ\8b, и на Ñ\8dÑ\82ом вÑ\81Ñ\91 ð\9f\8d\94 â\8f¹.
+ÐÑ\82о «Ñ\81инÑ\85Ñ\80оннаÑ\8f» Ñ\80абоÑ\82а, вÑ\8b «Ñ\81инÑ\85Ñ\80онизиÑ\80ованÑ\8b» Ñ\81 каÑ\81Ñ\81иÑ\80ом/поваÑ\80ом ð\9f\91¨â\80\8dð\9f\8d³. Ð\92ам нÑ\83жно ждаÑ\82Ñ\8c ð\9f\95\99 и наÑ\85одиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\82ам в Ñ\82оÑ\87нÑ\8bй моменÑ\82, когда каÑ\81Ñ\81иÑ\80/поваÑ\80 ð\9f\91¨â\80\8dð\9f\8d³ законÑ\87иÑ\82 бÑ\83Ñ\80геÑ\80Ñ\8b и вÑ\80Ñ\83Ñ\87иÑ\82 иÑ\85 вам, инаÑ\87е иÑ\85 можеÑ\82 забÑ\80аÑ\82Ñ\8c кÑ\82о-Ñ\82о дÑ\80Ñ\83гой.
-Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞.
+<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
----
+Затем ваш кассир/повар 👨🍳 наконец возвращается с вашими бургерами, после долгого ожидания 🕙 у стойки.
-В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍),
-на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе".
+<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
-В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳.
-Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨🍳.
+Вы берёте бургеры и идёте со своей возлюбленной к столику.
-Несмотря на обилие работников, опыт в итоге получился не из лучших 😞.
+Вы просто их съедаете — и всё. ⏹
+
+<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
+
+Разговоров и флирта было немного, потому что большую часть времени вы ждали 🕙 у стойки. 😞
+
+/// info | Информация
+
+Прекрасные иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
+
+///
---
-Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире.
+В этом сценарии «параллельных бургеров» вы — компьютер/программа 🤖 с двумя процессорами (вы и ваша возлюбленная), оба ждут 🕙 и уделяют внимание ⏯ тому, чтобы «ждать у стойки» 🕙 долгое время.
+
+В ресторане 8 процессоров (кассиров/поваров). Тогда как в «конкурентных бургерах» могло быть только 2 (один кассир и один повар).
-Ð\92оÑ\82 более Ñ\80еалиÑ\81Ñ\82иÑ\87нÑ\8bй пÑ\80имеÑ\80. Ð\9fÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е Ñ\81ебе банк.
+Ð\98 вÑ\81Ñ\91 же Ñ\84иналÑ\8cнÑ\8bй опÑ\8bÑ\82 â\80\94 не Ñ\81амÑ\8bй лÑ\83Ñ\87Ñ\88ий. ð\9f\98\9e
-До недавних пор в большинстве банков было несколько кассиров 👨💼👨💼👨💼👨💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙.
+---
-Ð\9aаждÑ\8bй каÑ\81Ñ\81иÑ\80 обÑ\81лÑ\83живал одного клиенÑ\82а, поÑ\82ом Ñ\81ледÑ\83Ñ\8eÑ\89его ð\9f\91¨â\80\8dð\9f\92¼â\8f¯.
+ÐÑ\82о бÑ\8bла паÑ\80аллелÑ\8cнаÑ\8f веÑ\80Ñ\81иÑ\8f иÑ\81Ñ\82оÑ\80ии пÑ\80о бÑ\83Ñ\80геÑ\80Ñ\8b. ð\9f\8d\94
-Ð\9dÑ\83жно бÑ\8bло долгое вÑ\80емÑ\8f ð\9f\95\99 Ñ\81Ñ\82оÑ\8fÑ\82Ñ\8c пеÑ\80ед окоÑ\88ком вмеÑ\81Ñ\82е Ñ\81о вÑ\81еми, инаÑ\87е пÑ\80опÑ\83Ñ\81Ñ\82иÑ\88Ñ\8c Ñ\81воÑ\8e оÑ\87еÑ\80едÑ\8c.
+Ð\94лÑ\8f более «жизненного» пÑ\80имеÑ\80а пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е банк.
-СомневаÑ\8eÑ\81Ñ\8c, Ñ\87Ñ\82о Ñ\83 ваÑ\81 бÑ\8b возникло желание пÑ\80ийÑ\82и Ñ\81 возлÑ\8eбленной ð\9f\98\8d в банк ð\9f\8f¦ оплаÑ\87иваÑ\82Ñ\8c налоги.
+Ð\94о недавнего вÑ\80емени в болÑ\8cÑ\88инÑ\81Ñ\82ве банков бÑ\8bло неÑ\81колÑ\8cко каÑ\81Ñ\81иÑ\80ов ð\9f\91¨â\80\8dð\9f\92¼ð\9f\91¨â\80\8dð\9f\92¼ð\9f\91¨â\80\8dð\9f\92¼ð\9f\91¨â\80\8dð\9f\92¼ и длиннаÑ\8f оÑ\87еÑ\80едÑ\8c ð\9f\95\99ð\9f\95\99ð\9f\95\99ð\9f\95\99ð\9f\95\99ð\9f\95\99ð\9f\95\99ð\9f\95\99.
-### Выводы о бургерах
+Все кассиры делают всю работу с одним клиентом за другим 👨💼⏯.
-В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙,
-поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯.
+И вам приходится долго 🕙 стоять в очереди, иначе вы потеряете свою очередь.
-Ð\98 Ñ\82о же Ñ\81амое Ñ\81 болÑ\8cÑ\88инÑ\81Ñ\82вом веб-пÑ\80иложений.
+Ð\92Ñ\8b вÑ\80Ñ\8fд ли заÑ\85оÑ\82иÑ\82е взÑ\8fÑ\82Ñ\8c Ñ\81воÑ\8e возлÑ\8eбленнÑ\83Ñ\8e ð\9f\98\8d Ñ\81 Ñ\81обой, Ñ\87Ñ\82обÑ\8b занÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f делами в банке ð\9f\8f¦.
-Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению.
+### Вывод про бургеры { #burger-conclusion }
-Ð\9fоÑ\82ом Ñ\81нова ждаÑ\82Ñ\8c ð\9f\95\99, пока веÑ\80нÑ\91Ñ\82Ñ\81Ñ\8f оÑ\82веÑ\82.
+Ð\92 Ñ\8dÑ\82ом Ñ\81Ñ\86енаÑ\80ии «Ñ\84аÑ\81Ñ\82Ñ\84Ñ\83да Ñ\81 ваÑ\88ей возлÑ\8eбленной», Ñ\82ак как много ожиданиÑ\8f ð\9f\95\99, гоÑ\80аздо логиÑ\87нее имеÑ\82Ñ\8c конкÑ\83Ñ\80енÑ\82нÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 â\8f¸ð\9f\94\80â\8f¯.
-<!--https://forum.wordreference.com/threads/%D0%9D%D0%BE-%D0%B5%D1%81%D0%BB%D0%B8.3258695/-->
-Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени.
+Так обстоит дело и с большинством веб-приложений.
-Ð\92оÑ\82 поÑ\87емÑ\83 еÑ\81Ñ\82Ñ\8c Ñ\81мÑ\8bÑ\81л иÑ\81полÑ\8cзоваÑ\82Ñ\8c аÑ\81инÑ\85Ñ\80онное â\8f¸ð\9f\94\80â\8f¯ пÑ\80огÑ\80аммиÑ\80ование пÑ\80и поÑ\81Ñ\82Ñ\80оении веб-API.
+Ð\9eÑ\87енÑ\8c много полÑ\8cзоваÑ\82елей, но ваÑ\88 Ñ\81еÑ\80веÑ\80 ждÑ\91Ñ\82 ð\9f\95\99, пока иÑ\85 не Ñ\81амое Ñ\85оÑ\80оÑ\88ее Ñ\81оединение оÑ\82пÑ\80авиÑ\82 иÑ\85 запÑ\80оÑ\81Ñ\8b.
-Большинство популярных фреймворков (включая Flask и Django) создавались
-до появления в Python новых возможностей асинхронного программирования. Поэтому
-их можно разворачивать с поддержкой параллельного исполнения или асинхронного
-программирования старого типа, которое не настолько эффективно.
+А затем снова ждёт 🕙, пока отправятся ответы.
-При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером
-(<a href="https://asgi.readthedocs.io" class="external-link" target="_blank">ASGI</a>)
-была разработана командой Django для внедрения поддержки веб-сокетов.
+Это «ожидание» 🕙 измеряется микросекундами, но если всё сложить, то в сумме получается много ожидания.
-Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный),
-и в этом преимущество Go как языка программирования.
+Вот почему асинхронный ⏸🔀⏯ код очень уместен для веб-API.
-И тот же уровень производительности даёт **FastAPI**.
+Именно такая асинхронность сделала NodeJS популярным (хотя NodeJS — не параллельный), и это сильная сторона Go как языка программирования.
-Поскольку можно использовать преимущества параллелизма и асинхронности вместе,
-вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков
-и на уровне с Go, который является компилируемым языком близким к C <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(всё благодаря Starlette)</a>.
+Того же уровня производительности вы получаете с **FastAPI**.
-### Получается, конкурентность лучше параллелизма?
+А так как можно одновременно использовать параллелизм и асинхронность, вы получаете производительность выше, чем у большинства протестированных фреймворков на NodeJS и на уровне Go, который — компилируемый язык, ближе к C <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(всё благодаря Starlette)</a>.
-Нет! Мораль истории совсем не в этом.
+### Конкурентность лучше параллелизма? { #is-concurrency-better-than-parallelism }
-Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание.
-Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях.
+Нет! Мораль истории не в этом.
-Ð\94авайÑ\82е поÑ\81моÑ\82Ñ\80им Ñ\81 дÑ\80Ñ\83гой Ñ\81Ñ\82оÑ\80онÑ\8b, пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е Ñ\82акÑ\83Ñ\8e каÑ\80Ñ\82инÑ\83:
+Ð\9aонкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c оÑ\82лиÑ\87аеÑ\82Ñ\81Ñ\8f оÑ\82 паÑ\80аллелизма. Ð\98 она лÑ\83Ñ\87Ñ\88е в **конкÑ\80еÑ\82нÑ\8bÑ\85** Ñ\81Ñ\86енаÑ\80иÑ\8fÑ\85, где много ожиданиÑ\8f. Ð\9fоÑ\8dÑ\82омÑ\83 пÑ\80и Ñ\80азÑ\80абоÑ\82ке веб-пÑ\80иложений она обÑ\8bÑ\87но намного лÑ\83Ñ\87Ñ\88е паÑ\80аллелизма. Ð\9dо не во вÑ\81Ñ\91м.
-> Вам нужно убраться в большом грязном доме.
+Чтобы уравновесить это, представьте такую короткую историю:
+
+> Вам нужно убрать большой грязный дом.
*Да, это вся история*.
---
-ТÑ\83Ñ\82 не нÑ\83жно нигде ждаÑ\82Ñ\8c ð\9f\95\99, пÑ\80оÑ\81Ñ\82о еÑ\81Ñ\82Ñ\8c кÑ\83Ñ\87а Ñ\80абоÑ\82Ñ\8b в Ñ\80азнÑ\8bÑ\85 Ñ\87аÑ\81Ñ\82Ñ\8fх дома.
+Ð\97деÑ\81Ñ\8c нигде неÑ\82 ожиданиÑ\8f ð\9f\95\99, пÑ\80оÑ\81Ñ\82о оÑ\87енÑ\8c много Ñ\80абоÑ\82Ñ\8b в Ñ\80азнÑ\8bÑ\85 меÑ\81Ñ\82ах дома.
-Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня,
-но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете.
+Можно организовать «очереди» как в примере с бургерами — сначала гостиная, потом кухня, — но так как вы ничего не ждёте 🕙, а просто убираете и убираете, очереди ни на что не повлияют.
-И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё,
-и работы будет сделано тоже одинаковое количество.
+На завершение уйдёт одинаковое время — с очередями (конкурентностью) и без них — и объём выполненной работы будет одинаковым.
-Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳,
-и каждый из них (вместе с вами) взялся бы за свой участок дома,
-с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**.
+Но в этом случае, если бы вы могли привести 8 бывших кассиров/поваров, а теперь — уборщиков, и каждый из них (плюс вы) взял бы свою зону дома для уборки, вы могли бы сделать всю работу **параллельно**, с дополнительной помощью, и завершить гораздо быстрее.
-В описанном сценарии каждый уборщик (включая вас) был бы исполнителем, занятым на своём участке работы.
+В этом сценарии каждый уборщик (включая вас) был бы процессором, выполняющим свою часть работы.
-И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание),
-а работу в компьютере делает <abbr title="Центральный процессор (CPU)">ЦП</abbr>,
-такие задачи называют <abbr title="CPU bound">ограниченными производительностью процессора</abbr>.
+И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет <abbr title="Central Processing Unit – Центральный процессор">CPU</abbr>, такие задачи называют «ограниченными процессором» (CPU bound).
---
-Ð\9eгÑ\80аниÑ\87ение по пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80Ñ\83 пÑ\80оÑ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f в опеÑ\80аÑ\86иÑ\8fÑ\85, где Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f вÑ\8bполнÑ\8fÑ\82Ñ\8c Ñ\81ложнÑ\8bе маÑ\82емаÑ\82иÑ\87еÑ\81кие вÑ\8bÑ\87иÑ\81лениÑ\8f.
+ТипиÑ\87нÑ\8bе пÑ\80имеÑ\80Ñ\8b CPU-bound опеÑ\80аÑ\86ий â\80\94 Ñ\82е, коÑ\82оÑ\80Ñ\8bе Ñ\82Ñ\80ебÑ\83Ñ\8eÑ\82 Ñ\81ложной маÑ\82емаÑ\82иÑ\87еÑ\81кой обÑ\80абоÑ\82ки.
Например:
-* Обработка **звука** или **изображений**.
-* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета,
-обработка обычно требует проведения расчётов по всем пикселям сразу.
-* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов".
-Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить.
-* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание.
-Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется
-специальный процессор для создания и / или использования построенных таким образом моделей.
+* Обработка **аудио** или **изображений**.
+* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения/цвета; обычно требуется вычислить что-то для всех этих пикселей одновременно.
+* **Машинное обучение**: обычно требует множества умножений «матриц» и «векторов». Представьте огромную таблицу с числами и умножение всех этих чисел «одновременно».
+* **Глубокое обучение**: это подполе Машинного обучения, так что всё вышесказанное применимо. Просто это не одна таблица чисел, а их огромный набор, и во многих случаях вы используете специальный процессор, чтобы строить и/или использовать такие модели.
-### Ð\9aонкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c + паÑ\80аллелизм: Ð\92еб + маÑ\88инное обÑ\83Ñ\87ение
+### Ð\9aонкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c + паÑ\80аллелизм: Ð\92еб + Ð\9cаÑ\88инное обÑ\83Ñ\87ение { #concurrency-parallelism-web-machine-learning }
-**FastAPI** предоставляет возможности конкуретного программирования,
-которое очень распространено в веб-разработке (именно этим славится NodeJS).
+С **FastAPI** вы можете использовать преимущества конкурентности, что очень распространено в веб-разработке (это та же основная «фишка» NodeJS).
-Кроме того вы сможете использовать все преимущества параллелизма и
-<abbr title="multiprocessing">многопроцессорности</abbr> (когда несколько процессов работают параллельно),
-если рабочая нагрузка предполагает **ограничение по процессору**,
-как, например, в системах машинного обучения. <!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_329-->
+Но вы также можете использовать выгоды параллелизма и многопроцессности (когда несколько процессов работают параллельно) для рабочих нагрузок, **ограниченных процессором** (CPU bound), как в системах Машинного обучения.
-Необходимо также отметить, что Python является главным языком в области
-<abbr title="наука о данных (data science)">**дата-сайенс**</abbr>,
-машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI
-отличным вариантом (среди многих других) для разработки веб-API и приложений
-в области дата-сайенс / машинного обучения.
+Плюс к этому простой факт, что Python — основной язык для **Data Science**, Машинного обучения и особенно Глубокого обучения, делает FastAPI очень хорошим выбором для веб-API и приложений в области Data Science / Машинного обучения (среди многих других).
-Как добиться такого параллелизма в эксплуатации описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}.
+Как добиться такого параллелизма в продакшн, см. раздел [Развёртывание](deployment/index.md){.internal-link target=_blank}.
-## `async` и `await`
+## `async` и `await` { #async-and-await }
-В современных версиях Python разработка асинхронного кода реализована очень интуитивно.
-Он выглядит как обычный "последовательный" код и самостоятельно выполняет "ожидание", когда это необходимо.
+В современных версиях Python есть очень интуитивный способ определять асинхронный код. Это делает его похожим на обычный «последовательный» код, а «ожидание» выполняется за вас в нужные моменты.
-Если некая операция требует ожидания перед тем, как вернуть результат, и
-поддерживает современные возможности Python, код можно написать следующим образом:
+Когда есть операция, которой нужно подождать перед тем, как вернуть результат, и она поддерживает эти новые возможности Python, вы можете написать так:
```Python
burgers = await get_burgers(2)
```
-Главное здесь слово `await`. Оно сообщает интерпретатору, что необходимо дождаться ⏸
-пока `get_burgers(2)` закончит свои дела 🕙, и только после этого сохранить результат в `burgers`.
-Зная это, Python может пока переключиться на выполнение других задач 🔀 ⏯
-(например получение следующего запроса).<!--http://new.gramota.ru/spravka/buro/search-answer?s=296614-->
+Ключ здесь — `await`. Он говорит Python, что нужно подождать ⏸, пока `get_burgers(2)` закончит своё дело 🕙, прежде чем сохранять результат в `burgers`. Благодаря этому Python будет знать, что за это время можно заняться чем-то ещё 🔀 ⏯ (например, принять другой запрос).
-Чтобы ключевое слово `await` сработало, оно должно находиться внутри функции,
-которая поддерживает асинхронность. Для этого вам просто нужно объявить её как `async def`:
+Чтобы `await` работал, он должен находиться внутри функции, которая поддерживает такую асинхронность. Для этого просто объявите её с `async def`:
```Python hl_lines="1"
async def get_burgers(number: int):
- # Ð\93оÑ\82овим бÑ\83Ñ\80геÑ\80Ñ\8b по Ñ\81пеÑ\86иалÑ\8cномÑ\83 аÑ\81инÑ\85Ñ\80онномÑ\83 Ñ\80еÑ\86епÑ\82Ñ\83
+ # СделаÑ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о аÑ\81инÑ\85Ñ\80онное, Ñ\87Ñ\82обÑ\8b пÑ\80игоÑ\82овиÑ\82Ñ\8c бÑ\83Ñ\80геÑ\80Ñ\8b
return burgers
```
```Python hl_lines="2"
# Это не асинхронный код
def get_sequential_burgers(number: int):
- # Ð\93оÑ\82овим бÑ\83Ñ\80геÑ\80Ñ\8b поÑ\81ледоваÑ\82елÑ\8cно по Ñ\88агам
+ # СделаÑ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о поÑ\81ледоваÑ\82елÑ\8cное, Ñ\87Ñ\82обÑ\8b пÑ\80игоÑ\82овиÑ\82Ñ\8c бÑ\83Ñ\80геÑ\80Ñ\8b
return burgers
```
-Объявление `async def` указывает интерпретатору, что внутри этой функции
-следует ожидать выражений `await`, и что можно поставить выполнение такой функции на "паузу" ⏸ и
-переключиться на другие задачи 🔀, с тем чтобы вернуться сюда позже.
+С `async def` Python знает, что внутри этой функции нужно учитывать выражения `await` и что выполнение такой функции можно «приостанавливать» ⏸ и идти делать что-то ещё 🔀, чтобы потом вернуться.
-Если вы хотите вызвать функцию с `async def`, вам нужно <abbr title="await">"ожидать"</abbr> её.
-Поэтому такое не сработает:
+Когда вы хотите вызвать функцию, объявленную с `async def`, нужно её «ожидать». Поэтому вот так не сработает:
```Python
-# Это не заработает, поскольку get_burgers объявлена с использованием async def
+# Это не сработает, потому что get_burgers определена с: async def
burgers = get_burgers(2)
```
---
-Если сторонняя библиотека требует вызывать её с ключевым словом `await`,
-необходимо писать *функции обработки пути* с использованием `async def`, например:
+Итак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функцию-обработчик пути*, которая её использует, с `async def`, например:
```Python hl_lines="2-3"
@app.get('/burgers')
return burgers
```
-### Технические подробности
+### Более технические подробности { #more-technical-details }
+
+Вы могли заметить, что `await` можно использовать только внутри функций, определённых с `async def`.
-Ð\9aак вÑ\8b могли замеÑ\82иÑ\82Ñ\8c, `await` можеÑ\82 пÑ\80именÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f Ñ\82олÑ\8cко в Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85, обÑ\8aÑ\8fвленнÑ\8bÑ\85 Ñ\81 иÑ\81полÑ\8cзованием `async def`.
+Ð\9dо пÑ\80и Ñ\8dÑ\82ом Ñ\84Ñ\83нкÑ\86ии, опÑ\80еделÑ\91ннÑ\8bе Ñ\81 `async def`, нÑ\83жно «ожидаÑ\82Ñ\8c». Ð\97наÑ\87иÑ\82, Ñ\84Ñ\83нкÑ\86ии Ñ\81 `async def` Ñ\82оже можно вÑ\8bзÑ\8bваÑ\82Ñ\8c Ñ\82олÑ\8cко из Ñ\84Ñ\83нкÑ\86ий, опÑ\80еделÑ\91ннÑ\8bÑ\85 Ñ\81 `async def`.
-<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_128-->
-Но выполнение такой функции необходимо "ожидать" с помощью `await`.
-Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`.
+Так что же с «яйцом и курицей» — как вызвать первую `async` функцию?
-Ð\9dо как же Ñ\82огда поÑ\8fвилаÑ\81Ñ\8c пеÑ\80ваÑ\8f <abbr title="или Ñ\8fйÑ\86о?ð\9f¤\94">кÑ\83Ñ\80иÑ\86а</abbr>? Ð\92 Ñ\81мÑ\8bÑ\81ле... как нам вÑ\8bзваÑ\82Ñ\8c пеÑ\80вÑ\83Ñ\8e аÑ\81инÑ\85Ñ\80оннÑ\83Ñ\8e Ñ\84Ñ\83нкÑ\86иÑ\8e?
+Ð\95Ñ\81ли вÑ\8b Ñ\80абоÑ\82аеÑ\82е Ñ\81 **FastAPI**, вам не о Ñ\87ем беÑ\81покоиÑ\82Ñ\8cÑ\81Ñ\8f, поÑ\82омÑ\83 Ñ\87Ñ\82о Ñ\8dÑ\82ой «пеÑ\80вой» Ñ\84Ñ\83нкÑ\86ией бÑ\83деÑ\82 ваÑ\88а *Ñ\84Ñ\83нкÑ\86иÑ\8f-обÑ\80абоÑ\82Ñ\87ик пÑ\83Ñ\82и*, а FastAPI знаеÑ\82, как Ñ\81делаÑ\82Ñ\8c вÑ\81Ñ\91 пÑ\80авилÑ\8cно.
-При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*,
-и дальше с этим разберётся FastAPI.
+Но если вы хотите использовать `async` / `await` без FastAPI, вы тоже можете это сделать.
-Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI.
+### Пишите свой асинхронный код { #write-your-own-async-code }
-### Пишите свой асинхронный код
+Starlette (и **FastAPI**) основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, что делает их совместимыми и со стандартной библиотекой Python <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a>, и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
-Starlette (и **FastAPI**) основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, что делает их совместимыми как со стандартной библиотекой <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> в Python, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.<!--http://new.gramota.ru/spravka/buro/search-answer?s=285295-->
+В частности, вы можете напрямую использовать <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> для продвинутых сценариев конкурентности, где в вашем коде нужны более сложные паттерны.
-Ð\92 Ñ\87аÑ\81Ñ\82ноÑ\81Ñ\82и, вÑ\8b можеÑ\82е напÑ\80Ñ\8fмÑ\83Ñ\8e иÑ\81полÑ\8cзоваÑ\82Ñ\8c <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> в Ñ\82еÑ\85 пÑ\80оекÑ\82аÑ\85, где Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f более Ñ\81ложнаÑ\8f логика Ñ\80абоÑ\82Ñ\8b Ñ\81 конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8cÑ\8e.
+Ð\98 даже еÑ\81ли вÑ\8b не иÑ\81полÑ\8cзÑ\83еÑ\82е FastAPI, вÑ\8b можеÑ\82е пиÑ\81аÑ\82Ñ\8c Ñ\81вои аÑ\81инÑ\85Ñ\80оннÑ\8bе пÑ\80иложениÑ\8f Ñ\81 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, Ñ\87Ñ\82обÑ\8b они бÑ\8bли макÑ\81ималÑ\8cно Ñ\81овмеÑ\81Ñ\82имÑ\8bми и полÑ\83Ñ\87али его пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82ва (напÑ\80имеÑ\80, *Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80нÑ\83Ñ\8e конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c*).
-Ð\94аже еÑ\81ли вÑ\8b не иÑ\81полÑ\8cзÑ\83еÑ\82е FastAPI, вÑ\8b можеÑ\82е пиÑ\81аÑ\82Ñ\8c аÑ\81инÑ\85Ñ\80оннÑ\8bе пÑ\80иложениÑ\8f Ñ\81 помоÑ\89Ñ\8cÑ\8e <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, Ñ\87Ñ\82обÑ\8b они бÑ\8bли макÑ\81ималÑ\8cно Ñ\81овмеÑ\81Ñ\82имÑ\8bми и полÑ\83Ñ\87али его пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82ва (напÑ\80имеÑ\80 *Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80нÑ\83Ñ\8e конкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c*).
+Я Ñ\81оздал еÑ\89Ñ\91 однÑ\83 библиоÑ\82екÑ\83 повеÑ\80Ñ\85 AnyIO, Ñ\82онкий Ñ\81лой, Ñ\87Ñ\82обÑ\8b немного Ñ\83лÑ\83Ñ\87Ñ\88иÑ\82Ñ\8c анноÑ\82аÑ\86ии Ñ\82ипов и полÑ\83Ñ\87иÑ\82Ñ\8c более каÑ\87еÑ\81Ñ\82венное **авÑ\82озавеÑ\80Ñ\88ение**, **оÑ\88ибки пÑ\80Ñ\8fмо в Ñ\80едакÑ\82оÑ\80е** и Ñ\82.д. Там Ñ\82акже еÑ\81Ñ\82Ñ\8c дÑ\80Ñ\83желÑ\8eбное введение и Ñ\80Ñ\83ководÑ\81Ñ\82во, Ñ\87Ñ\82обÑ\8b помоÑ\87Ñ\8c вам **понÑ\8fÑ\82Ñ\8c** и пиÑ\81аÑ\82Ñ\8c **Ñ\81вой Ñ\81обÑ\81Ñ\82веннÑ\8bй аÑ\81инÑ\85Ñ\80оннÑ\8bй код**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. Ð\9eна оÑ\81обенно полезна, еÑ\81ли вам нÑ\83жно **комбиниÑ\80оваÑ\82Ñ\8c аÑ\81инÑ\85Ñ\80оннÑ\8bй код Ñ\81 обÑ\8bÑ\87нÑ\8bм** (блокиÑ\80Ñ\83Ñ\8eÑ\89им/Ñ\81инÑ\85Ñ\80оннÑ\8bм) кодом.
-### Другие виды асинхронного программирования
+### Другие формы асинхронного кода { #other-forms-of-asynchronous-code }
-СÑ\82илÑ\8c напиÑ\81аниÑ\8f кода Ñ\81 `async` и `await` поÑ\8fвилÑ\81Ñ\8f в Ñ\8fзÑ\8bке Python оÑ\82ноÑ\81иÑ\82елÑ\8cно недавно.
+Такой Ñ\81Ñ\82илÑ\8c иÑ\81полÑ\8cзованиÑ\8f `async` и `await` оÑ\82ноÑ\81иÑ\82елÑ\8cно новÑ\8bй в Ñ\8fзÑ\8bке.
-Но он сильно облегчает работу с асинхронным кодом.
+Но он сильно упрощает работу с асинхронным кодом.
-Ровно Ñ\82акой же Ñ\81инÑ\82акÑ\81иÑ\81 (нÑ\83 или поÑ\87Ñ\82и Ñ\82акой же) недавно бÑ\8bл вклÑ\8eÑ\87Ñ\91н в Ñ\81овÑ\80еменнÑ\8bе веÑ\80Ñ\81ии JavaScript (в браузере и NodeJS).
+Такой же (или поÑ\87Ñ\82и Ñ\82акой же) Ñ\81инÑ\82акÑ\81иÑ\81 недавно поÑ\8fвилÑ\81Ñ\8f в Ñ\81овÑ\80еменнÑ\8bÑ\85 веÑ\80Ñ\81иÑ\8fÑ\85 JavaScript (в браузере и NodeJS).
-До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать.
+До этого работа с асинхронным кодом была заметно сложнее и труднее для понимания.
-Ð\92 пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 веÑ\80Ñ\81иÑ\8fÑ\85 Python длÑ\8f Ñ\8dÑ\82ого иÑ\81полÑ\8cзовалиÑ\81Ñ\8c поÑ\82оки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Ð\9dо Ñ\82акой код намного Ñ\81ложнее понимаÑ\82Ñ\8c, оÑ\82лаживаÑ\82Ñ\8c и мÑ\8bÑ\81ленно пÑ\80едÑ\81Ñ\82авлÑ\8fÑ\82Ñ\8c.
+Ð\92 пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 веÑ\80Ñ\81иÑ\8fÑ\85 Python можно бÑ\8bло иÑ\81полÑ\8cзоваÑ\82Ñ\8c поÑ\82оки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Ð\9dо Ñ\82акой код гоÑ\80аздо Ñ\81ложнее понимаÑ\82Ñ\8c, оÑ\82лаживаÑ\82Ñ\8c и деÑ\80жаÑ\82Ñ\8c в голове.
-Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели
-<abbr title="callback">"обратные вызовы"</abbr>. Что выливалось в
-"ад обратных вызовов".
+В прежних версиях NodeJS/браузерного JavaScript вы бы использовали «callbacks» (обратные вызовы), что приводит к «callback hell» (ад обратных вызовов).
-## Сопрограммы
+## Сопрограммы { #coroutines }
-<abbr title="coroutine">**Корути́на**</abbr> (или же сопрограмма) — это крутое словечко для именования той сущности,
-которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию,
-но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`.
+**Сопрограмма** (coroutine) — это просто «навороченное» слово для того, что возвращает функция `async def`. Python знает, что это похоже на функцию: её можно запустить, она когда-нибудь завершится, но её выполнение может приостанавливаться ⏸ внутри, когда встречается `await`.
-Всю функциональность асинхронного программирования с использованием `async` и `await`
-часто обобщают словом "корутины". Они аналогичны <abbr title="Goroutines">"горутинам"</abbr>, ключевой особенности
-языка Go.
+Часто всю функциональность использования асинхронного кода с `async` и `await` кратко называют «сопрограммами». Это сопоставимо с ключевой особенностью Go — «goroutines».
-## Заключение
+## Заключение { #conclusion }
-В самом начале была такая фраза:
+Вернёмся к той же фразе:
-> Современные версии Python поддерживают разработку так называемого
-**"асинхронного кода"** посредством написания **"сопрограмм"** с использованием
-синтаксиса **`async` и `await`**.
+> Современные версии Python поддерживают **«асинхронный код»** с помощью **«сопрограмм»** (coroutines) и синтаксиса **`async` и `await`**.
-Теперь всё должно звучать понятнее. ✨
+Теперь это должно звучать понятнее. ✨
-На этом основана работа FastAPI (посредством Starlette), и именно это
-обеспечивает его высокую производительность.
+Именно это «движет» FastAPI (через Starlette) и обеспечивает столь впечатляющую производительность.
-## Очень технические подробности
+## Очень технические подробности { #very-technical-details }
-/// warning
+/// warning | Предупреждение
-ÐÑ\82оÑ\82 Ñ\80аздел Ñ\87иÑ\82аÑ\82Ñ\8c не обÑ\8fзаÑ\82елÑ\8cно.
+СкоÑ\80ее вÑ\81его, Ñ\8dÑ\82оÑ\82 Ñ\80аздел можно пÑ\80опÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c.
-Здесь приводятся подробности внутреннего устройства **FastAPI**.
+Здесь — очень технические подробности о том, как **FastAPI** работает «под капотом».
-Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.)
-и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`,
-читайте дальше.
+Если у вас есть достаточно технических знаний (сопрограммы, потоки, блокировки и т.д.) и вам интересно, как FastAPI обрабатывает `async def` по сравнению с обычным `def`, — вперёд.
///
-### Функции обработки пути
+### Функции-обработчики пути { #path-operation-functions }
-Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def`
-вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем
-<abbr title="threadpool">пуле потоков</abbr>, а не напрямую (это бы заблокировало сервер).
+Когда вы объявляете *функцию-обработчик пути* обычным `def` вместо `async def`, она запускается во внешнем пуле потоков, который затем «ожидается», вместо прямого вызова (прямой вызов заблокировал бы сервер).
-Если ранее вы использовали другой асинхронный фреймворк, который работает иначе,
-и привыкли объявлять простые вычислительные *функции* через `def` ради
-незначительного прироста скорости (порядка 100 наносекунд), обратите внимание,
-что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит
-`async def`, если только *функция обработки пути* не использует код, приводящий
-к блокировке <abbr title="Ввод/вывод: чтение и запись на диск, сетевые соединения.">I/O</abbr>.
-<!--Уточнить: Не использовать async def, если код приводит к блокировке IO?-->
+Если вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий <abbr title="Input/Output – Ввод/вывод: чтение или запись на диск, сетевые соединения.">I/O</abbr>.
-<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_285-->
-Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](index.md#_11){.internal-link target=_blank}
-другого фреймворка (или хотя бы на уровне с ним).
+Тем не менее, в обоих случаях велика вероятность, что **FastAPI** [всё равно будет быстрее](index.md#performance){.internal-link target=_blank} (или как минимум сопоставим) с вашим предыдущим фреймворком.
-### Зависимости
+### Зависимости { #dependencies }
-То же относится к зависимостям. Если это обычная функция `def`, а не `async def`,
-она запускается во внешнем пуле потоков.
+То же относится к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость — это обычная функция `def`, а не `async def`, она запускается во внешнем пуле потоков.
-### Подзависимости
+### Подзависимости { #sub-dependencies }
-Вы можете объявить множество ссылающихся друг на друга зависимостей и подзависимостей
-(в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`,
-другие обычным образом через `def`, и такая схема вполне работоспособна. Функции,
-объявленные с помощью `def` будут запускаться на внешнем потоке (из пула),
-а не с помощью `await`.
+У вас может быть несколько зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}, которые требуют друг друга (в виде параметров определений функций): часть из них может быть объявлена с `async def`, а часть — обычным `def`. Всё будет работать, а те, что объявлены обычным `def`, будут вызываться во внешнем потоке (из пула), а не «ожидаться».
-### Другие служебные функции
+### Другие служебные функции { #other-utility-functions }
-Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять
-с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы
-их запускаете.
+Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять обычным `def` или `async def`, и FastAPI не будет влиять на то, как вы их вызываете.
-Этим они отличаются от функций, которые FastAPI вызывает самостоятельно:
-*функции обработки пути* и зависимости.
+В отличие от функций, которые FastAPI вызывает за вас: *функции-обработчики пути* и зависимости.
-Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую
-(как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с
-помощью `async def`, её вызов должен осуществляться с ожиданием через `await`.
+Если служебная функция — обычная функция с `def`, она будет вызвана напрямую (как вы и пишете в коде), не в пуле потоков; если функция объявлена с `async def`, тогда при её вызове в вашем коде вы должны использовать `await`.
---
-<!--http://new.gramota.ru/spravka/buro/search-answer?s=299749-->
-Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали.
+Снова: это очень технические подробности, полезные, вероятно, только если вы целенаправленно их ищете.
-Ð\92 пÑ\80оÑ\82ивном Ñ\81лÑ\83Ñ\87ае пÑ\80оÑ\81Ñ\82о ознакомÑ\8cÑ\82еÑ\81Ñ\8c Ñ\81 оÑ\81новнÑ\8bми пÑ\80инÑ\86ипами в Ñ\80азделе вÑ\8bÑ\88е: <a href="#_1">Нет времени?</a>.
+Ð\98наÑ\87е вам доÑ\81Ñ\82аÑ\82оÑ\87но Ñ\80Ñ\83ководÑ\81Ñ\82воваÑ\82Ñ\8cÑ\81Ñ\8f Ñ\80екомендаÑ\86иÑ\8fми из Ñ\80аздела вÑ\8bÑ\88е: <a href="#in-a-hurry">Нет времени?</a>.
-# Ð\97амеÑ\80Ñ\8b пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и
+# Ð\91енÑ\87маÑ\80ки (Ñ\82еÑ\81Ñ\82Ñ\8b пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и) { #benchmarks }
-Независимые тесты производительности приложений от TechEmpower показывают, что **FastAPI** под управлением Uvicorn <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">один из самых быстрых Python-фреймворков</a> и уступает только Starlette и Uvicorn (которые используются в FastAPI). (*)
+Независимые бенчмарки TechEmpower показывают, что приложения **FastAPI** под управлением Uvicorn — <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">одни из самых быстрых Python‑фреймворков</a>, уступающие только Starlette и самому Uvicorn (используются внутри FastAPI).
-Ð\9dо пÑ\80и пÑ\80оÑ\81моÑ\82Ñ\80е и Ñ\81Ñ\80авнении замеÑ\80ов пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и Ñ\81ледÑ\83еÑ\82 имеÑ\82Ñ\8c в видÑ\83 нижеопиÑ\81анное.
+Ð\9dо пÑ\80и пÑ\80оÑ\81моÑ\82Ñ\80е бенÑ\87маÑ\80ков и Ñ\81Ñ\80авнений Ñ\81ледÑ\83еÑ\82 имеÑ\82Ñ\8c в видÑ\83 Ñ\81ледÑ\83Ñ\8eÑ\89ее.
-## Ð\97амеÑ\80Ñ\8b пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82и и Ñ\81коÑ\80оÑ\81Ñ\82и
+## Ð\91енÑ\87маÑ\80ки и Ñ\81коÑ\80оÑ\81Ñ\82Ñ\8c { #benchmarks-and-speed }
-Ð\92 подобнÑ\8bÑ\85 Ñ\82еÑ\81Ñ\82аÑ\85 Ñ\87аÑ\81Ñ\82о можно Ñ\83видеÑ\82Ñ\8c, Ñ\87Ñ\82о инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b Ñ\80азного Ñ\82ипа Ñ\81Ñ\80авниваÑ\8eÑ\82 дÑ\80Ñ\83г Ñ\81 дÑ\80Ñ\83гом, как аналогиÑ\87ные.
+Ð\9fÑ\80и пÑ\80овеÑ\80ке бенÑ\87маÑ\80ков Ñ\87аÑ\81Ñ\82о можно Ñ\83видеÑ\82Ñ\8c, Ñ\87Ñ\82о инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b Ñ\80азнÑ\8bÑ\85 Ñ\82ипов Ñ\81Ñ\80авниваÑ\8eÑ\82 как Ñ\8dквиваленÑ\82ные.
-В частности, сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов).
+Ð\92 Ñ\87аÑ\81Ñ\82ноÑ\81Ñ\82и, Ñ\87аÑ\81Ñ\82о Ñ\81Ñ\80авниваÑ\8eÑ\82 вмеÑ\81Ñ\82е Uvicorn, Starlette и FastAPI (Ñ\81Ñ\80еди многиÑ\85 дÑ\80Ñ\83гиÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов).
-Чем пÑ\80оÑ\89е пÑ\80облема, коÑ\82оÑ\80Ñ\83Ñ\8e Ñ\80еÑ\88аеÑ\82 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82, Ñ\82ем вÑ\8bÑ\88е его пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c. Ð\98 болÑ\8cÑ\88инÑ\81Ñ\82во Ñ\82еÑ\81Ñ\82ов не пÑ\80овеÑ\80Ñ\8fÑ\8eÑ\82 дополниÑ\82елÑ\8cнÑ\8bе Ñ\84Ñ\83нкÑ\86ии, предоставляемые инструментом.
+Чем пÑ\80оÑ\89е задаÑ\87а, коÑ\82оÑ\80Ñ\83Ñ\8e Ñ\80еÑ\88аеÑ\82 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82, Ñ\82ем вÑ\8bÑ\88е его пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c. Ð\98 болÑ\8cÑ\88инÑ\81Ñ\82во бенÑ\87маÑ\80ков не Ñ\82еÑ\81Ñ\82иÑ\80Ñ\83Ñ\8eÑ\82 дополниÑ\82елÑ\8cнÑ\8bе возможноÑ\81Ñ\82и, предоставляемые инструментом.
-Ð\98еÑ\80аÑ\80Ñ\85иÑ\8f инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов имееÑ\82 Ñ\81ледÑ\83Ñ\8eÑ\89ий вид:
+Ð\98еÑ\80аÑ\80Ñ\85иÑ\8f вÑ\8bглÑ\8fдиÑ\82 Ñ\82ак:
* **Uvicorn**: ASGI-сервер
- * **Starlette** (использует Uvicorn): веб-микрофреймворк
- * **FastAPI** (использует Starlette): API-микрофреймворк с дополнительными функциями для создания API, с валидацией данных и т.д.
+ * **Starlette**: (использует Uvicorn) веб-микрофреймворк
+ * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т. п.
* **Uvicorn**:
- * Будет иметь наилучшую производительность, так как не имеет большого количества дополнительного кода, кроме самого сервера.
- * Вы не будете писать приложение на Uvicorn напрямую. Это означало бы, что Ваш код должен включать как минимум весь
- код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки.
- * Uvicorn подлежит сравнению с Daphne, Hypercorn, uWSGI и другими веб-серверами.
-
+ * Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода.
+ * Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки.
+ * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т. д. — серверами приложений.
* **Starlette**:
- * Будет уступать Uvicorn по производительности. Фактически Starlette управляется Uvicorn и из-за выполнения большего количества кода он не может быть быстрее, чем Uvicorn.
- * Зато он предоставляет Вам инструменты для создания простых веб-приложений с обработкой маршрутов URL и т.д.
- * Starlette следует сравнивать с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками).
-
+ * Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода.
+ * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т. п.
+ * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т. д. — веб‑фреймворками (или микрофреймворками).
* **FastAPI**:
- * Так же как Starlette иÑ\81полÑ\8cзÑ\83еÑ\82 Uvicorn и не можеÑ\82 бÑ\8bÑ\82Ñ\8c бÑ\8bÑ\81Ñ\82Ñ\80ее него, **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Starlette, Ñ\82о еÑ\81Ñ\82Ñ\8c он не можеÑ\82 бÑ\8bÑ\82Ñ\8c бÑ\8bÑ\81Ñ\82Ñ\80ее Starlette.
- * FastAPI предоставляет больше возможностей поверх Starlette, которые наверняка Вам понадобятся при создании API, такие как проверка данных и сериализация. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске).
- * Ð\95Ñ\81ли Ð\92Ñ\8b не иÑ\81полÑ\8cзÑ\83еÑ\82е FastAPI, а иÑ\81полÑ\8cзÑ\83еÑ\82е Starlette напÑ\80Ñ\8fмÑ\83Ñ\8e (или дÑ\80Ñ\83гой инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82 вÑ\80оде Sanic, Flask, Responder и Ñ\82.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
- * Таким образом, используя FastAPI Вы потратите меньше времени на разработку, уменьшите количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своем коде).
- * FastAPI должно сравнивать с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные.
+ * ТоÑ\87но Ñ\82ак же, как Starlette иÑ\81полÑ\8cзÑ\83еÑ\82 Uvicorn и не можеÑ\82 бÑ\8bÑ\82Ñ\8c бÑ\8bÑ\81Ñ\82Ñ\80ее него, **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Starlette, поÑ\8dÑ\82омÑ\83 не можеÑ\82 бÑ\8bÑ\82Ñ\8c бÑ\8bÑ\81Ñ\82Ñ\80ее его.
+ * FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске).
+ * Ð\95Ñ\81ли бÑ\8b Ð\92Ñ\8b не иÑ\81полÑ\8cзовали FastAPI, а иÑ\81полÑ\8cзовали Starlette напÑ\80Ñ\8fмÑ\83Ñ\8e (или дÑ\80Ñ\83гой инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82 вÑ\80оде Sanic, Flask, Responder и Ñ\82. д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
+ * Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде).
+ * Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией.
-# Концепции развёртывания
+# Концепции развёртывания { #deployments-concepts }
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 неÑ\81колÑ\8cко конÑ\86епÑ\86ий, пÑ\80именÑ\8fемÑ\8bÑ\85 длÑ\8f Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f пÑ\80иложений **FastAPI**, Ñ\80авно как и длÑ\8f лÑ\8eбÑ\8bÑ\85 дÑ\80Ñ\83гиÑ\85 Ñ\82ипов веб-пÑ\80иложений, Ñ\81Ñ\80еди коÑ\82оÑ\80Ñ\8bÑ\85 вÑ\8b можеÑ\82е вÑ\8bбÑ\80аÑ\82Ñ\8c **наиболее подÑ\85одÑ\8fÑ\89ий** Ñ\81поÑ\81об.
+Ð\9fÑ\80и Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвании пÑ\80иложениÑ\8f **FastAPI** (и вообÑ\89е лÑ\8eбого вебâ\80\91API) еÑ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко конÑ\86епÑ\86ий, о коÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81Ñ\82оиÑ\82 дÑ\83маÑ\82Ñ\8c â\80\94 Ñ\81 иÑ\85 помоÑ\89Ñ\8cÑ\8e можно вÑ\8bбÑ\80аÑ\82Ñ\8c **наиболее подÑ\85одÑ\8fÑ\89ий** Ñ\81поÑ\81об **Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f ваÑ\88его пÑ\80иложениÑ\8f**.
-СамÑ\8bе важнÑ\8bе из ниÑ\85:
+Ð\9dекоÑ\82оÑ\80Ñ\8bе из важнÑ\8bÑ\85 конÑ\86епÑ\86ий:
-* Ð\98Ñ\81полÑ\8cзование более безопаÑ\81ного пÑ\80оÑ\82окола HTTPS
-* Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка пÑ\80иложениÑ\8f
-* Ð\9fеÑ\80езагÑ\80Ñ\83зка пÑ\80иложениÑ\8f
-* Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f
-* УпÑ\80авление памÑ\8fÑ\82Ñ\8cÑ\8e
-* Ð\98Ñ\81полÑ\8cзование пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий пеÑ\80ед запÑ\83Ñ\81ком пÑ\80иложениÑ\8f.
+* Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c â\80\94 HTTPS
+* Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е
+* Ð\9fеÑ\80езапÑ\83Ñ\81ки
+* РепликаÑ\86иÑ\8f (колиÑ\87еÑ\81Ñ\82во запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов)
+* Ð\9fамÑ\8fÑ\82Ñ\8c
+* Ð\9fÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком
-РаÑ\81Ñ\81моÑ\82Ñ\80им ниже влиÑ\8fние каждого из ниÑ\85 на пÑ\80оÑ\86еÑ\81Ñ\81 **развёртывания**.
+Ð\9fоÑ\81моÑ\82Ñ\80им, как они влиÑ\8fÑ\8eÑ\82 на **развёртывания**.
-Ð\9dаÑ\88а конеÑ\87наÑ\8f Ñ\86елÑ\8c - **обÑ\81лÑ\83живаÑ\82Ñ\8c клиенÑ\82ов ваÑ\88его API безопаÑ\81но** и **беÑ\81пеÑ\80ебойно**, Ñ\81 макÑ\81ималÑ\8cно Ñ\8dÑ\84Ñ\84екÑ\82ивнÑ\8bм иÑ\81полÑ\8cзованием **вÑ\8bÑ\87иÑ\81лиÑ\82елÑ\8cнÑ\8bÑ\85 Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов** (напÑ\80имеÑ\80, Ñ\83далÑ\91ннÑ\8bÑ\85 Ñ\81еÑ\80веÑ\80ов/виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bÑ\85 маÑ\88ин). 🚀
+Ð\92 конеÑ\87ном иÑ\82оге Ñ\86елÑ\8c â\80\94 **обÑ\81лÑ\83живаÑ\82Ñ\8c клиенÑ\82ов ваÑ\88его API** безопаÑ\81но, **избегаÑ\82Ñ\8c пеÑ\80ебоев** и макÑ\81ималÑ\8cно Ñ\8dÑ\84Ñ\84екÑ\82ивно иÑ\81полÑ\8cзоваÑ\82Ñ\8c **вÑ\8bÑ\87иÑ\81лиÑ\82елÑ\8cнÑ\8bе Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81Ñ\8b** (напÑ\80имеÑ\80, Ñ\83далÑ\91ннÑ\8bе Ñ\81еÑ\80веÑ\80Ñ\8b/виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bе маÑ\88инÑ\8b). 🚀
-Ð\97деÑ\81Ñ\8c Ñ\8f немного Ñ\80аÑ\81Ñ\81кажÑ\83 Ð\92ам об Ñ\8dÑ\82иÑ\85 **конÑ\86епÑ\86иÑ\8fÑ\85** и надеÑ\8eÑ\81Ñ\8c, Ñ\87Ñ\82о Ñ\83 ваÑ\81 Ñ\81ложиÑ\82Ñ\81Ñ\8f **инÑ\82Ñ\83иÑ\82ивное понимание**, какой Ñ\81поÑ\81об вÑ\8bбÑ\80аÑ\82Ñ\8c пÑ\80и Ñ\80азвеÑ\80Ñ\82Ñ\8bвании ваÑ\88его API в Ñ\80азлиÑ\87нÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8fÑ\85, возможно, даже **еÑ\89Ñ\91 не Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83Ñ\8eÑ\89иÑ\85**.
+Ð\97деÑ\81Ñ\8c Ñ\8f немного Ñ\80аÑ\81Ñ\81кажÑ\83 о Ñ\8dÑ\82иÑ\85 **конÑ\86епÑ\86иÑ\8fÑ\85**, Ñ\87Ñ\82обÑ\8b Ñ\83 ваÑ\81 поÑ\8fвилаÑ\81Ñ\8c **инÑ\82Ñ\83иÑ\86иÑ\8f**, как Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваÑ\82Ñ\8c ваÑ\88 API в Ñ\80азнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8fÑ\85, возможно даже в **бÑ\83дÑ\83Ñ\89иÑ\85**, коÑ\82оÑ\80Ñ\8bÑ\85 еÑ\89Ñ\91 не Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82.
-Ð\9eзнакомивÑ\88иÑ\81Ñ\8c Ñ\81 Ñ\8dÑ\82ими конÑ\86епÑ\86иÑ\8fми, вÑ\8b Ñ\81можеÑ\82е **оÑ\86ениÑ\82Ñ\8c и вÑ\8bбÑ\80аÑ\82Ñ\8c** лÑ\83Ñ\87Ñ\88ий Ñ\81поÑ\81об Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвании **Ð\92аÑ\88его API**.
+УÑ\87иÑ\82Ñ\8bваÑ\8f Ñ\8dÑ\82и конÑ\86епÑ\86ии, вÑ\8b Ñ\81можеÑ\82е **оÑ\86ениÑ\82Ñ\8c и Ñ\81пÑ\80оекÑ\82иÑ\80оваÑ\82Ñ\8c** лÑ\83Ñ\87Ñ\88ий Ñ\81поÑ\81об Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f **Ñ\81воиÑ\85 API**.
-В последующих главах я предоставлю Вам **конкретные рецепты** развёртывания приложения FastAPI.
+В следующих главах я дам более **конкретные рецепты** по развёртыванию приложений FastAPI.
-А сейчас давайте остановимся на важных **идеях этих концепций**. Эти идеи можно также применить и к другим типам веб-приложений. 💡
+А пока давайте разберём важные **идеи**. Эти концепции применимы и к другим типам веб‑API. 💡
-## Ð\98Ñ\81полÑ\8cзование более безопаÑ\81ного пÑ\80оÑ\82окола HTTPS
+## Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c â\80\94 HTTPS { #security-https }
-Ð\92 [пÑ\80едÑ\8bдÑ\83Ñ\89ей главе об HTTPS](https.md){.internal-link target=_blank} мÑ\8b Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80ели, как HTTPS обеспечивает шифрование для вашего API.
+Ð\92 [пÑ\80едÑ\8bдÑ\83Ñ\89ей главе пÑ\80о HTTPS](https.md){.internal-link target=_blank} мÑ\8b Ñ\80азобÑ\80алиÑ\81Ñ\8c, как HTTPS обеспечивает шифрование для вашего API.
-Также мы заметили, что обычно для работы с HTTPS вашему приложению нужен **дополнительный** компонент - **прокси-сервер завершения работы TLS**.
+Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **TLS Termination Proxy**.
-Ð\98 еÑ\81ли пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80 не Ñ\83мееÑ\82 Ñ\81ам **обновлÑ\8fÑ\82Ñ\8c Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b HTTPS**, Ñ\82о нÑ\83жен еÑ\89Ñ\91 один компоненÑ\82 длÑ\8f Ñ\8dÑ\82ого дейÑ\81Ñ\82виÑ\8f.
+Ð\98 должен бÑ\8bÑ\82Ñ\8c компоненÑ\82, оÑ\82веÑ\87аÑ\8eÑ\89ий за **обновление HTTPSâ\80\91Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов** â\80\94 Ñ\8dÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\82оÑ\82 же Ñ\81амÑ\8bй компоненÑ\82 или оÑ\82делÑ\8cнÑ\8bй.
-### Примеры инструментов для работы с HTTPS
+### Примеры инструментов для HTTPS { #example-tools-for-https }
-Ð\92оÑ\82 некоÑ\82оÑ\80Ñ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b, коÑ\82оÑ\80Ñ\8bе вÑ\8b можеÑ\82е пÑ\80именÑ\8fÑ\82Ñ\8c как пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80Ñ\8b:
+Ð\9dекоÑ\82оÑ\80Ñ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b, коÑ\82оÑ\80Ñ\8bе можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c как TLS Termination Proxy:
* Traefik
- * С авÑ\82омаÑ\82иÑ\87еÑ\81ким обновлением Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов ✨
+ * Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81ки обновлÑ\8fеÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b ✨
* Caddy
- * С авÑ\82омаÑ\82иÑ\87еÑ\81ким обновлением Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов ✨
+ * Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81ки обновлÑ\8fеÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b ✨
* Nginx
- * С дополниÑ\82елÑ\8cнÑ\8bм компоненÑ\82ом Ñ\82ипа Certbot для обновления сертификатов
+ * С внеÑ\88ним компоненÑ\82ом (напÑ\80имеÑ\80, Certbot) для обновления сертификатов
* HAProxy
- * С дополниÑ\82елÑ\8cнÑ\8bм компоненÑ\82ом Ñ\82ипа Certbot для обновления сертификатов
-* Kubernetes с Ingress Controller похожим на Nginx
- * С дополниÑ\82елÑ\8cнÑ\8bм компоненÑ\82ом Ñ\82ипа cert-manager для обновления сертификатов
-* Ð\98Ñ\81полÑ\8cзование Ñ\83Ñ\81лÑ\83г облаÑ\87ного пÑ\80овайдеÑ\80а (Ñ\87иÑ\82айÑ\82е ниже 👇)
+ * С внеÑ\88ним компоненÑ\82ом (напÑ\80имеÑ\80, Certbot) для обновления сертификатов
+* Kubernetes с Ingress Controller (например, Nginx)
+ * С внеÑ\88ним компоненÑ\82ом (напÑ\80имеÑ\80, cert-manager) для обновления сертификатов
+* Ð\9eбÑ\80абаÑ\82Ñ\8bваеÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80и облаÑ\87ного пÑ\80овайдеÑ\80а как Ñ\87аÑ\81Ñ\82Ñ\8c его Ñ\83Ñ\81лÑ\83г (Ñ\81м. ниже 👇)
-Ð\92 поÑ\81леднем ваÑ\80ианÑ\82е вÑ\8b можеÑ\82е воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f Ñ\83Ñ\81лÑ\83гами **облаÑ\87ного Ñ\81еÑ\80виÑ\81а**, коÑ\82оÑ\80Ñ\8bй Ñ\81делаеÑ\82 болÑ\8cÑ\88Ñ\83Ñ\8e Ñ\87аÑ\81Ñ\82Ñ\8c Ñ\80абоÑ\82Ñ\8b, вклÑ\8eÑ\87аÑ\8f наÑ\81Ñ\82Ñ\80ойкÑ\83 HTTPS. ÐÑ\82о можеÑ\82 наложиÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\8bе огÑ\80аниÑ\87ениÑ\8f или поÑ\82Ñ\80ебоваÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\83Ñ\8e плаÑ\82Ñ\83 и Ñ\82.п. Ð\97аÑ\82о Ð\92ам не понадобиÑ\82Ñ\81Ñ\8f Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно занимаÑ\82Ñ\8cÑ\81Ñ\8f наÑ\81Ñ\82Ñ\80ойками пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80а.
+Ð\94Ñ\80Ñ\83гой ваÑ\80ианÑ\82 â\80\94 иÑ\81полÑ\8cзоваÑ\82Ñ\8c **облаÑ\87нÑ\8bй Ñ\81еÑ\80виÑ\81**, коÑ\82оÑ\80Ñ\8bй возÑ\8cмÑ\91Ñ\82 на Ñ\81ебÑ\8f болÑ\8cÑ\88е задаÑ\87, вклÑ\8eÑ\87аÑ\8f наÑ\81Ñ\82Ñ\80ойкÑ\83 HTTPS. Там могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c огÑ\80аниÑ\87ениÑ\8f или дополниÑ\82елÑ\8cнаÑ\8f Ñ\81Ñ\82оимоÑ\81Ñ\82Ñ\8c и Ñ\82.п., но в Ñ\82аком Ñ\81лÑ\83Ñ\87ае вам не пÑ\80идÑ\91Ñ\82Ñ\81Ñ\8f Ñ\81амим наÑ\81Ñ\82Ñ\80аиваÑ\82Ñ\8c TLS Termination Proxy.
-В дальнейшем я покажу Вам некоторые конкретные примеры их применения.
+В следующих главах я покажу конкретные примеры.
---
-СледÑ\83Ñ\8eÑ\89ие конÑ\86епÑ\86ии Ñ\80аÑ\81Ñ\81маÑ\82Ñ\80иваÑ\8eÑ\82 пÑ\80именение пÑ\80огÑ\80аммÑ\8b, запÑ\83Ñ\81каÑ\8eÑ\89ей Ð\92аÑ\88 API (Ñ\82акой как Uvicorn).
+Ð\94алее Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им конÑ\86епÑ\86ии, Ñ\81вÑ\8fзаннÑ\8bе Ñ\81 пÑ\80огÑ\80аммой, коÑ\82оÑ\80аÑ\8f запÑ\83Ñ\81каеÑ\82 ваÑ\88 Ñ\80еалÑ\8cнÑ\8bй API (напÑ\80имеÑ\80, Uvicorn).
-## Программа и процесс
+## Программа и процесс { #program-and-process }
-Ð\9cÑ\8b Ñ\87аÑ\81Ñ\82о бÑ\83дем вÑ\81Ñ\82Ñ\80еÑ\87аÑ\82Ñ\8c Ñ\81лова **пÑ\80оÑ\86еÑ\81Ñ\81** и **пÑ\80огÑ\80амма**, поÑ\82омÑ\83 Ñ\81ледÑ\83еÑ\82 Ñ\83Ñ\8fÑ\81ниÑ\82Ñ\8c оÑ\82лиÑ\87иÑ\8f междÑ\83 ними.
+Ð\9cÑ\8b Ñ\87аÑ\81Ñ\82о бÑ\83дем говоÑ\80иÑ\82Ñ\8c о Ñ\80абоÑ\82аÑ\8eÑ\89ем "**пÑ\80оÑ\86еÑ\81Ñ\81е**", поÑ\8dÑ\82омÑ\83 полезно Ñ\87Ñ\91Ñ\82ко понимаÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\8dÑ\82о знаÑ\87иÑ\82 и Ñ\87ем оÑ\82лиÑ\87аеÑ\82Ñ\81Ñ\8f оÑ\82 "**пÑ\80огÑ\80аммÑ\8b**".
-### Что такое программа
+### Что такое программа { #what-is-a-program }
-ТеÑ\80мином **пÑ\80огÑ\80амма** обÑ\8bÑ\87но опиÑ\81Ñ\8bваÑ\8eÑ\82 множеÑ\81Ñ\82во веÑ\89ей:
+Словом **пÑ\80огÑ\80амма** обÑ\8bÑ\87но назÑ\8bваÑ\8eÑ\82 Ñ\80азнÑ\8bе веÑ\89и:
-* **Ð\9aод**, коÑ\82оÑ\80Ñ\8bй вÑ\8b напиÑ\81али, в наÑ\88ем Ñ\81лÑ\83Ñ\87ае **Python-файлы**.
-* **Файл**, коÑ\82оÑ\80Ñ\8bй можеÑ\82 бÑ\8bÑ\82Ñ\8c **иÑ\81полнен** опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емой, напÑ\80имеÑ\80 `python`, `python.exe` или `uvicorn`.
-* Конкретная программа, **запущенная** операционной системой и использующая центральный процессор и память. В таком случае это также называется **процесс**.
+* **Ð\9aод**, коÑ\82оÑ\80Ñ\8bй вÑ\8b пиÑ\88еÑ\82е, Ñ\82о еÑ\81Ñ\82Ñ\8c **Pythonâ\80\91файлы**.
+* **Файл**, коÑ\82оÑ\80Ñ\8bй можеÑ\82 бÑ\8bÑ\82Ñ\8c **запÑ\83Ñ\89ен** опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емой, напÑ\80имеÑ\80: `python`, `python.exe` или `uvicorn`.
+* Конкретную программу в момент, когда она **работает** в операционной системе, используя CPU и память. Это также называют **процессом**.
-### Что такое процесс
+### Что такое процесс { #what-is-a-process }
-ТеÑ\80мин **пÑ\80оÑ\86еÑ\81Ñ\81** имееÑ\82 более Ñ\83зкое Ñ\82олкование, подÑ\80азÑ\83меваÑ\8f Ñ\87Ñ\82о-Ñ\82о, запÑ\83Ñ\89енное опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емой (как в поÑ\81леднем пÑ\83нкÑ\82е из вÑ\8bÑ\88еÑ\81Ñ\82оÑ\8fÑ\89его абзаÑ\86а):
+Слово **пÑ\80оÑ\86еÑ\81Ñ\81** обÑ\8bÑ\87но иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 более конкÑ\80еÑ\82но â\80\94 Ñ\82олÑ\8cко длÑ\8f Ñ\82ого, Ñ\87Ñ\82о Ñ\80еалÑ\8cно вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f в опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82еме (как в поÑ\81леднем пÑ\83нкÑ\82е вÑ\8bÑ\88е):
-* Конкретная программа, **запущенная** операционной системой.
- * ÐÑ\82о не имееÑ\82 оÑ\82ноÑ\88ениÑ\8f к какомÑ\83-либо Ñ\84айлÑ\83 или кодÑ\83, но неÑ\87Ñ\82о **опÑ\80еделÑ\91нное**, Ñ\83пÑ\80авлÑ\8fемое и **вÑ\8bполнÑ\8fемое** операционной системой.
-* Любая программа, любой код, **могут делать что-то** только когда они **выполняются**. То есть, когда являются **работающим процессом**.
-* Ð\9fÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 бÑ\8bÑ\82Ñ\8c **пÑ\80еÑ\80ван** (или "Ñ\83биÑ\82") Ð\92ами или ваÑ\88ей опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емой. Ð\92 Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82е Ñ\87его он пеÑ\80еÑ\81Ñ\82анеÑ\82 иÑ\81полнÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f и **не бÑ\83деÑ\82 пÑ\80одолжаÑ\82Ñ\8c делаÑ\82Ñ\8c Ñ\87Ñ\82о-либо**.
-* Ð\9aаждое пÑ\80иложение, коÑ\82оÑ\80ое вÑ\8b запÑ\83Ñ\81Ñ\82или на Ñ\81воÑ\91м компÑ\8cÑ\8eÑ\82еÑ\80е, каждаÑ\8f пÑ\80огÑ\80амма, каждое "окно" запÑ\83Ñ\81каеÑ\82 какой-Ñ\82о пÑ\80оÑ\86еÑ\81Ñ\81. Ð\98 обÑ\8bÑ\87но на вклÑ\8eÑ\87енном компÑ\8cÑ\8eÑ\82еÑ\80е **одновÑ\80еменно** запÑ\83Ñ\89ено множеÑ\81Ñ\82во пÑ\80оÑ\86еÑ\81Ñ\81ов.
-* Ð\98 **одна пÑ\80огÑ\80амма** можеÑ\82 запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c **неÑ\81колÑ\8cко паÑ\80аллелÑ\8cнÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов**.
+* Конкретная программа в момент, когда она **запущена** в операционной системе.
+ * РеÑ\87Ñ\8c не о Ñ\84айле и не о коде, а **конкÑ\80еÑ\82но** о Ñ\82ом, Ñ\87Ñ\82о **иÑ\81полнÑ\8fеÑ\82Ñ\81Ñ\8f** и Ñ\83пÑ\80авлÑ\8fеÑ\82Ñ\81Ñ\8f операционной системой.
+* Любая программа, любой код **могут что‑то делать** только когда **исполняются**, то есть когда есть **работающий процесс**.
+* Ð\9fÑ\80оÑ\86еÑ\81Ñ\81 можно **завеÑ\80Ñ\88иÑ\82Ñ\8c** (или «Ñ\83биÑ\82Ñ\8c») вами или опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емой. Ð\92 Ñ\8dÑ\82оÑ\82 моменÑ\82 он пеÑ\80еÑ\81Ñ\82аÑ\91Ñ\82 вÑ\8bполнÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f и **болÑ\8cÑ\88е ниÑ\87его делаÑ\82Ñ\8c не можеÑ\82**.
+* У каждого запÑ\83Ñ\89енного пÑ\80иложениÑ\8f на ваÑ\88ем компÑ\8cÑ\8eÑ\82еÑ\80е еÑ\81Ñ\82Ñ\8c Ñ\81вой пÑ\80оÑ\86еÑ\81Ñ\81; Ñ\83 каждой пÑ\80огÑ\80аммÑ\8b, Ñ\83 каждого окна и Ñ\82.д. Ð\9eбÑ\8bÑ\87но одновÑ\80еменно **Ñ\80абоÑ\82аеÑ\82 много пÑ\80оÑ\86еÑ\81Ñ\81ов**, пока компÑ\8cÑ\8eÑ\82еÑ\80 вклÑ\8eÑ\87Ñ\91н.
+* Ð\9cогÑ\83Ñ\82 **одновÑ\80еменно** Ñ\80абоÑ\82аÑ\82Ñ\8c **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов** одной и Ñ\82ой же **пÑ\80огÑ\80аммÑ\8b**.
-Ð\95Ñ\81ли вÑ\8b заглÑ\8fнеÑ\82е в "диÑ\81пеÑ\82Ñ\87еÑ\80 задаÑ\87" или "Ñ\81иÑ\81Ñ\82емнÑ\8bй мониÑ\82оÑ\80" (или аналогиÑ\87нÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b) ваÑ\88ей опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емÑ\8b, то увидите множество работающих процессов.
+Ð\95Ñ\81ли вÑ\8b поÑ\81моÑ\82Ñ\80иÑ\82е «диÑ\81пеÑ\82Ñ\87еÑ\80 задаÑ\87» или «Ñ\81иÑ\81Ñ\82емнÑ\8bй мониÑ\82оÑ\80» (или аналогиÑ\87нÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b) в ваÑ\88ей опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82еме, то увидите множество работающих процессов.
-Ð\92полне веÑ\80оÑ\8fÑ\82но, Ñ\87Ñ\82о вÑ\8b Ñ\83видиÑ\82е неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов Ñ\81 одним и Ñ\82ем же названием бÑ\80аÑ\83зеÑ\80ной пÑ\80огÑ\80аммÑ\8b (Firefox, Chrome, Edge и Ñ\82. Ð\94.). Ð\9eбÑ\8bÑ\87но бÑ\80аÑ\83зеÑ\80Ñ\8b запÑ\83Ñ\81каÑ\8eÑ\82 один пÑ\80оÑ\86еÑ\81Ñ\81 на вкладкÑ\83 и вдобавок некоÑ\82оÑ\80Ñ\8bе дополнительные процессы.
+Ð\9dапÑ\80имеÑ\80, вÑ\8b, Ñ\81коÑ\80ее вÑ\81его, Ñ\83видиÑ\82е неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов одного и Ñ\82ого же бÑ\80аÑ\83зеÑ\80а (Firefox, Chrome, Edge и Ñ\82.д.). Ð\9eбÑ\8bÑ\87но бÑ\80аÑ\83зеÑ\80Ñ\8b запÑ\83Ñ\81каÑ\8eÑ\82 один пÑ\80оÑ\86еÑ\81Ñ\81 на вкладкÑ\83 плÑ\8eÑ\81 дополнительные процессы.
<img class="shadow" src="/img/deployment/concepts/image01.png">
---
-ТепеÑ\80Ñ\8c, когда нам извеÑ\81Ñ\82на Ñ\80азниÑ\86а междÑ\83 **пÑ\80оÑ\86еÑ\81Ñ\81ом** и **пÑ\80огÑ\80аммой**, давайÑ\82е пÑ\80одолжим обÑ\81Ñ\83ждение Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f.
+ТепеÑ\80Ñ\8c, когда мÑ\8b понимаем Ñ\80азниÑ\86Ñ\83 междÑ\83 **пÑ\80оÑ\86еÑ\81Ñ\81ом** и **пÑ\80огÑ\80аммой**, пÑ\80одолжим Ñ\80азговоÑ\80 о Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8fÑ\85.
-## Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка пÑ\80иложениÑ\8f
+## Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е { #running-on-startup }
-В большинстве случаев когда вы создаёте веб-приложение, то желаете, чтоб оно **работало постоянно** и непрерывно, предоставляя клиентам доступ в любое время. Хотя иногда у вас могут быть причины, чтоб оно запускалось только при определённых условиях.
+В большинстве случаев, создавая веб‑API, вы хотите, чтобы он **работал постоянно**, без перерывов, чтобы клиенты всегда могли к нему обратиться. Разве что у вас есть особые причины запускать его только при определённых условиях, но обычно вы хотите, чтобы он был постоянно запущен и **доступен**.
-### УдалÑ\91ннÑ\8bй Ñ\81еÑ\80веÑ\80
+### Ð\9dа Ñ\83далÑ\91нном Ñ\81еÑ\80веÑ\80е { #in-a-remote-server }
-Когда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самое простое, что можно сделать, запустить Uvicorn (или его аналог) вручную, как вы делаете при локальной разработке.
+Когда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самый простой вариант — вручную использовать `fastapi run` (он использует Uvicorn) или что‑то похожее, как вы делаете при локальной разработке.
-Это рабочий способ и он полезен **во время разработки**.
+Это будет работать и полезно **во время разработки**.
-Но если вы потеряете соединение с сервером, то не сможете отслеживать - работает ли всё ещё **запущенный Вами процесс**.
+Но если соединение с сервером прервётся, **запущенный процесс**, скорее всего, завершится.
-Ð\98 еÑ\81ли Ñ\81еÑ\80веÑ\80 пеÑ\80езагÑ\80Ñ\83зиÑ\82Ñ\81Ñ\8f (напÑ\80имеÑ\80, поÑ\81ле обновлениÑ\8f или какиÑ\85-Ñ\82о дейÑ\81Ñ\82вий облаÑ\87ного пÑ\80овайдеÑ\80а), вÑ\8b Ñ\81коÑ\80ее вÑ\81его **Ñ\8dÑ\82ого не замеÑ\82иÑ\82е**, Ñ\87Ñ\82обÑ\8b Ñ\81нова запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c пÑ\80оÑ\86еÑ\81Ñ\81 вÑ\80Ñ\83Ñ\87нÑ\83Ñ\8e. Ð\92Ñ\81ледÑ\81Ñ\82вие Ñ\8dÑ\82ого Ð\92аÑ\88 API оÑ\81Ñ\82анеÑ\82Ñ\81Ñ\8f мÑ\91Ñ\80Ñ\82вÑ\8bм. 😱
+Ð\90 еÑ\81ли Ñ\81еÑ\80веÑ\80 пеÑ\80езагÑ\80Ñ\83зиÑ\82Ñ\81Ñ\8f (напÑ\80имеÑ\80, поÑ\81ле обновлений или мигÑ\80аÑ\86ий Ñ\83 облаÑ\87ного пÑ\80овайдеÑ\80а), вÑ\8b, веÑ\80оÑ\8fÑ\82но, **даже не замеÑ\82иÑ\82е Ñ\8dÑ\82ого**. Ð\98зâ\80\91за Ñ\8dÑ\82ого вÑ\8b не Ñ\83знаеÑ\82е, Ñ\87Ñ\82о нÑ\83жно вÑ\80Ñ\83Ñ\87нÑ\83Ñ\8e пеÑ\80езапÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c пÑ\80оÑ\86еÑ\81Ñ\81 â\80\94 и ваÑ\88 API пÑ\80оÑ\81Ñ\82о бÑ\83деÑ\82 «мÑ\91Ñ\80Ñ\82в». 😱
-### Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81кий запÑ\83Ñ\81к пÑ\80огÑ\80амм
+### Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81кий запÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е { #run-automatically-on-startup }
-Ð\92еÑ\80оÑ\8fÑ\82но вÑ\8b заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82об Ð\92аÑ\88а Ñ\81еÑ\80веÑ\80наÑ\8f пÑ\80огÑ\80амма (Ñ\82акаÑ\8f, как Uvicorn) Ñ\81Ñ\82аÑ\80Ñ\82овала авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80и вклÑ\8eÑ\87ении Ñ\81еÑ\80веÑ\80а, без **Ñ\87еловеÑ\87еÑ\81кого вмеÑ\88аÑ\82елÑ\8cÑ\81Ñ\82ва** и вÑ\81егда могла Ñ\83пÑ\80авлÑ\8fÑ\82Ñ\8c Ð\92аÑ\88им API (Ñ\82ак как Uvicorn запÑ\83Ñ\81каеÑ\82 приложение FastAPI).
+Ð\9aак пÑ\80авило, вÑ\8b заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b Ñ\81еÑ\80веÑ\80наÑ\8f пÑ\80огÑ\80амма (напÑ\80имеÑ\80, Uvicorn) запÑ\83Ñ\81калаÑ\81Ñ\8c авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е Ñ\81еÑ\80веÑ\80а и без **Ñ\83Ñ\87аÑ\81Ñ\82иÑ\8f Ñ\87еловека**, Ñ\87Ñ\82обÑ\8b вÑ\81егда бÑ\8bл пÑ\80оÑ\86еÑ\81Ñ\81, запÑ\83Ñ\89еннÑ\8bй Ñ\81 ваÑ\88им API (напÑ\80имеÑ\80, Uvicorn, запÑ\83Ñ\81каÑ\8eÑ\89ий ваÑ\88е приложение FastAPI).
-### Отдельная программа
+### Отдельная программа { #separate-program }
-Ð\94лÑ\8f Ñ\8dÑ\82ого Ñ\83 обÑ\8bÑ\87но иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 оÑ\82делÑ\8cнÑ\83Ñ\8e пÑ\80огÑ\80аммÑ\83, коÑ\82оÑ\80аÑ\8f Ñ\81ледиÑ\82 за Ñ\82ем, Ñ\87Ñ\82обÑ\8b Ð\92аÑ\88и пÑ\80иложениÑ\8f запÑ\83Ñ\81калиÑ\81Ñ\8c пÑ\80и вклÑ\8eÑ\87ении Ñ\81еÑ\80веÑ\80а. Такой подÑ\85од гаÑ\80анÑ\82иÑ\80Ñ\83еÑ\82, Ñ\87Ñ\82о дÑ\80Ñ\83гие компоненÑ\82Ñ\8b или пÑ\80иложениÑ\8f Ñ\82акже бÑ\83дÑ\83Ñ\82 запÑ\83Ñ\89енÑ\8b, напÑ\80имеÑ\80, база даннÑ\8bÑ\85
+ЧÑ\82обÑ\8b Ñ\8dÑ\82ого добиÑ\82Ñ\8cÑ\81Ñ\8f, обÑ\8bÑ\87но иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 **оÑ\82делÑ\8cнÑ\83Ñ\8e пÑ\80огÑ\80аммÑ\83**, коÑ\82оÑ\80аÑ\8f гаÑ\80анÑ\82иÑ\80Ñ\83еÑ\82 запÑ\83Ñ\81к ваÑ\88его пÑ\80иложениÑ\8f пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е. Ð\92о многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 она Ñ\82акже запÑ\83Ñ\81каеÑ\82 и дÑ\80Ñ\83гие компоненÑ\82Ñ\8b/пÑ\80иложениÑ\8f, напÑ\80имеÑ\80 базÑ\83 даннÑ\8bÑ\85.
-### Примеры инструментов, управляющих запуском программ
+### Примеры инструментов для запуска при старте { #example-tools-to-run-at-startup }
-Ð\92оÑ\82 неÑ\81колÑ\8cко пÑ\80имеÑ\80ов, коÑ\82оÑ\80Ñ\8bе могÑ\83Ñ\82 Ñ\81пÑ\80авиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81 Ñ\82акой задаÑ\87ей:
+Ð\9fÑ\80имеÑ\80Ñ\8b инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе могÑ\83Ñ\82 Ñ\81 Ñ\8dÑ\82им Ñ\81пÑ\80авиÑ\82Ñ\8cÑ\81Ñ\8f:
* Docker
* Kubernetes
* Docker Compose
-* Docker в режиме Swarm
+* Docker в режиме Swarm (Swarm Mode)
* Systemd
* Supervisor
-* Ð\98Ñ\81полÑ\8cзование Ñ\83Ñ\81лÑ\83г облаÑ\87ного пÑ\80овайдеÑ\80а
+* Ð\9eбÑ\80абоÑ\82ка внÑ\83Ñ\82Ñ\80и облаÑ\87ного пÑ\80овайдеÑ\80а как Ñ\87аÑ\81Ñ\82Ñ\8c его Ñ\83Ñ\81лÑ\83г
* Прочие...
-Я покажÑ\83 Ð\92ам некоÑ\82оÑ\80Ñ\8bе пÑ\80имеÑ\80Ñ\8b иÑ\85 иÑ\81полÑ\8cзованиÑ\8f в следующих главах.
+Ð\91олее конкÑ\80еÑ\82нÑ\8bе пÑ\80имеÑ\80Ñ\8b бÑ\83дÑ\83Ñ\82 в следующих главах.
-## Перезапуск
+## Перезапуски { #restarts }
-Ð\92Ñ\8b, веÑ\80оÑ\8fÑ\82но, Ñ\82акже заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82об ваÑ\88е пÑ\80иложение **пеÑ\80езапÑ\83Ñ\81калоÑ\81Ñ\8c**, еÑ\81ли в нÑ\91м пÑ\80оизоÑ\88Ñ\91л Ñ\81бой.
+Ð\9fодобно Ñ\82омÑ\83 как вÑ\8b обеÑ\81пеÑ\87иваеÑ\82е запÑ\83Ñ\81к пÑ\80иложениÑ\8f пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е, вÑ\8b, веÑ\80оÑ\8fÑ\82но, заÑ\85оÑ\82иÑ\82е обеÑ\81пеÑ\87иÑ\82Ñ\8c его **пеÑ\80езапÑ\83Ñ\81к** поÑ\81ле Ñ\81боев.
-### Мы ошибаемся
+### Мы ошибаемся { #we-make-mistakes }
-Ð\92Ñ\81е лÑ\8eди Ñ\81овеÑ\80Ñ\88аÑ\8eÑ\82 **оÑ\88ибки**. Ð\9fÑ\80огÑ\80аммное обеÑ\81пеÑ\87ение поÑ\87Ñ\82и *вÑ\81егда* Ñ\81одеÑ\80жиÑ\82 **баги** Ñ\81пÑ\80Ñ\8fÑ\82авÑ\88иеÑ\81Ñ\8f в разных местах. 🐛
+Ð\9cÑ\8b, лÑ\8eди, поÑ\81Ñ\82оÑ\8fнно Ñ\81овеÑ\80Ñ\88аем **оÑ\88ибки**. Ð\92 пÑ\80огÑ\80аммном обеÑ\81пеÑ\87ении поÑ\87Ñ\82и вÑ\81егда еÑ\81Ñ\82Ñ\8c **баги**, Ñ\81кÑ\80Ñ\8bÑ\82Ñ\8bе в разных местах. 🐛
-Ð\98 мÑ\8b, бÑ\83дÑ\83Ñ\87и Ñ\80азÑ\80абоÑ\82Ñ\87иками, пÑ\80одолжаем Ñ\83лÑ\83Ñ\87Ñ\88аÑ\82Ñ\8c код, когда обнаÑ\80Ñ\83живаем в нÑ\91м баги или добавлÑ\8fем новÑ\8bй Ñ\84Ñ\83нкÑ\86ионал (возможно, добавлÑ\8fÑ\8f пÑ\80и Ñ\8dÑ\82ом баги 😅).
+Ð\98 мÑ\8b, как Ñ\80азÑ\80абоÑ\82Ñ\87ики, пÑ\80одолжаем Ñ\83лÑ\83Ñ\87Ñ\88аÑ\82Ñ\8c код â\80\94 наÑ\85одим баги и добавлÑ\8fем новÑ\8bе возможноÑ\81Ñ\82и (иногда добавлÑ\8fÑ\8f новÑ\8bе баги 😅).
-### Небольшие ошибки обрабатываются автоматически
+### Небольшие ошибки обрабатываются автоматически { #small-errors-automatically-handled }
-Ð\9aогда вÑ\8b Ñ\81оздаÑ\91Ñ\82е Ñ\81вои API на оÑ\81нове FastAPI и допÑ\83Ñ\81каеÑ\82е в коде оÑ\88ибкÑ\83, Ñ\82о FastAPI обÑ\8bÑ\87но оÑ\81Ñ\82ановиÑ\82 еÑ\91 Ñ\80аÑ\81пÑ\80оÑ\81Ñ\82Ñ\80анение внÑ\83Ñ\82Ñ\80и одного запÑ\80оÑ\81а, пÑ\80и обÑ\80абоÑ\82ке коÑ\82оÑ\80ого она возникла. 🛡
+СоздаваÑ\8f вебâ\80\91API Ñ\81 FastAPI, еÑ\81ли в наÑ\88ем коде возникаеÑ\82 оÑ\88ибка, FastAPI обÑ\8bÑ\87но «локализÑ\83еÑ\82» еÑ\91 в пÑ\80еделаÑ\85 одного запÑ\80оÑ\81а, коÑ\82оÑ\80Ñ\8bй Ñ\8dÑ\82Ñ\83 оÑ\88ибкÑ\83 вÑ\8bзвал. 🛡
-Клиент получит ошибку **500 Internal Server Error** в ответ на свой запрос, но приложение не сломается и будет продолжать работать с последующими запросами.
+Клиент получит **500 Internal Server Error** для этого запроса, но приложение продолжит работать для последующих запросов, а не «упадёт» целиком.
-### Большие ошибки - Падение приложений
+### Большие ошибки — падения { #bigger-errors-crashes }
-Тем не менее, может случиться так, что ошибка вызовет **сбой всего приложения** или даже сбой в Uvicorn, а то и в самом Python. 💥
+Тем не менее возможны случаи, когда код **роняет всё приложение**, приводя к сбою Uvicorn и Python. 💥
-Ð\9dо мÑ\8b вÑ\81Ñ\91 еÑ\89Ñ\91 Ñ\85оÑ\82им, Ñ\87Ñ\82обÑ\8b пÑ\80иложение **пÑ\80одолжало Ñ\80абоÑ\82аÑ\82Ñ\8c** неÑ\81моÑ\82Ñ\80Ñ\8f на Ñ\8dÑ\82Ñ\83 единÑ\81Ñ\82веннÑ\83Ñ\8e оÑ\88ибкÑ\83, обÑ\80абаÑ\82Ñ\8bваÑ\8f, как минимÑ\83м, запÑ\80оÑ\81Ñ\8b к *опеÑ\80аÑ\86иÑ\8fм пÑ\83Ñ\82и* не имеÑ\8eÑ\89им оÑ\88ибок.
+Ð\98 вÑ\8b, Ñ\81коÑ\80ее вÑ\81его, не заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b пÑ\80иложение оÑ\81Ñ\82авалоÑ\81Ñ\8c «мÑ\91Ñ\80Ñ\82вÑ\8bм» изâ\80\91за оÑ\88ибки в одном меÑ\81Ñ\82е â\80\94 вÑ\8b заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b оно **пÑ\80одолжало Ñ\80абоÑ\82аÑ\82Ñ\8c** Ñ\85оÑ\82Ñ\8f бÑ\8b длÑ\8f *опеÑ\80аÑ\86ий пÑ\83Ñ\82и*, коÑ\82оÑ\80Ñ\8bе не Ñ\81ломанÑ\8b.
-### Перезапуск после падения
+### Перезапуск после падения { #restart-after-crash }
-Ð\94лÑ\8f Ñ\81лÑ\83Ñ\87аев, когда оÑ\88ибки пÑ\80иводÑ\8fÑ\82 к Ñ\81боÑ\8e в запÑ\83Ñ\89енном **пÑ\80оÑ\86еÑ\81Ñ\81е**, Ð\92ам понадобиÑ\82Ñ\81Ñ\8f добавиÑ\82Ñ\8c компоненÑ\82, коÑ\82оÑ\80Ñ\8bй **пеÑ\80езапÑ\83Ñ\81Ñ\82иÑ\82** пÑ\80оÑ\86еÑ\81Ñ\81 Ñ\85оÑ\82Ñ\8f бÑ\8b пару раз...
+Ð\92 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 дейÑ\81Ñ\82виÑ\82елÑ\8cно Ñ\81еÑ\80Ñ\8cÑ\91знÑ\8bÑ\85 оÑ\88ибок, коÑ\82оÑ\80Ñ\8bе Ñ\80онÑ\8fÑ\8eÑ\82 Ñ\80абоÑ\82аÑ\8eÑ\89ий **пÑ\80оÑ\86еÑ\81Ñ\81**, вам понадобиÑ\82Ñ\81Ñ\8f внеÑ\88ний компоненÑ\82, оÑ\82веÑ\87аÑ\8eÑ\89ий за **пеÑ\80езапÑ\83Ñ\81к** пÑ\80оÑ\86еÑ\81Ñ\81а, как минимÑ\83м пару раз...
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-... Если приложение падает сразу же после запуска, вероятно бесполезно его бесконечно перезапускать. Но полагаю, вы заметите такое поведение во время разработки или, по крайней мере, сразу после развёртывания.
+...Хотя если приложение **падает сразу же**, вероятно, нет смысла перезапускать его бесконечно. Но такие случаи вы, скорее всего, заметите во время разработки или как минимум сразу после развёртывания.
-Так Ñ\87Ñ\82о давайÑ\82е Ñ\81оÑ\81Ñ\80едоÑ\82оÑ\87имÑ\81Ñ\8f на конкÑ\80еÑ\82нÑ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85, когда пÑ\80иложение можеÑ\82 полноÑ\81Ñ\82Ñ\8cÑ\8e вÑ\8bйÑ\82и из Ñ\81Ñ\82Ñ\80оÑ\8f, но вÑ\81Ñ\91 еÑ\89Ñ\91 еÑ\81Ñ\82Ñ\8c Ñ\81мÑ\8bÑ\81л его запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c заново.
+Ð\94авайÑ\82е Ñ\81оÑ\81Ñ\80едоÑ\82оÑ\87имÑ\81Ñ\8f на оÑ\81новнÑ\8bÑ\85 Ñ\81Ñ\86енаÑ\80иÑ\8fÑ\85, когда в какиÑ\85â\80\91Ñ\82о конкÑ\80еÑ\82нÑ\8bÑ\85 Ñ\81иÑ\82Ñ\83аÑ\86иÑ\8fÑ\85 **в бÑ\83дÑ\83Ñ\89ем** пÑ\80иложение можеÑ\82 падаÑ\82Ñ\8c Ñ\86еликом, и пÑ\80и Ñ\8dÑ\82ом имееÑ\82 Ñ\81мÑ\8bÑ\81л его пеÑ\80езапÑ\83Ñ\81каÑ\82Ñ\8c.
///
-Ð\92озможно вÑ\8b заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82об бÑ\8bл некий **внеÑ\88ний компоненÑ\82**, оÑ\82веÑ\82Ñ\81Ñ\82веннÑ\8bй за пеÑ\80езапÑ\83Ñ\81к ваÑ\88его пÑ\80иложениÑ\8f даже еÑ\81ли Ñ\83же не Ñ\80абоÑ\82аеÑ\82 Uvicorn или Python. То еÑ\81Ñ\82Ñ\8c ниÑ\87его из Ñ\82ого, Ñ\87Ñ\82о напиÑ\81ано в ваÑ\88ем коде внÑ\83Ñ\82Ñ\80и пÑ\80иложениÑ\8f, не можеÑ\82 бÑ\8bÑ\82Ñ\8c вÑ\8bполнено в пÑ\80инÑ\86ипе.
+СкоÑ\80ее вÑ\81его, вÑ\8b заÑ\85оÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b пеÑ\80езапÑ\83Ñ\81ком ваÑ\88его пÑ\80иложениÑ\8f занималÑ\81Ñ\8f **внеÑ\88ний компоненÑ\82**, поÑ\82омÑ\83 Ñ\87Ñ\82о к Ñ\82омÑ\83 моменÑ\82Ñ\83 Uvicorn и Python Ñ\83же Ñ\83пали, и внÑ\83Ñ\82Ñ\80и Ñ\82ого же кода ваÑ\88его пÑ\80иложениÑ\8f Ñ\81делаÑ\82Ñ\8c Ñ\83же ниÑ\87его нелÑ\8cзÑ\8f.
-### Примеры инструментов для автоматического перезапуска
+### Примеры инструментов для автоматического перезапуска { #example-tools-to-restart-automatically }
-В большинстве случаев инструменты **запускающие программы при старте сервера** умеют **перезапускать** эти программы.
+В большинстве случаев тот же инструмент, который **запускает программу при старте**, умеет обрабатывать и автоматические **перезапуски**.
-Ð\92 каÑ\87еÑ\81Ñ\82ве пÑ\80имеÑ\80а можно взÑ\8fÑ\82Ñ\8c Ñ\82е же:
+Ð\9dапÑ\80имеÑ\80, Ñ\8dÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c:
* Docker
* Kubernetes
* Docker Compose
-* Docker в режиме Swarm
+* Docker в режиме Swarm (Swarm Mode)
* Systemd
* Supervisor
-* Ð\98Ñ\81полÑ\8cзование Ñ\83Ñ\81лÑ\83г облаÑ\87ного пÑ\80овайдеÑ\80а
+* Ð\9eбÑ\80абоÑ\82ка внÑ\83Ñ\82Ñ\80и облаÑ\87ного пÑ\80овайдеÑ\80а как Ñ\87аÑ\81Ñ\82Ñ\8c его Ñ\83Ñ\81лÑ\83г
* Прочие...
-## Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f (РепликаÑ\86иÑ\8f) - Ð\9fÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b и памÑ\8fÑ\82Ñ\8c
+## РепликаÑ\86иÑ\8f â\80\94 пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b и памÑ\8fÑ\82Ñ\8c { #replication-processes-and-memory }
-Ð\9fÑ\80иложение FastAPI, Ñ\83пÑ\80авлÑ\8fемое Ñ\81еÑ\80веÑ\80ной пÑ\80огÑ\80аммой (Ñ\82акой как Uvicorn), запÑ\83Ñ\81каеÑ\82Ñ\81Ñ\8f как **один пÑ\80оÑ\86еÑ\81Ñ\81** и можеÑ\82 обÑ\81лÑ\83живаÑ\82Ñ\8c множеÑ\81Ñ\82во клиентов одновременно.
+Ð\92 пÑ\80иложении FastAPI, иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\81еÑ\80веÑ\80нÑ\83Ñ\8e пÑ\80огÑ\80аммÑ\83 (напÑ\80имеÑ\80, командÑ\83 `fastapi`, коÑ\82оÑ\80аÑ\8f запÑ\83Ñ\81каеÑ\82 Uvicorn), запÑ\83Ñ\81к в **одном пÑ\80оÑ\86еÑ\81Ñ\81е** Ñ\83же позволÑ\8fеÑ\82 обÑ\81лÑ\83живаÑ\82Ñ\8c неÑ\81колÑ\8cкиÑ\85 клиентов одновременно.
-Но часто Вам может понадобиться несколько одновременно работающих одинаковых процессов.
+Но во многих случаях вы захотите одновременно запустить несколько процессов‑воркеров.
-### Ð\9cножеÑ\81Ñ\82во пÑ\80оÑ\86еÑ\81Ñ\81ов - Ð\92оÑ\80кеÑ\80Ñ\8b (Workers)
+### Ð\9dеÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов â\80\94 Ð\92оÑ\80кеÑ\80Ñ\8b { #multiple-processes-workers }
-Ð\95Ñ\81ли колиÑ\87еÑ\81Ñ\82во Ð\92аÑ\88иÑ\85 клиенÑ\82ов болÑ\8cÑ\88е, Ñ\87ем можеÑ\82 обÑ\81лÑ\83жиÑ\82Ñ\8c один пÑ\80оÑ\86еÑ\81Ñ\81 (допÑ\83Ñ\81Ñ\82им, Ñ\87Ñ\82о виÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f маÑ\88ина не Ñ\81лиÑ\88ком моÑ\89наÑ\8f), но пÑ\80и Ñ\8dÑ\82ом Ð\92ам доÑ\81Ñ\82Ñ\83пно **неÑ\81колÑ\8cко Ñ\8fдеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а**, Ñ\82о вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов** одного и Ñ\82ого же пÑ\80иложениÑ\8f паÑ\80аллелÑ\8cно и Ñ\80аÑ\81пÑ\80еделиÑ\82Ñ\8c запÑ\80оÑ\81Ñ\8b междÑ\83 Ñ\8dÑ\82ими пÑ\80оÑ\86еÑ\81Ñ\81ами.
+Ð\95Ñ\81ли клиенÑ\82ов болÑ\8cÑ\88е, Ñ\87ем Ñ\81поÑ\81обен обÑ\81лÑ\83жиÑ\82Ñ\8c один пÑ\80оÑ\86еÑ\81Ñ\81 (напÑ\80имеÑ\80, еÑ\81ли виÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f маÑ\88ина не Ñ\81лиÑ\88ком моÑ\89наÑ\8f), и на Ñ\81еÑ\80веÑ\80е еÑ\81Ñ\82Ñ\8c **неÑ\81колÑ\8cко Ñ\8fдеÑ\80 CPU**, вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов** одного и Ñ\82ого же пÑ\80иложениÑ\8f паÑ\80аллелÑ\8cно и Ñ\80аÑ\81пÑ\80еделÑ\8fÑ\82Ñ\8c запÑ\80оÑ\81Ñ\8b междÑ\83 ними.
-**Несколько запущенных процессов** одной и той же API-программы часто называют **воркерами**.
+Когда вы запускаете **несколько процессов** одной и той же программы API, их обычно называют **воркерами**.
-### Процессы и порты́
+### Процессы‑воркеры и порты { #worker-processes-and-ports }
-Ð\9fомниÑ\82е ли Ð\92Ñ\8b, как на Ñ\81Ñ\82Ñ\80аниÑ\86е [Ð\9eб HTTPS](https.md){.internal-link target=_blank} мÑ\8b обÑ\81Ñ\83ждали, Ñ\87Ñ\82о на Ñ\81еÑ\80веÑ\80е Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 Ñ\81лÑ\83Ñ\88аÑ\82Ñ\8c однÑ\83 комбинаÑ\86иÑ\8e IP-адÑ\80еÑ\81а и поÑ\80Ñ\82а?
+Ð\9fомниÑ\82е из Ñ\80аздела [Ð\9eб HTTPS](https.md){.internal-link target=_blank}, Ñ\87Ñ\82о на Ñ\81еÑ\80веÑ\80е Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 Ñ\81лÑ\83Ñ\88аÑ\82Ñ\8c конкÑ\80еÑ\82нÑ\83Ñ\8e комбинаÑ\86иÑ\8e поÑ\80Ñ\82а и IPâ\80\91адÑ\80еÑ\81а?
-С Ñ\82еÑ\85 поÑ\80 ниÑ\87его не изменилоÑ\81Ñ\8c.
+ÐÑ\82о поâ\80\91пÑ\80ежнемÑ\83 Ñ\82ак.
-СооÑ\82веÑ\82Ñ\81Ñ\82венно, Ñ\87Ñ\82обÑ\8b имеÑ\82Ñ\8c возможноÑ\81Ñ\82Ñ\8c Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 **неÑ\81колÑ\8cкими пÑ\80оÑ\86еÑ\81Ñ\81ами** одновÑ\80еменно, должен бÑ\8bÑ\82Ñ\8c **один пÑ\80оÑ\86еÑ\81Ñ\81, пÑ\80оÑ\81лÑ\83Ñ\88иваÑ\8eÑ\89ий поÑ\80Ñ\82** и заÑ\82ем каким-либо обÑ\80азом пеÑ\80едаÑ\8eÑ\89ий даннÑ\8bе каждомÑ\83 Ñ\80абоÑ\87емÑ\83 процессу.
+Ð\9fоÑ\8dÑ\82омÑ\83, Ñ\87Ñ\82обÑ\8b одновÑ\80еменно Ñ\80абоÑ\82ало **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов**, должен бÑ\8bÑ\82Ñ\8c **один пÑ\80оÑ\86еÑ\81Ñ\81, Ñ\81лÑ\83Ñ\88аÑ\8eÑ\89ий поÑ\80Ñ\82**, коÑ\82оÑ\80Ñ\8bй заÑ\82ем какимâ\80\91Ñ\82о обÑ\80азом пеÑ\80едаÑ\91Ñ\82 коммÑ\83никаÑ\86иÑ\8e каждомÑ\83 воÑ\80кеÑ\80â\80\91процессу.
-### У каждого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81воÑ\8f памÑ\8fÑ\82Ñ\8c
+### Ð\9fамÑ\8fÑ\82Ñ\8c на пÑ\80оÑ\86еÑ\81Ñ\81 { #memory-per-process }
-РабоÑ\82аÑ\8eÑ\89аÑ\8f пÑ\80огÑ\80амма загÑ\80Ñ\83жаеÑ\82 в памÑ\8fÑ\82Ñ\8c даннÑ\8bе, необÑ\85одимÑ\8bе длÑ\8f еÑ\91 Ñ\80абоÑ\82Ñ\8b, напÑ\80имеÑ\80, пеÑ\80еменнÑ\8bе Ñ\81одеÑ\80жаÑ\89ие модели маÑ\88инного обÑ\83Ñ\87ениÑ\8f или болÑ\8cÑ\88ие Ñ\84айлÑ\8b. Ð\9aаждаÑ\8f пеÑ\80еменнаÑ\8f **поÑ\82Ñ\80еблÑ\8fеÑ\82 некоÑ\82оÑ\80ое колиÑ\87еÑ\81Ñ\82во опеÑ\80аÑ\82ивной памяти (RAM)** сервера.
+Ð\9aогда пÑ\80огÑ\80амма загÑ\80Ñ\83жаеÑ\82 Ñ\87Ñ\82оâ\80\91Ñ\82о в памÑ\8fÑ\82Ñ\8c (напÑ\80имеÑ\80, моделÑ\8c маÑ\88инного обÑ\83Ñ\87ениÑ\8f в пеÑ\80еменнÑ\83Ñ\8e или Ñ\81одеÑ\80жимое болÑ\8cÑ\88ого Ñ\84айла в пеÑ\80еменнÑ\83Ñ\8e), вÑ\81Ñ\91 Ñ\8dÑ\82о **поÑ\82Ñ\80еблÑ\8fеÑ\82 Ñ\87аÑ\81Ñ\82Ñ\8c памяти (RAM)** сервера.
-Ð\9eбÑ\8bÑ\87но пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b **не делÑ\8fÑ\82Ñ\81Ñ\8f памÑ\8fÑ\82Ñ\8cÑ\8e дÑ\80Ñ\83г Ñ\81 дÑ\80Ñ\83гом**. Сие ознаÑ\87аеÑ\82, Ñ\87Ñ\82о каждÑ\8bй Ñ\80абоÑ\82аÑ\8eÑ\89ий пÑ\80оÑ\86еÑ\81Ñ\81 имееÑ\82 Ñ\81вои даннÑ\8bе, пеÑ\80еменнÑ\8bе и Ñ\81вой кÑ\83Ñ\81ок памÑ\8fÑ\82и. Ð\98 еÑ\81ли длÑ\8f вÑ\8bполнениÑ\8f ваÑ\88его кода пÑ\80оÑ\86еÑ\81Ñ\81Ñ\83 нÑ\83жно много памÑ\8fÑ\82и, Ñ\82о **каждÑ\8bй Ñ\82акой же пÑ\80оÑ\86еÑ\81Ñ\81** запÑ\83Ñ\89еннÑ\8bй дополниÑ\82елÑ\8cно, поÑ\82Ñ\80ебÑ\83еÑ\82 Ñ\82акого же колиÑ\87еÑ\81Ñ\82ва памяти.
+Ð\98 Ñ\80азнÑ\8bе пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b обÑ\8bÑ\87но **не делÑ\8fÑ\82 памÑ\8fÑ\82Ñ\8c**. ÐÑ\82о знаÑ\87иÑ\82, Ñ\87Ñ\82о Ñ\83 каждого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81вои пеÑ\80еменнÑ\8bе и Ñ\81воÑ\8f памÑ\8fÑ\82Ñ\8c. Ð\95Ñ\81ли ваÑ\88 код поÑ\82Ñ\80еблÑ\8fеÑ\82 много памÑ\8fÑ\82и, Ñ\82о **каждÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81** бÑ\83деÑ\82 поÑ\82Ñ\80еблÑ\8fÑ\82Ñ\8c Ñ\81опоÑ\81Ñ\82авимÑ\8bй обÑ\8aÑ\91м памяти.
-### Память сервера
+### Память сервера { #server-memory }
-Ð\94опÑ\83Ñ\81Ñ\82им, Ñ\87Ñ\82о Ð\92аÑ\88 код загÑ\80Ñ\83жаеÑ\82 моделÑ\8c маÑ\88инного обÑ\83Ñ\87ениÑ\8f **Ñ\80азмеÑ\80ом 1 Ð\93Ð\91**. Ð\9aогда вÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82е Ñ\81воÑ\91 API как один пÑ\80оÑ\86еÑ\81Ñ\81, он займÑ\91Ñ\82 в опеÑ\80аÑ\82ивной памÑ\8fÑ\82и не менее 1 Ð\93Ð\91. Ð\90 еÑ\81ли вÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82е **4 Ñ\82акиÑ\85 же пÑ\80оÑ\86еÑ\81Ñ\81а** (4 воÑ\80кеÑ\80а), Ñ\82о каждÑ\8bй из ниÑ\85 займÑ\91Ñ\82 1 Ð\93Ð\91 опеÑ\80аÑ\82ивной памÑ\8fÑ\82и. Ð\92 Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82е ваÑ\88емÑ\83 API поÑ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f **4 Ð\93Ð\91 опеÑ\80аÑ\82ивной памÑ\8fÑ\82и (RAM)**.
+Ð\9dапÑ\80имеÑ\80, еÑ\81ли ваÑ\88 код загÑ\80Ñ\83жаеÑ\82 моделÑ\8c Ð\9cаÑ\88инного обÑ\83Ñ\87ениÑ\8f Ñ\80азмеÑ\80ом **1 Ð\93Ð\91**, Ñ\82о пÑ\80и запÑ\83Ñ\81ке одного пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 ваÑ\88им API он бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c как минимÑ\83м 1 Ð\93Ð\91 RAM. Ð\90 еÑ\81ли вÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82е **4 пÑ\80оÑ\86еÑ\81Ñ\81а** (4 воÑ\80кеÑ\80а), каждÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81 бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c 1 Ð\93Ð\91 RAM. Ð\92Ñ\81его ваÑ\88 API бÑ\83деÑ\82 поÑ\82Ñ\80еблÑ\8fÑ\82Ñ\8c **4 Ð\93Ð\91 RAM**.
-И если Ваш удалённый сервер или виртуальная машина располагает только 3 ГБ памяти, то попытка загрузить в неё 4 ГБ данных вызовет проблемы. 🚨
+И если у вашего удалённого сервера или виртуальной машины только 3 ГБ RAM, попытка загрузить более 4 ГБ вызовет проблемы. 🚨
-### Ð\9cножеÑ\81Ñ\82во пÑ\80оÑ\86еÑ\81Ñ\81ов - Ð\9fÑ\80имеÑ\80
+### Ð\9dеÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов â\80\94 пÑ\80имеÑ\80 { #multiple-processes-an-example }
-В этом примере **менеджер процессов** запустит и будет управлять двумя **воркерами**.
+В этом примере есть **процесс‑менеджер**, который запускает и контролирует два **процесса‑воркера**.
-Ð\9cенеджеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81ов бÑ\83деÑ\82 Ñ\81лÑ\83Ñ\88аÑ\82Ñ\8c опÑ\80еделÑ\91ннÑ\8bй **Ñ\81океÑ\82** (IP:поÑ\80Ñ\82) и пеÑ\80едаваÑ\82Ñ\8c даннÑ\8bе Ñ\80абоÑ\82аÑ\8eÑ\89им процессам.
+Ð\9fÑ\80оÑ\86еÑ\81Ñ\81â\80\91менеджеÑ\80, веÑ\80оÑ\8fÑ\82но, бÑ\83деÑ\82 Ñ\82ем, кÑ\82о Ñ\81лÑ\83Ñ\88аеÑ\82 **поÑ\80Ñ\82** на IP. Ð\98 он бÑ\83деÑ\82 пеÑ\80едаваÑ\82Ñ\8c вÑ\81Ñ\8e коммÑ\83никаÑ\86иÑ\8e воÑ\80кеÑ\80â\80\91процессам.
-Ð\9aаждÑ\8bй из Ñ\8dÑ\82иÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов бÑ\83деÑ\82 запÑ\83Ñ\81каÑ\82Ñ\8c ваÑ\88е пÑ\80иложение длÑ\8f обÑ\80абоÑ\82ки полÑ\83Ñ\87енного **запÑ\80оÑ\81а** и возвÑ\80аÑ\89ениÑ\8f вÑ\8bÑ\87иÑ\81ленного **оÑ\82веÑ\82а** и они бÑ\83дÑ\83Ñ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c опеÑ\80аÑ\82ивнÑ\83Ñ\8e памÑ\8fÑ\82Ñ\8c.
+ÐÑ\82и воÑ\80кеÑ\80Ñ\8b бÑ\83дÑ\83Ñ\82 запÑ\83Ñ\81каÑ\82Ñ\8c ваÑ\88е пÑ\80иложение, вÑ\8bполнÑ\8fÑ\82Ñ\8c оÑ\81новнÑ\8bе вÑ\8bÑ\87иÑ\81лениÑ\8f длÑ\8f полÑ\83Ñ\87ениÑ\8f **запÑ\80оÑ\81а** и возвÑ\80аÑ\82а **оÑ\82веÑ\82а**, и загÑ\80Ñ\83жаÑ\82Ñ\8c вÑ\81Ñ\91, Ñ\87Ñ\82о вÑ\8b кладÑ\91Ñ\82е в пеÑ\80еменнÑ\8bе, в RAM.
<img src="/img/deployment/concepts/process-ram.drawio.svg">
-Ð\91езÑ\83Ñ\81ловно, на Ñ\8dÑ\82ом же Ñ\81еÑ\80веÑ\80е бÑ\83дÑ\83Ñ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c и **дÑ\80Ñ\83гие пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b**, коÑ\82оÑ\80Ñ\8bе не оÑ\82ноÑ\81Ñ\8fÑ\82Ñ\81Ñ\8f к ваÑ\88емÑ\83 пÑ\80иложениÑ\8e.
+Ð\9aонеÑ\87но, на Ñ\82ой же маÑ\88ине помимо ваÑ\88его пÑ\80иложениÑ\8f, Ñ\81коÑ\80ее вÑ\81его, бÑ\83дÑ\83Ñ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c и **дÑ\80Ñ\83гие пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b**.
-Интересная деталь заключается в том, что процент **использования центрального процессора (CPU)** каждым процессом может сильно меняться с течением времени, но объём занимаемой **оперативной памяти (RAM)** остаётся относительно **стабильным**.
+Интересная деталь: процент **использования CPU** каждым процессом со временем может сильно **меняться**, но **память (RAM)** обычно остаётся более‑менее **стабильной**.
-Если у вас есть API, который каждый раз выполняет сопоставимый объем вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *также будет стабильной* (вместо того, чтобы постоянно быстро увеличиваться и уменьшаться).
+Если у вас API, который каждый раз выполняет сопоставимый объём вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *тоже будет стабильной* (вместо того, чтобы быстро и постоянно «скакать»).
-### Примеры стратегий и инструментов для запуска нескольких экземпляров приложения
+### Примеры инструментов и стратегий репликации { #examples-of-replication-tools-and-strategies }
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 неÑ\81колÑ\8cко подÑ\85одов длÑ\8f доÑ\81Ñ\82ижениÑ\8f Ñ\86елей Ñ\80епликаÑ\86ии и Ñ\8f Ñ\80аÑ\81Ñ\81кажÑ\83 Ð\92ам болÑ\8cÑ\88е о конкÑ\80еÑ\82нÑ\8bÑ\85 Ñ\81Ñ\82Ñ\80аÑ\82егиÑ\8fÑ\85 в Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 главаÑ\85, напÑ\80имеÑ\80, когда Ñ\80еÑ\87Ñ\8c пойдеÑ\82 о Docker и контейнерах.
+Ð\95Ñ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко подÑ\85одов длÑ\8f доÑ\81Ñ\82ижениÑ\8f Ñ\8dÑ\82ого, и Ñ\8f Ñ\80аÑ\81Ñ\81кажÑ\83 болÑ\8cÑ\88е о конкÑ\80еÑ\82нÑ\8bÑ\85 Ñ\81Ñ\82Ñ\80аÑ\82егиÑ\8fÑ\85 в Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 главаÑ\85, напÑ\80имеÑ\80, говоÑ\80Ñ\8f о Docker и контейнерах.
-Ð\9eÑ\81новное огÑ\80аниÑ\87ение пÑ\80и Ñ\8dÑ\82ом - Ñ\82олÑ\8cко **один** компоненÑ\82 можеÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 опÑ\80еделÑ\91ннÑ\8bм **поÑ\80Ñ\82ом пÑ\83блиÑ\87ного IP**. Ð\98 должен бÑ\8bÑ\82Ñ\8c Ñ\81поÑ\81об **пеÑ\80едаÑ\87и** даннÑ\8bÑ\85 междÑ\83 Ñ\8dÑ\82им компоненÑ\82ом и копиÑ\8fми **пÑ\80оÑ\86еÑ\81Ñ\81ов/воÑ\80кеÑ\80ов**.
+Ð\93лавное огÑ\80аниÑ\87ение: должен бÑ\8bÑ\82Ñ\8c **один** компоненÑ\82, коÑ\82оÑ\80Ñ\8bй обÑ\80абаÑ\82Ñ\8bваеÑ\82 **поÑ\80Ñ\82** на **пÑ\83блиÑ\87ном IP**. Ð\98 Ñ\83 него должен бÑ\8bÑ\82Ñ\8c Ñ\81поÑ\81об **пеÑ\80едаваÑ\82Ñ\8c** коммÑ\83никаÑ\86иÑ\8e Ñ\80еплиÑ\86иÑ\80ованнÑ\8bм **пÑ\80оÑ\86еÑ\81Ñ\81ам/воÑ\80кеÑ\80ам**.
-Ð\92оÑ\82 некоторые возможные комбинации и стратегии:
+Ð\9dекоторые возможные комбинации и стратегии:
-* **Gunicorn** управляющий **воркерами Uvicorn**
- * Gunicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **множества работающих процессов Uvicorn**.
-* **Uvicorn** управляющий **воркерами Uvicorn**
- * Один процесс Uvicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Он будет запускать **множество работающих процессов Uvicorn**.
-* **Kubernetes** и аналогичные **контейнерные системы**
- * Какой-то компонент в **Kubernetes** будет слушать **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**.
-* **Облачные сервисы**, которые позаботятся обо всём за Вас
- * Возможно, что облачный сервис умеет **управлять запуском дополнительных экземпляров приложения**. Вероятно, он потребует, чтоб вы указали - какой **процесс** или **образ** следует клонировать. Скорее всего, вы укажете **один процесс Uvicorn** и облачный сервис будет запускать его копии при необходимости.
+* **Uvicorn** с `--workers`
+ * Один **процесс‑менеджер** Uvicorn будет слушать **IP** и **порт** и запускать **несколько процессов‑воркеров Uvicorn**.
+* **Kubernetes** и другие распределённые **контейнерные системы**
+ * Некий компонент на уровне **Kubernetes** будет слушать **IP** и **порт**. Репликация достигается с помощью **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**.
+* **Облачные сервисы**, которые берут это на себя
+ * Облачный сервис, скорее всего, **возьмёт репликацию на себя**. Он, возможно, позволит указать **процесс для запуска** или **образ контейнера**. В любом случае это, скорее всего, будет **один процесс Uvicorn**, а сервис займётся его репликацией.
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-Ð\95Ñ\81ли вÑ\8b не знаеÑ\82е, Ñ\87Ñ\82о Ñ\82акое **конÑ\82ейнеÑ\80Ñ\8b**, Docker или Kubernetes, не пеÑ\80еживайÑ\82е.
+Ð\9dе беÑ\81покойÑ\82еÑ\81Ñ\8c, еÑ\81ли некоÑ\82оÑ\80Ñ\8bе пÑ\83нкÑ\82Ñ\8b пÑ\80о **конÑ\82ейнеÑ\80Ñ\8b**, Docker или Kubernetes пока кажÑ\83Ñ\82Ñ\81Ñ\8f неоÑ\87евиднÑ\8bми.
-Я поведаю Вам о контейнерах, образах, Docker, Kubernetes и т.п. в главе: [FastAPI внутри контейнеров - Docker](docker.md){.internal-link target=_blank}.
+Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md){.internal-link target=_blank}.
///
-## Шаги, пÑ\80едÑ\88еÑ\81Ñ\82вÑ\83Ñ\8eÑ\89ие запÑ\83Ñ\81кÑ\83
+## Ð\9fÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком { #previous-steps-before-starting }
-ЧаÑ\81Ñ\82о бÑ\8bваеÑ\82, Ñ\87Ñ\82о Ð\92ам необÑ\85одимо пÑ\80оизвеÑ\81Ñ\82и какие-Ñ\82о подгоÑ\82овиÑ\82елÑ\8cнÑ\8bе Ñ\88аги **пеÑ\80ед запÑ\83Ñ\81ком** Ñ\81воего приложения.
+Ð\92о многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вÑ\8b заÑ\85оÑ\82иÑ\82е вÑ\8bполниÑ\82Ñ\8c некоÑ\82оÑ\80Ñ\8bе Ñ\88аги **пеÑ\80ед запÑ\83Ñ\81ком** приложения.
Например, запустить **миграции базы данных**.
-Но в большинстве случаев такие действия достаточно произвести **однократно**.
+Но чаще всего эти шаги нужно выполнять только **один раз**.
-Ð\9fоÑ\8dÑ\82омÑ\83 Ð\92ам нÑ\83жен бÑ\83деÑ\82 **один пÑ\80оÑ\86еÑ\81Ñ\81**, вÑ\8bполнÑ\8fÑ\8eÑ\89ий Ñ\8dÑ\82и **подгоÑ\82овиÑ\82елÑ\8cнÑ\8bе Ñ\88аги** до запÑ\83Ñ\81ка пÑ\80иложениÑ\8f.
+Ð\9fоÑ\8dÑ\82омÑ\83 вÑ\8b заÑ\85оÑ\82иÑ\82е имеÑ\82Ñ\8c **один пÑ\80оÑ\86еÑ\81Ñ\81**, коÑ\82оÑ\80Ñ\8bй вÑ\8bполниÑ\82 Ñ\8dÑ\82и **пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги**, пÑ\80ежде Ñ\87ем запÑ\83Ñ\81каÑ\82Ñ\8c пÑ\80иложение.
-Также Ð\92ам нÑ\83жно бÑ\83деÑ\82 Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о Ñ\8dÑ\82оÑ\82 пÑ\80оÑ\86еÑ\81Ñ\81 вÑ\8bполнил подгоÑ\82овиÑ\82елÑ\8cнÑ\8bе Ñ\88аги *даже* еÑ\81ли впоÑ\81ледÑ\81Ñ\82вии вÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82е **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов** (неÑ\81колÑ\8cко воÑ\80кеÑ\80ов) Ñ\81амого пÑ\80иложениÑ\8f. Ð\95Ñ\81ли бÑ\8b Ñ\8dÑ\82и Ñ\88аги вÑ\8bполнÑ\8fлиÑ\81Ñ\8c в каждом **клониÑ\80ованном пÑ\80оÑ\86еÑ\81Ñ\81е**, они бÑ\8b **дÑ\83блиÑ\80овали** Ñ\80абоÑ\82Ñ\83, пÑ\8bÑ\82аÑ\8fÑ\81Ñ\8c вÑ\8bполниÑ\82Ñ\8c еÑ\91 **паÑ\80аллелÑ\8cно**. Ð\98 еÑ\81ли бÑ\8b Ñ\8dÑ\82а Ñ\80абоÑ\82а бÑ\8bла бÑ\8b Ñ\87ем-Ñ\82о деликаÑ\82нÑ\8bм, вÑ\80оде мигÑ\80аÑ\86ии базÑ\8b даннÑ\8bÑ\85, Ñ\82о Ñ\8dÑ\82о можеÑ\82 вÑ\8bзваÑ\82Ñ\8c конÑ\84ликÑ\82Ñ\8b междÑ\83 ними.
+Ð\98 вам нÑ\83жно бÑ\83деÑ\82 Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о Ñ\8dÑ\82о делаеÑ\82 один пÑ\80оÑ\86еÑ\81Ñ\81 **даже** еÑ\81ли поÑ\82ом вÑ\8b запÑ\83Ñ\81каеÑ\82е **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов** (неÑ\81колÑ\8cко воÑ\80кеÑ\80ов) Ñ\81амого пÑ\80иложениÑ\8f. Ð\95Ñ\81ли Ñ\8dÑ\82и Ñ\88аги вÑ\8bполнÑ\8fÑ\82 **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов**, они **дÑ\83блиÑ\80Ñ\83Ñ\8eÑ\82** Ñ\80абоÑ\82Ñ\83, запÑ\83Ñ\81Ñ\82ив еÑ\91 **паÑ\80аллелÑ\8cно**, и, еÑ\81ли Ñ\80еÑ\87Ñ\8c о Ñ\87Ñ\91мâ\80\91Ñ\82о деликаÑ\82ном (напÑ\80имеÑ\80, мигÑ\80аÑ\86ии Ð\91Ð\94), Ñ\8dÑ\82о можеÑ\82 вÑ\8bзваÑ\82Ñ\8c конÑ\84ликÑ\82Ñ\8b.
-Ð\91езÑ\83Ñ\81ловно, возможнÑ\8b Ñ\81лÑ\83Ñ\87аи, когда неÑ\82 пÑ\80облем пÑ\80и вÑ\8bполнении пÑ\80едваÑ\80иÑ\82елÑ\8cной подгоÑ\82овки паÑ\80аллелÑ\8cно или неÑ\81колÑ\8cко Ñ\80аз. Тогда Ð\92ам повезло, Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 ними намного проще.
+Ð\9aонеÑ\87но, бÑ\8bваÑ\8eÑ\82 Ñ\81лÑ\83Ñ\87аи, когда неÑ\82 пÑ\80облем, еÑ\81ли пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги вÑ\8bполнÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f неÑ\81колÑ\8cко Ñ\80аз â\80\94 Ñ\82огда вÑ\81Ñ\91 проще.
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о в некоÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 запÑ\83Ñ\81к ваÑ\88его пÑ\80иложениÑ\8f **можеÑ\82 не Ñ\82Ñ\80ебоваÑ\82Ñ\8c какиÑ\85-либо пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bÑ\85 Ñ\88агов вовÑ\81е**.
+Также Ñ\83Ñ\87Ñ\82иÑ\82е, Ñ\87Ñ\82о в завиÑ\81имоÑ\81Ñ\82и оÑ\82 ваÑ\88ей Ñ\81Ñ\85емÑ\8b Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f в некоÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 **пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги могÑ\83Ñ\82 вовÑ\81е не Ñ\82Ñ\80ебоваÑ\82Ñ\8cÑ\81Ñ\8f**.
-ЧÑ\82о ж, Ñ\82огда Ð\92ам не нÑ\83жно беÑ\81покоиÑ\82Ñ\8cÑ\81Ñ\8f об Ñ\8dÑ\82ом. 🤷
+Тогда об Ñ\8dÑ\82ом можно не беÑ\81покоиÑ\82Ñ\8cÑ\81Ñ\8f. 🤷
///
-### Ð\9fÑ\80имеÑ\80Ñ\8b Ñ\81Ñ\82Ñ\80аÑ\82егий запÑ\83Ñ\81ка пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bÑ\85 Ñ\88агов
+### Ð\9fÑ\80имеÑ\80Ñ\8b Ñ\81Ñ\82Ñ\80аÑ\82егий длÑ\8f пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bÑ\85 Ñ\88агов { #examples-of-previous-steps-strategies }
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 **Ñ\81илÑ\8cнаÑ\8f завиÑ\81имоÑ\81Ñ\82Ñ\8c** оÑ\82 Ñ\82ого, как вÑ\8b **Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваеÑ\82е Ñ\81воÑ\8e Ñ\81иÑ\81Ñ\82емÑ\83**, запускаете программы, обрабатываете перезапуски и т.д.
+ÐÑ\82о бÑ\83деÑ\82 **Ñ\81илÑ\8cно завиÑ\81еÑ\82Ñ\8c** оÑ\82 Ñ\82ого, как вÑ\8b **Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваеÑ\82е Ñ\81иÑ\81Ñ\82емÑ\83**, как запускаете программы, обрабатываете перезапуски и т.д.
-Ð\92оÑ\82 некоторые возможные идеи:
+Ð\9dекоторые возможные идеи:
-* При использовании Kubernetes нужно предусмотреть "инициализирующий контейнер", запускаемый до контейнера с приложением.
-* Bash-скрипт, выполняющий предварительные шаги, а затем запускающий приложение.
- * Ð\9fÑ\80и Ñ\8dÑ\82ом Ð\92ам вÑ\81Ñ\91 еÑ\89Ñ\91 нÑ\83жно найÑ\82и Ñ\81поÑ\81об - как запÑ\83Ñ\81каÑ\82Ñ\8c/пеÑ\80езапÑ\83Ñ\81каÑ\82Ñ\8c *Ñ\82акой* bash-скрипт, обнаруживать ошибки и т.п.
+* «Init Container» в Kubernetes, который запускается перед контейнером с приложением
+* Bash‑скрипт, который выполняет предварительные шаги, а затем запускает приложение
+ * Ð\9fÑ\80и Ñ\8dÑ\82ом вÑ\81Ñ\91 Ñ\80авно нÑ\83жен Ñ\81поÑ\81об запÑ\83Ñ\81каÑ\82Ñ\8c/пеÑ\80езапÑ\83Ñ\81каÑ\82Ñ\8c *Ñ\8dÑ\82оÑ\82* bashâ\80\91скрипт, обнаруживать ошибки и т.п.
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-Я пÑ\80иведÑ\83 Ð\92ам болÑ\8cÑ\88е конкÑ\80еÑ\82нÑ\8bÑ\85 пÑ\80имеÑ\80ов Ñ\80абоÑ\82Ñ\8b Ñ\81 конÑ\82ейнеÑ\80ами в главе: [FastAPI внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80ов - Docker](docker.md){.internal-link target=_blank}.
+Я пÑ\80иведÑ\83 более конкÑ\80еÑ\82нÑ\8bе пÑ\80имеÑ\80Ñ\8b Ñ\81 конÑ\82ейнеÑ\80ами в Ñ\81ледÑ\83Ñ\8eÑ\89ей главе: [FastAPI внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80ов â\80\94 Docker](docker.md){.internal-link target=_blank}.
///
-## УÑ\82илизаÑ\86иÑ\8f Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов
+## Ð\98Ñ\81полÑ\8cзование Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов { #resource-utilization }
-Ваш сервер располагает ресурсами, которые Ваши программы могут потреблять или **утилизировать**, а именно - время работы центрального процессора и объём оперативной памяти.
+Ваш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM).
-Как много системных ресурсов вы предполагаете потребить/утилизировать? Если не задумываться, то можно ответить - "немного", но на самом деле Вы, вероятно, захотите использовать **максимально возможное количество**.
+Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, скорее всего, захотите потреблять **максимум без падений**.
-Если вы платите за содержание трёх серверов, но используете лишь малую часть системных ресурсов каждого из них, то вы **выбрасываете деньги на ветер**, а также **впустую тратите электроэнергию** и т.п.
+Если вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п.
-Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае бÑ\8bло бÑ\8b лÑ\83Ñ\87Ñ\88е обойÑ\82иÑ\81Ñ\8c двÑ\83мÑ\8f Ñ\81еÑ\80веÑ\80ами, но более полно Ñ\83Ñ\82илизиÑ\80оваÑ\82Ñ\8c иÑ\85 Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81Ñ\8b (Ñ\86енÑ\82Ñ\80алÑ\8cнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80, опеÑ\80аÑ\82ивнÑ\83Ñ\8e памÑ\8fÑ\82Ñ\8c, жÑ\91Ñ\81Ñ\82кий диÑ\81к, Ñ\81еÑ\82и пеÑ\80едаÑ\87и даннÑ\8bÑ\85 и Ñ\82.д).
+Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае лÑ\83Ñ\87Ñ\88е имеÑ\82Ñ\8c 2 Ñ\81еÑ\80веÑ\80а и иÑ\81полÑ\8cзоваÑ\82Ñ\8c более вÑ\8bÑ\81окий пÑ\80оÑ\86енÑ\82 иÑ\85 Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов (CPU, памÑ\8fÑ\82Ñ\8c, диÑ\81к, Ñ\81еÑ\82евÑ\83Ñ\8e полоÑ\81Ñ\83 и Ñ\82.д.).
-С другой стороны, если вы располагаете только двумя серверами и используете **на 100% их процессоры и память**, но какой-либо процесс запросит дополнительную память, то операционная система сервера будет использовать жёсткий диск для расширения оперативной памяти (а диск работает в тысячи раз медленнее), а то вовсе **упадёт**. Или если какому-то процессу понадобится произвести вычисления, то ему придётся подождать, пока процессор освободится.
+С другой стороны, если у вас 2 сервера и вы используете **100% их CPU и RAM**, в какой‑то момент один процесс попросит больше памяти, и сервер начнёт использовать диск как «память» (что в тысячи раз медленнее) или даже **упадёт**. Или процессу понадобятся вычисления, но ему придётся ждать освобождения CPU.
-Ð\92 Ñ\82акой Ñ\81иÑ\82Ñ\83аÑ\86ии лÑ\83Ñ\87Ñ\88е подклÑ\8eÑ\87иÑ\82Ñ\8c **еÑ\89Ñ\91 один Ñ\81еÑ\80веÑ\80** и пеÑ\80еÑ\80аÑ\81пÑ\80еделиÑ\82Ñ\8c пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b междÑ\83 Ñ\81еÑ\80веÑ\80ами, Ñ\87Ñ\82об вÑ\81ем **Ñ\85ваÑ\82ало памÑ\8fÑ\82и и пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80ного вÑ\80емени**.
+Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае лÑ\83Ñ\87Ñ\88е добавиÑ\82Ñ\8c **еÑ\89Ñ\91 один Ñ\81еÑ\80веÑ\80** и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c Ñ\87аÑ\81Ñ\82Ñ\8c пÑ\80оÑ\86еÑ\81Ñ\81ов на нÑ\91м, Ñ\87Ñ\82обÑ\8b Ñ\83 вÑ\81еÑ\85 бÑ\8bло **доÑ\81Ñ\82аÑ\82оÑ\87но RAM и вÑ\80емени CPU**.
-Также еÑ\81Ñ\82Ñ\8c веÑ\80оÑ\8fÑ\82ноÑ\81Ñ\82Ñ\8c, Ñ\87Ñ\82о по какой-Ñ\82о пÑ\80иÑ\87ине возник **вÑ\81плеÑ\81к** запÑ\80оÑ\81ов к ваÑ\88емÑ\83 API. Ð\92озможно, Ñ\8dÑ\82о бÑ\8bл виÑ\80Ñ\83Ñ\81, боÑ\82Ñ\8b или дÑ\80Ñ\83гие Ñ\81еÑ\80виÑ\81Ñ\8b наÑ\87али полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f им. Ð\98 длÑ\8f Ñ\82акиÑ\85 пÑ\80оиÑ\81Ñ\88еÑ\81Ñ\82вий вÑ\8b можеÑ\82е заÑ\85оÑ\82еÑ\82Ñ\8c имеÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\8bе Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81Ñ\8b.
+Также возможен **вÑ\81плеÑ\81к** иÑ\81полÑ\8cзованиÑ\8f ваÑ\88его API: он мог «взоÑ\80ваÑ\82Ñ\8cÑ\81Ñ\8f» по попÑ\83лÑ\8fÑ\80ноÑ\81Ñ\82и, или какиеâ\80\91Ñ\82о Ñ\81еÑ\80виÑ\81Ñ\8b/боÑ\82Ñ\8b наÑ\87али его акÑ\82ивно иÑ\81полÑ\8cзоваÑ\82Ñ\8c. Ð\9dа Ñ\82акие Ñ\81лÑ\83Ñ\87аи Ñ\81Ñ\82оиÑ\82 имеÑ\82Ñ\8c запаÑ\81 Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов.
-Ð\9fÑ\80и наÑ\81Ñ\82Ñ\80ойке логики Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваний, вÑ\8b можеÑ\82е Ñ\83казаÑ\82Ñ\8c **Ñ\86елевое знаÑ\87ение** Ñ\83Ñ\82илизаÑ\86ии Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов, допÑ\83Ñ\81Ñ\82им, **оÑ\82 50% до 90%**. Ð\9eбÑ\8bÑ\87но Ñ\8dÑ\82и меÑ\82Ñ\80ики и иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82.
+Ð\9cожно задаÑ\82Ñ\8c **Ñ\86елевое знаÑ\87ение**, напÑ\80имеÑ\80 **междÑ\83 50% и 90%** иÑ\81полÑ\8cзованиÑ\8f Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов. СкоÑ\80ее вÑ\81его, именно Ñ\8dÑ\82и веÑ\89и вÑ\8b бÑ\83деÑ\82е измеÑ\80Ñ\8fÑ\82Ñ\8c и на иÑ\85 оÑ\81нове наÑ\81Ñ\82Ñ\80аиваÑ\82Ñ\8c Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвание.
-Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c пÑ\80оÑ\81Ñ\82Ñ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b, Ñ\82акие как `htop`, длÑ\8f оÑ\82Ñ\81леживаниÑ\8f загÑ\80Ñ\83зки Ñ\86енÑ\82Ñ\80алÑ\8cного пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а и опеÑ\80аÑ\82ивной памÑ\8fÑ\82и Ñ\81еÑ\80веÑ\80а, в Ñ\82ом Ñ\87иÑ\81ле каждÑ\8bм пÑ\80оÑ\86еÑ\81Ñ\81ом. Ð\98ли более Ñ\81ложнÑ\8bе Ñ\81иÑ\81Ñ\82емÑ\8b мониÑ\82оÑ\80инга неÑ\81колÑ\8cкиÑ\85 Ñ\81еÑ\80веÑ\80ов.
+Ð\9cожно иÑ\81полÑ\8cзоваÑ\82Ñ\8c пÑ\80оÑ\81Ñ\82Ñ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b вÑ\80оде `htop`, Ñ\87Ñ\82обÑ\8b Ñ\81моÑ\82Ñ\80еÑ\82Ñ\8c загÑ\80Ñ\83зкÑ\83 CPU и RAM на Ñ\81еÑ\80веÑ\80е или по пÑ\80оÑ\86еÑ\81Ñ\81ам. Ð\98ли более Ñ\81ложнÑ\8bе Ñ\80аÑ\81пÑ\80еделÑ\91ннÑ\8bе Ñ\81иÑ\81Ñ\82емÑ\8b мониÑ\82оÑ\80инга.
-## Резюме
+## Резюме { #recap }
-Ð\92Ñ\8b пÑ\80оÑ\87иÑ\82али некоÑ\82оÑ\80Ñ\8bе из оÑ\81новнÑ\8bÑ\85 конÑ\86епÑ\86ий, коÑ\82оÑ\80Ñ\8bе необÑ\85одимо имеÑ\82Ñ\8c в видÑ\83 пÑ\80и пÑ\80инÑ\8fÑ\82ии Ñ\80еÑ\88ениÑ\8f о Ñ\80азвеÑ\80Ñ\82Ñ\8bвании пÑ\80иложений:
+Ð\97деÑ\81Ñ\8c вÑ\8b пÑ\80оÑ\87иÑ\82али о некоÑ\82оÑ\80Ñ\8bÑ\85 оÑ\81новнÑ\8bÑ\85 конÑ\86епÑ\86иÑ\8fÑ\85, коÑ\82оÑ\80Ñ\8bе, веÑ\80оÑ\8fÑ\82но, Ñ\81Ñ\82оиÑ\82 Ñ\83Ñ\87иÑ\82Ñ\8bваÑ\82Ñ\8c пÑ\80и вÑ\8bбоÑ\80е Ñ\81поÑ\81оба Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f пÑ\80иложениÑ\8f:
-* Ð\98Ñ\81полÑ\8cзование более безопаÑ\81ного пÑ\80оÑ\82окола HTTPS
-* Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка пÑ\80иложениÑ\8f
-* Ð\9fеÑ\80езагÑ\80Ñ\83зка пÑ\80иложениÑ\8f
-* Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f
-* УпÑ\80авление памÑ\8fÑ\82Ñ\8cÑ\8e
-* Ð\98Ñ\81полÑ\8cзование пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий пеÑ\80ед запÑ\83Ñ\81ком пÑ\80иложениÑ\8f.
+* Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c â\80\94 HTTPS
+* Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е
+* Ð\9fеÑ\80езапÑ\83Ñ\81ки
+* РепликаÑ\86иÑ\8f (колиÑ\87еÑ\81Ñ\82во запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов)
+* Ð\9fамÑ\8fÑ\82Ñ\8c
+* Ð\9fÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком
-Ð\9eÑ\81ознание Ñ\8dÑ\82иÑ\85 идей и Ñ\82ого, как иÑ\85 пÑ\80именÑ\8fÑ\82Ñ\8c, должно даÑ\82Ñ\8c Ð\92ам инÑ\82Ñ\83иÑ\82ивное понимание, необÑ\85одимое длÑ\8f пÑ\80инÑ\8fÑ\82иÑ\8f Ñ\80еÑ\88ений пÑ\80и наÑ\81Ñ\82Ñ\80ойке Ñ\80азвертываний. 🤓
+Ð\9fонимание Ñ\8dÑ\82иÑ\85 идей и Ñ\82ого, как иÑ\85 пÑ\80именÑ\8fÑ\82Ñ\8c, даÑ\81Ñ\82 вам инÑ\82Ñ\83иÑ\86иÑ\8e, необÑ\85одимÑ\83Ñ\8e длÑ\8f пÑ\80инÑ\8fÑ\82иÑ\8f Ñ\80еÑ\88ений пÑ\80и наÑ\81Ñ\82Ñ\80ойке и доÑ\80абоÑ\82ке ваÑ\88иÑ\85 Ñ\80азвÑ\91ртываний. 🤓
-В следующих разделах я приведу более конкретные примеры возможных стратегий, которым вы можете следовать. 🚀
+В следующих разделах я приведу более конкретные примеры возможных стратегий. 🚀
-# FastAPI и Docker-конÑ\82ейнеÑ\80Ñ\8b
+# FastAPI в конÑ\82ейнеÑ\80аÑ\85 â\80\94 Docker { #fastapi-in-containers-docker }
-При развёртывании приложений FastAPI, часто начинают с создания **образа контейнера на основе Linux**. Обычно для этого используют <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Затем можно развернуть такой контейнер на сервере одним из нескольких способов.
+При развёртывании приложений FastAPI распространённый подход — собирать **образ контейнера на Linux**. Обычно это делают с помощью <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Затем такой образ контейнера можно развернуть несколькими способами.
-Использование контейнеров на основе Linux имеет ряд преимуществ, включая **безопасность**, **воспроизводимость**, **простоту** и прочие.
+Использование Linux-контейнеров даёт ряд преимуществ: **безопасность**, **воспроизводимость**, **простоту** и другие.
/// tip | Подсказка
-ТоÑ\80опиÑ\82еÑ\81Ñ\8c или Ñ\83же знакомÑ\8b Ñ\81 Ñ\8dÑ\82ой Ñ\82еÑ\85нологией? Ð\9fеÑ\80епÑ\80Ñ\8bгниÑ\82е на Ñ\80аздел [СоздаÑ\82Ñ\8c Docker-обÑ\80аз длÑ\8f FastAPI ð\9f\91\87](#docker-fastapi)
+Ð\9dеÑ\82 вÑ\80емени и вÑ\8b Ñ\83же знакомÑ\8b Ñ\81 Ñ\8dÑ\82им? Ð\9fеÑ\80ейдиÑ\82е к [`Dockerfile` ниже ð\9f\91\87](#build-a-docker-image-for-fastapi).
///
<details>
-<summary>РазвеÑ\80нÑ\83Ñ\82Ñ\8c Dockerfile 👀</summary>
+<summary>Ð\9fÑ\80едпÑ\80оÑ\81моÑ\82Ñ\80 Dockerfile 👀</summary>
```Dockerfile
FROM python:3.9
COPY ./app /code/app
-CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
-# Ð\95Ñ\81ли иÑ\81полÑ\8cзÑ\83еÑ\82е пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80, Ñ\82акой как Nginx или Traefik, добавьте --proxy-headers
-# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
+# Ð\95Ñ\81ли запÑ\83Ñ\81каеÑ\82е за пÑ\80окÑ\81и, напÑ\80имеÑ\80 Nginx или Traefik, добавьте --proxy-headers
+# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
```
</details>
-## Что такое "контейнер"
+## Что такое контейнер { #what-is-a-container }
-Контейнеризация - это **легковесный** способ упаковать приложение, включая все его зависимости и необходимые файлы, чтобы изолировать его от других контейнеров (других приложений и компонентов) работающих на этой же системе.
+Контейнеры (в основном Linux-контейнеры) — это очень **легковесный** способ упаковать приложения вместе со всеми их зависимостями и необходимыми файлами, изолировав их от других контейнеров (других приложений или компонентов) в той же системе.
-Контейнеры, основанные на Linux, запускаются используя ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это значит, что они очень легковесные (по сравнению с полноценными виртуальными машинами, полностью эмулирующими работу операционной системы).
+Linux-контейнеры запускаются, используя то же ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это означает, что они очень легковесные (по сравнению с полноценными виртуальными машинами, эмулирующими целую операционную систему).
-Ð\91лагодаÑ\80Ñ\8f Ñ\8dÑ\82омÑ\83, конÑ\82ейнеÑ\80Ñ\8b поÑ\82Ñ\80еблÑ\8fÑ\8eÑ\82 **малое колиÑ\87еÑ\81Ñ\82во Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов**, Ñ\81Ñ\80авнимое Ñ\81 пÑ\80оÑ\86еÑ\81Ñ\81ом запÑ\83Ñ\89еннÑ\8bм напÑ\80Ñ\8fмÑ\83Ñ\8e (виÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f маÑ\88ина поÑ\82Ñ\80ебÑ\83еÑ\82 гоÑ\80аздо больше ресурсов).
+Таким обÑ\80азом, конÑ\82ейнеÑ\80Ñ\8b поÑ\82Ñ\80еблÑ\8fÑ\8eÑ\82 **малое колиÑ\87еÑ\81Ñ\82во Ñ\80еÑ\81Ñ\83Ñ\80Ñ\81ов**, Ñ\81опоÑ\81Ñ\82авимое Ñ\81 запÑ\83Ñ\81ком пÑ\80оÑ\86еÑ\81Ñ\81ов напÑ\80Ñ\8fмÑ\83Ñ\8e (виÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f маÑ\88ина поÑ\82Ñ\80ебовала бÑ\8b намного больше ресурсов).
-Ð\9aонÑ\82ейнеÑ\80Ñ\8b Ñ\82акже имеÑ\8eÑ\82 Ñ\81обÑ\81Ñ\82веннÑ\8bе запÑ\83Ñ\89еннÑ\8bе **изолиÑ\80ованнÑ\8bе** пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b (но Ñ\87аÑ\81Ñ\82о Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81), Ñ\84айловÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 и Ñ\81еÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\83пÑ\80оÑ\89аеÑ\82 Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвание, Ñ\80азÑ\80абоÑ\82кÑ\83, Ñ\83пÑ\80авление доÑ\81Ñ\82Ñ\83пом и Ñ\82.п.
+У конÑ\82ейнеÑ\80ов Ñ\82акже еÑ\81Ñ\82Ñ\8c Ñ\81обÑ\81Ñ\82веннÑ\8bе **изолиÑ\80ованнÑ\8bе** вÑ\8bполнÑ\8fемÑ\8bе пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b (обÑ\8bÑ\87но вÑ\81его один пÑ\80оÑ\86еÑ\81Ñ\81), Ñ\84айловаÑ\8f Ñ\81иÑ\81Ñ\82ема и Ñ\81еÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\83пÑ\80оÑ\89аеÑ\82 Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвание, безопаÑ\81ноÑ\81Ñ\82Ñ\8c, Ñ\80азÑ\80абоÑ\82кÑ\83 и Ñ\82.д.
-## Что такое "образ контейнера"
+## Что такое образ контейнера { #what-is-a-container-image }
-Для запуска **контейнера** нужен **образ контейнера**.
+**Контейнер** запускается из **образа контейнера**.
-Образ контейнера - это **замороженная** версия всех файлов, переменных окружения, программ и команд по умолчанию, необходимых для работы приложения. **Замороженный** - означает, что **образ** не запущен и не выполняется, это всего лишь упакованные вместе файлы и метаданные.
+Образ контейнера — это **статическая** версия всех файлов, переменных окружения и команды/программы по умолчанию, которые должны присутствовать в контейнере. Здесь **статическая** означает, что **образ** не запущен, он не выполняется — это только упакованные файлы и метаданные.
-Ð\92 оÑ\82лиÑ\87ие оÑ\82 **обÑ\80аза конÑ\82ейнеÑ\80а**, Ñ\85Ñ\80анÑ\8fÑ\89его неизменное Ñ\81одеÑ\80жимое, под Ñ\82еÑ\80мином **конÑ\82ейнеÑ\80** подÑ\80азÑ\83меваÑ\8eÑ\82 запÑ\83Ñ\89еннÑ\8bй обÑ\80аз, Ñ\82о еÑ\81Ñ\82Ñ\8c обÑ\8aÑ\91кÑ\82, коÑ\82оÑ\80Ñ\8bй **иÑ\81полняется**.
+Ð\92 пÑ\80оÑ\82ивоположноÑ\81Ñ\82Ñ\8c «**обÑ\80азÑ\83 конÑ\82ейнеÑ\80а**» (Ñ\85Ñ\80анÑ\8fÑ\89емÑ\83 Ñ\81Ñ\82аÑ\82иÑ\87еÑ\81кое Ñ\81одеÑ\80жимое), «**конÑ\82ейнеÑ\80**» обÑ\8bÑ\87но ознаÑ\87аеÑ\82 запÑ\83Ñ\89еннÑ\8bй Ñ\8dкземплÑ\8fÑ\80, Ñ\82о, Ñ\87Ñ\82о **вÑ\8bполняется**.
-Ð\9aогда **конÑ\82ейнеÑ\80** запÑ\83Ñ\89ен (на оÑ\81новании **обÑ\80аза**), он можеÑ\82 Ñ\81оздаваÑ\82Ñ\8c и изменÑ\8fÑ\82Ñ\8c Ñ\84айлÑ\8b, пеÑ\80еменнÑ\8bе окÑ\80Ñ\83жениÑ\8f и Ñ\82.д. ÐÑ\82и изменениÑ\8f бÑ\83дÑ\83Ñ\82 Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82воваÑ\82Ñ\8c Ñ\82олÑ\8cко внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а, но не бÑ\83дÑ\83Ñ\82 Ñ\81оÑ\85Ñ\80анÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f в обÑ\80азе конÑ\82ейнеÑ\80а (не бÑ\83дÑ\83Ñ\82 Ñ\81оÑ\85Ñ\80аненÑ\8b на диск).
+Ð\9aогда **конÑ\82ейнеÑ\80** запÑ\83Ñ\89ен (на оÑ\81нове **обÑ\80аза конÑ\82ейнеÑ\80а**), он можеÑ\82 Ñ\81оздаваÑ\82Ñ\8c или изменÑ\8fÑ\82Ñ\8c Ñ\84айлÑ\8b, пеÑ\80еменнÑ\8bе окÑ\80Ñ\83жениÑ\8f и Ñ\82.д.. ÐÑ\82и изменениÑ\8f Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83Ñ\8eÑ\82 Ñ\82олÑ\8cко внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а и не Ñ\81оÑ\85Ñ\80анÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f в иÑ\81Ñ\85одном обÑ\80азе конÑ\82ейнеÑ\80а (не запиÑ\81Ñ\8bваÑ\8eÑ\82Ñ\81Ñ\8f на диск).
-Образ контейнера можно сравнить с файлом, содержащем **программу**, например, как файл `main.py`.
+Образ контейнера можно сравнить с **файлами программы**, например `python` и каким-то файлом `main.py`.
-Ð\98 **конÑ\82ейнеÑ\80** (в оÑ\82лиÑ\87ие оÑ\82 **обÑ\80аза**) - Ñ\8dÑ\82о на Ñ\81амом деле вÑ\8bполнÑ\8fемÑ\8bй Ñ\8dкземплÑ\8fÑ\80 обÑ\80аза, пÑ\80имеÑ\80но как **пÑ\80оÑ\86еÑ\81Ñ\81**. Ð\9fо Ñ\84акÑ\82Ñ\83, конÑ\82ейнеÑ\80 запÑ\83Ñ\89ен Ñ\82олÑ\8cко когда запÑ\83Ñ\89енÑ\8b его пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b (Ñ\87аÑ\89е, вÑ\81его один пÑ\80оÑ\86еÑ\81Ñ\81) и оÑ\81Ñ\82ановлен, когда запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов неÑ\82.
+Ð\90 Ñ\81ам **конÑ\82ейнеÑ\80** (в оÑ\82лиÑ\87ие оÑ\82 **обÑ\80аза конÑ\82ейнеÑ\80а**) â\80\94 Ñ\8dÑ\82о Ñ\84акÑ\82иÑ\87еÑ\81ки запÑ\83Ñ\89еннÑ\8bй Ñ\8dкземплÑ\8fÑ\80 обÑ\80аза, Ñ\81опоÑ\81Ñ\82авимÑ\8bй Ñ\81 **пÑ\80оÑ\86еÑ\81Ñ\81ом**. Ð\9fо Ñ\81Ñ\83Ñ\82и, конÑ\82ейнеÑ\80 Ñ\80абоÑ\82аеÑ\82 Ñ\82олÑ\8cко Ñ\82огда, когда в нÑ\91м еÑ\81Ñ\82Ñ\8c **запÑ\83Ñ\89еннÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81** (и обÑ\8bÑ\87но Ñ\8dÑ\82о один пÑ\80оÑ\86еÑ\81Ñ\81). Ð\9aонÑ\82ейнеÑ\80 оÑ\81Ñ\82анавливаеÑ\82Ñ\81Ñ\8f, когда в нÑ\91м не оÑ\81Ñ\82аÑ\91Ñ\82Ñ\81Ñ\8f запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов.
-## Образы контейнеров
+## Образы контейнеров { #container-images }
-Docker является одним из основных инструментов для создания **образов** и **контейнеров** и управления ими.
+Docker — один из основных инструментов для создания и управления **образами контейнеров** и **контейнерами**.
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 обÑ\89едоÑ\81Ñ\82Ñ\83пнÑ\8bй <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> Ñ\81 подгоÑ\82овленнÑ\8bми **оÑ\84иÑ\86иалÑ\8cнÑ\8bми обÑ\80азами** многих инструментов, окружений, баз данных и приложений.
+СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 пÑ\83блиÑ\87нÑ\8bй <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> Ñ\81 гоÑ\82овÑ\8bми **оÑ\84иÑ\86иалÑ\8cнÑ\8bми обÑ\80азами** длÑ\8f многих инструментов, окружений, баз данных и приложений.
-Ð\9a пÑ\80имеÑ\80Ñ\83, есть официальный <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">образ Python</a>.
+Ð\9dапÑ\80имеÑ\80, есть официальный <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">образ Python</a>.
-Также Ñ\82ам пÑ\80едÑ\81Ñ\82авленÑ\8b и дÑ\80Ñ\83гие полезнÑ\8bе обÑ\80азÑ\8b, Ñ\82акие как базÑ\8b данных:
+Ð\90 Ñ\82акже множеÑ\81Ñ\82во обÑ\80азов длÑ\8f Ñ\80азнÑ\8bÑ\85 веÑ\89ей, напÑ\80имеÑ\80 баз данных:
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
-* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>
+* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, и т.д.
-и Ñ\82.п.
+Ð\98Ñ\81полÑ\8cзÑ\83Ñ\8f гоÑ\82овÑ\8bе обÑ\80азÑ\8b, оÑ\87енÑ\8c легко **комбиниÑ\80оваÑ\82Ñ\8c** Ñ\80азнÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b и иÑ\81полÑ\8cзоваÑ\82Ñ\8c иÑ\85. Ð\9dапÑ\80имеÑ\80, Ñ\87Ñ\82обÑ\8b попÑ\80обоваÑ\82Ñ\8c новÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85. Ð\92 болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев можно воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f **оÑ\84иÑ\86иалÑ\8cнÑ\8bми обÑ\80азами** и пÑ\80оÑ\81Ñ\82о наÑ\81Ñ\82Ñ\80оиÑ\82Ñ\8c иÑ\85 Ñ\87еÑ\80ез пеÑ\80еменнÑ\8bе окÑ\80Ñ\83жениÑ\8f.
-Ð\98Ñ\81полÑ\8cзование подгоÑ\82овленнÑ\8bÑ\85 обÑ\80азов знаÑ\87иÑ\82елÑ\8cно Ñ\83пÑ\80оÑ\89аеÑ\82 **комбиниÑ\80ование** и иÑ\81полÑ\8cзование Ñ\80азнÑ\8bÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов. Ð\9dапÑ\80имеÑ\80, вÑ\8b можеÑ\82е попÑ\8bÑ\82аÑ\82Ñ\8cÑ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c новÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85. Ð\92 болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c **оÑ\84иÑ\86иалÑ\8cнÑ\8bй обÑ\80аз** и вÑ\81его лиÑ\88Ñ\8c Ñ\83казаÑ\82Ñ\8c пеÑ\80еменнÑ\8bе окÑ\80Ñ\83жениÑ\8f.
+Таким обÑ\80азом, во многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вÑ\8b можеÑ\82е изÑ\83Ñ\87иÑ\82Ñ\8c конÑ\82ейнеÑ\80Ñ\8b и Docker и пеÑ\80еиÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82и знаниÑ\8f Ñ\81 множеÑ\81Ñ\82вом Ñ\80азлиÑ\87нÑ\8bÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов и компоненÑ\82ов.
-Таким обÑ\80азом, вÑ\8b можеÑ\82е изÑ\83Ñ\87иÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\82акое конÑ\82ейнеÑ\80изаÑ\86иÑ\8f и Docker, и иÑ\81полÑ\8cзоваÑ\82Ñ\8c полÑ\83Ñ\87еннÑ\8bе знаниÑ\8f Ñ\81 Ñ\80азнÑ\8bми инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ами и компоненÑ\82ами.
+Ð\9dапÑ\80имеÑ\80, вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c **неÑ\81колÑ\8cко конÑ\82ейнеÑ\80ов**: Ñ\81 базой даннÑ\8bÑ\85, Python-пÑ\80иложением, веб-Ñ\81еÑ\80веÑ\80ом Ñ\81 Ñ\84Ñ\80онÑ\82ендом на React и Ñ\81вÑ\8fзаÑ\82Ñ\8c иÑ\85 Ñ\87еÑ\80ез внÑ\83Ñ\82Ñ\80еннÑ\8eÑ\8e Ñ\81еÑ\82Ñ\8c.
-Так, вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c одновÑ\80еменно **множеÑ\81Ñ\82во конÑ\82ейнеÑ\80ов** Ñ\81 базой даннÑ\8bÑ\85, Python-пÑ\80иложением, веб-Ñ\81еÑ\80веÑ\80ом, React-пÑ\80иложением и Ñ\81оединиÑ\82Ñ\8c иÑ\85 вмеÑ\81Ñ\82е Ñ\87еÑ\80ез внÑ\83Ñ\82Ñ\80еннÑ\8eÑ\8e Ñ\81еÑ\82Ñ\8c.
+Ð\92Ñ\81е Ñ\81иÑ\81Ñ\82емÑ\8b Ñ\83пÑ\80авлениÑ\8f конÑ\82ейнеÑ\80ами (Ñ\82акие как Docker или Kubernetes) имеÑ\8eÑ\82 инÑ\82егÑ\80иÑ\80ованнÑ\8bе возможноÑ\81Ñ\82и длÑ\8f Ñ\82акого Ñ\81еÑ\82евого взаимодейÑ\81Ñ\82виÑ\8f.
-Все системы управления контейнерами (такие, как Docker или Kubernetes) имеют встроенные возможности для организации такого сетевого взаимодействия.
+## Контейнеры и процессы { #containers-and-processes }
-## Контейнеры и процессы
+**Образ контейнера** обычно включает в свои метаданные программу или команду по умолчанию, которую следует запускать при старте **контейнера**, а также параметры, передаваемые этой программе. Это очень похоже на запуск команды в терминале.
-Ð\9eбÑ\8bÑ\87но **обÑ\80аз конÑ\82ейнеÑ\80а** Ñ\81одеÑ\80жиÑ\82 меÑ\82аданнÑ\8bе пÑ\80едÑ\83Ñ\81Ñ\82ановленной пÑ\80огÑ\80аммÑ\8b или командÑ\83, коÑ\82оÑ\80Ñ\83Ñ\8e Ñ\81ледÑ\83еÑ\82 вÑ\8bполниÑ\82Ñ\8c пÑ\80и запÑ\83Ñ\81ке **конÑ\82ейнеÑ\80а**. Также он можеÑ\82 Ñ\81одеÑ\80жаÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80Ñ\8b, пеÑ\80едаваемÑ\8bе пÑ\80едÑ\83Ñ\81Ñ\82ановленной пÑ\80огÑ\80амме. Ð\9fоÑ\85оже на Ñ\82о, как еÑ\81ли бÑ\8b вÑ\8b запÑ\83Ñ\81кали Ñ\82акÑ\83Ñ\8e пÑ\80огÑ\80аммÑ\83 Ñ\87еÑ\80ез Ñ\82еÑ\80минал.
+Ð\9aогда **конÑ\82ейнеÑ\80** Ñ\81Ñ\82аÑ\80Ñ\82Ñ\83еÑ\82, он вÑ\8bполнÑ\8fеÑ\82 Ñ\83казаннÑ\83Ñ\8e командÑ\83/пÑ\80огÑ\80аммÑ\83 (Ñ\85оÑ\82Ñ\8f вÑ\8b можеÑ\82е пеÑ\80еопÑ\80еделиÑ\82Ñ\8c Ñ\8dÑ\82о и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c дÑ\80Ñ\83гÑ\83Ñ\8e командÑ\83/пÑ\80огÑ\80аммÑ\83).
-Ð\9aогда **конÑ\82ейнеÑ\80** запÑ\83Ñ\89ен, он бÑ\83деÑ\82 вÑ\8bполнÑ\8fÑ\82Ñ\8c пÑ\80опиÑ\81аннÑ\8bе в нÑ\91м командÑ\8b и пÑ\80огÑ\80аммÑ\8b. Ð\9dо вÑ\8b можеÑ\82е измениÑ\82Ñ\8c его Ñ\82ак, Ñ\87Ñ\82об он вÑ\8bполнÑ\8fл дÑ\80Ñ\83гие командÑ\8b и пÑ\80огÑ\80аммÑ\8b.
+Ð\9aонÑ\82ейнеÑ\80 Ñ\80абоÑ\82аеÑ\82 до Ñ\82еÑ\85 поÑ\80, пока Ñ\80абоÑ\82аеÑ\82 его **главнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81** (команда или пÑ\80огÑ\80амма).
-Ð\9aонÑ\82ейнеÑ\80 бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c до Ñ\82еÑ\85 поÑ\80, пока вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f его **главнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81** (команда или пÑ\80огÑ\80амма).
+Ð\9eбÑ\8bÑ\87но в конÑ\82ейнеÑ\80е еÑ\81Ñ\82Ñ\8c **один пÑ\80оÑ\86еÑ\81Ñ\81**, но главнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 запÑ\83Ñ\81каÑ\82Ñ\8c подпÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b, и Ñ\82огда в Ñ\82ом же конÑ\82ейнеÑ\80е бÑ\83деÑ\82 **неÑ\81колÑ\8cко пÑ\80оÑ\86еÑ\81Ñ\81ов**.
-Ð\92 конÑ\82ейнеÑ\80е обÑ\8bÑ\87но вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f **Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81**, но оÑ\82 его имени можно запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c дÑ\80Ñ\83гие пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b, Ñ\82огда в Ñ\8dÑ\82ом же в конÑ\82ейнеÑ\80е бÑ\83деÑ\82 вÑ\8bполнÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f **множеÑ\81Ñ\82во пÑ\80оÑ\86еÑ\81Ñ\81ов**.
+Ð\9dелÑ\8cзÑ\8f имеÑ\82Ñ\8c Ñ\80абоÑ\82аÑ\8eÑ\89ий конÑ\82ейнеÑ\80 без **Ñ\85оÑ\82Ñ\8f бÑ\8b одного запÑ\83Ñ\89енного пÑ\80оÑ\86еÑ\81Ñ\81а**. Ð\95Ñ\81ли главнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81 оÑ\81Ñ\82анавливаеÑ\82Ñ\81Ñ\8f, конÑ\82ейнеÑ\80 оÑ\81Ñ\82анавливаеÑ\82Ñ\81Ñ\8f.
-Контейнер не считается запущенным, если в нём **не выполняется хотя бы один процесс**. Если главный процесс остановлен, значит и контейнер остановлен.
+## Создать Docker-образ для FastAPI { #build-a-docker-image-for-fastapi }
-## Создать Docker-образ для FastAPI
+Итак, давайте что-нибудь соберём! 🚀
-ЧÑ\82о ж, давайÑ\82е Ñ\83жÑ\91 Ñ\81оздадим Ñ\87Ñ\82о-нибÑ\83дÑ\8c! ð\9f\9a\80
+Я покажÑ\83, как Ñ\81обÑ\80аÑ\82Ñ\8c **Docker-обÑ\80аз** длÑ\8f FastAPI **Ñ\81 нÑ\83лÑ\8f** на оÑ\81нове **оÑ\84иÑ\86иалÑ\8cного обÑ\80аза Python**.
-Я покажÑ\83 Ð\92ам, как Ñ\81обиÑ\80аÑ\82Ñ\8c **Docker-обÑ\80аз** длÑ\8f FastAPI **Ñ\81 нÑ\83лÑ\8f**, оÑ\81новÑ\8bваÑ\8fÑ\81Ñ\8c на **оÑ\84иÑ\86иалÑ\8cном обÑ\80азе Python**.
+Ð\98менно Ñ\82ак Ñ\81Ñ\82оиÑ\82 делаÑ\82Ñ\8c в **болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев**, напÑ\80имеÑ\80:
-Такой подход сгодится для **большинства случаев**, например:
+* При использовании **Kubernetes** или похожих инструментов
+* При запуске на **Raspberry Pi**
+* При использовании облачного сервиса, который запускает для вас образ контейнера и т.п.
-* Использование с **Kubernetes** или аналогичным инструментом
-* Запуск в **Raspberry Pi**
-* Использование в облачных сервисах, запускающих образы контейнеров для вас и т.п.
+### Зависимости пакетов { #package-requirements }
-### Установить зависимости
+Обычно **зависимости** вашего приложения описаны в каком-то файле.
-Ð\9eбÑ\8bÑ\87но ваÑ\88емÑ\83 пÑ\80иложениÑ\8e необÑ\85одимÑ\8b **дополниÑ\82елÑ\8cнÑ\8bе библиоÑ\82еки**, Ñ\81пиÑ\81ок коÑ\82оÑ\80Ñ\8bÑ\85 наÑ\85одиÑ\82Ñ\81Ñ\8f в оÑ\82делÑ\8cном Ñ\84айле.
+Ð\9aонкÑ\80еÑ\82нÑ\8bй Ñ\84оÑ\80маÑ\82 завиÑ\81иÑ\82 в оÑ\81новном оÑ\82 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82а, коÑ\82оÑ\80Ñ\8bм вÑ\8b **Ñ\83Ñ\81Ñ\82анавливаеÑ\82е** Ñ\8dÑ\82и завиÑ\81имоÑ\81Ñ\82и.
-Ð\9dа название и Ñ\81одеÑ\80жание Ñ\82акого Ñ\84айла влиÑ\8fеÑ\82 вÑ\8bбÑ\80аннÑ\8bй Ð\92ами инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82 **Ñ\83Ñ\81Ñ\82ановки** Ñ\8dÑ\82иÑ\85 библиоÑ\82ек (завиÑ\81имоÑ\81Ñ\82ей).
+ЧаÑ\89е вÑ\81его иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f Ñ\84айл `requirements.txt` Ñ\81 именами пакеÑ\82ов и иÑ\85 веÑ\80Ñ\81иÑ\8fми по одномÑ\83 на Ñ\81Ñ\82Ñ\80окÑ\83.
-ЧаÑ\89е вÑ\81его Ñ\8dÑ\82о пÑ\80оÑ\81Ñ\82ой Ñ\84айл `requirements.txt` Ñ\81 поÑ\81Ñ\82Ñ\80оÑ\87нÑ\8bм пеÑ\80еÑ\87иÑ\81лением библиоÑ\82ек и иÑ\85 версий.
+РазÑ\83мееÑ\82Ñ\81Ñ\8f, вÑ\8b бÑ\83деÑ\82е пÑ\80идеÑ\80живаÑ\82Ñ\8cÑ\81Ñ\8f Ñ\82еÑ\85 же идей, Ñ\87Ñ\82о опиÑ\81анÑ\8b здеÑ\81Ñ\8c: [Ð\9e веÑ\80Ñ\81иÑ\8fÑ\85 FastAPI](versions.md){.internal-link target=_blank}, Ñ\87Ñ\82обÑ\8b задаÑ\82Ñ\8c диапазонÑ\8b версий.
-При этом Вы, для выбора версий, будете использовать те же идеи, что упомянуты на странице [О версиях FastAPI](versions.md){.internal-link target=_blank}.
-
-Ваш файл `requirements.txt` может выглядеть как-то так:
+Например, ваш `requirements.txt` может выглядеть так:
```
-fastapi>=0.68.0,<0.69.0
-pydantic>=1.8.0,<2.0.0
-uvicorn>=0.15.0,<0.16.0
+fastapi[standard]>=0.113.0,<0.114.0
+pydantic>=2.7.0,<3.0.0
```
-УÑ\81Ñ\82анавливаÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82и пÑ\80оÑ\89е вÑ\81его Ñ\81 помоÑ\89Ñ\8cÑ\8e `pip`:
+Ð\98 обÑ\8bÑ\87но вÑ\8b Ñ\83Ñ\81Ñ\82ановиÑ\82е Ñ\8dÑ\82и завиÑ\81имоÑ\81Ñ\82и командой `pip`, напÑ\80имеÑ\80:
<div class="termy">
```console
$ pip install -r requirements.txt
---> 100%
-Successfully installed fastapi pydantic uvicorn
+Successfully installed fastapi pydantic
```
</div>
/// info | Информация
-Существуют и другие инструменты управления зависимостями.
-
-В этом же разделе, но позже, я покажу вам пример использования Poetry. 👇
+Существуют и другие форматы и инструменты для описания и установки зависимостей.
///
-### СоздаÑ\82Ñ\8c пÑ\80иложение **FastAPI**
+### СоздаÑ\82Ñ\8c код **FastAPI** { #create-the-fastapi-code }
* Создайте директорию `app` и перейдите в неё.
* Создайте пустой файл `__init__.py`.
-* Создайте файл `main.py` и заполните его:
+* Создайте файл `main.py` со следующим содержимым:
```Python
from typing import Union
return {"item_id": item_id, "q": q}
```
-### Dockerfile
+### Dockerfile { #dockerfile }
-Ð\92 Ñ\8dÑ\82ой же диÑ\80екÑ\82оÑ\80ии Ñ\81оздайÑ\82е Ñ\84айл `Dockerfile` и заполниÑ\82е его:
+ТепеÑ\80Ñ\8c в Ñ\82ой же диÑ\80екÑ\82оÑ\80ии пÑ\80оекÑ\82а Ñ\81оздайÑ\82е Ñ\84айл `Dockerfile`:
```{ .dockerfile .annotate }
-# (1)
+# (1)!
FROM python:3.9
-# (2)
+# (2)!
WORKDIR /code
-# (3)
+# (3)!
COPY ./requirements.txt /code/requirements.txt
-# (4)
+# (4)!
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-# (5)
+# (5)!
COPY ./app /code/app
-# (6)
-CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+# (6)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```
-1. Ð\9dаÑ\87ниÑ\82е Ñ\81 оÑ\84иÑ\86иалÑ\8cного обÑ\80аза Python, коÑ\82оÑ\80Ñ\8bй бÑ\83деÑ\82 оÑ\81новой длÑ\8f обÑ\80аза пÑ\80иложениÑ\8f.
+1. Ð\9dаÑ\87инаем Ñ\81 оÑ\84иÑ\86иалÑ\8cного базового обÑ\80аза Python.
-2. Укажите, что в дальнейшем команды запускаемые в контейнере, будут выполняться в директории `/code`.
+2. Устанавливаем текущую рабочую директорию в `/code`.
- Ð\98нÑ\81Ñ\82Ñ\80Ñ\83кÑ\86иÑ\8f Ñ\81оздаÑ\81Ñ\82 Ñ\8dÑ\82Ñ\83 диÑ\80екÑ\82оÑ\80иÑ\8e внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а и мÑ\8b помеÑ\81Ñ\82им в неÑ\91 файл `requirements.txt` и директорию `app`.
+ Ð\97деÑ\81Ñ\8c мÑ\8b Ñ\80азмеÑ\81Ñ\82им файл `requirements.txt` и директорию `app`.
-3. СкопиÑ\80Ñ\83еÑ\82е Ñ\84айл Ñ\81 завиÑ\81имоÑ\81Ñ\82Ñ\8fми из Ñ\82екÑ\83Ñ\89ей диÑ\80екÑ\82оÑ\80ии в `/code`.
+3. Ð\9aопиÑ\80Ñ\83ем Ñ\84айл Ñ\81 завиÑ\81имоÑ\81Ñ\82Ñ\8fми в диÑ\80екÑ\82оÑ\80иÑ\8e `/code`.
- Сначала копируйте **только** файл с зависимостями.
+ Сначала копируйте **только** файл с зависимостями, не остальной код.
- ÐÑ\82оÑ\82 Ñ\84айл **изменÑ\8fеÑ\82Ñ\81Ñ\8f доволÑ\8cно Ñ\80едко**, Docker иÑ\89еÑ\82 изменениÑ\8f пÑ\80и поÑ\81Ñ\82Ñ\80ойке обÑ\80аза и еÑ\81ли не наÑ\85одиÑ\82, Ñ\82о иÑ\81полÑ\8cзÑ\83еÑ\82 **кÑ\8dÑ\88**, в коÑ\82оÑ\80ом Ñ\85Ñ\80анÑ\8fÑ\82Ñ\81Ñ\8f пÑ\80едÑ\8bдÑ\83Ñ\89ие веÑ\80Ñ\81ии Ñ\81боÑ\80ки обÑ\80аза.
+ Так как Ñ\8dÑ\82оÑ\82 Ñ\84айл **менÑ\8fеÑ\82Ñ\81Ñ\8f неÑ\87аÑ\81Ñ\82о**, Docker опÑ\80еделиÑ\82 Ñ\8dÑ\82о и иÑ\81полÑ\8cзÑ\83еÑ\82 **кÑ\8dÑ\88** на Ñ\8dÑ\82ом Ñ\88аге, Ñ\87Ñ\82о позволиÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c кÑ\8dÑ\88 и на Ñ\81ледÑ\83Ñ\8eÑ\89ем Ñ\88аге.
-4. УÑ\81Ñ\82ановиÑ\82е библиоÑ\82еки пеÑ\80еÑ\87иÑ\81леннÑ\8bе в Ñ\84айле Ñ\81 завиÑ\81имоÑ\81Ñ\82ями.
+4. УÑ\81Ñ\82анавливаем завиÑ\81имоÑ\81Ñ\82и из Ñ\84айла Ñ\81 Ñ\82Ñ\80ебованиями.
- Ð\9eпÑ\86иÑ\8f `--no-cache-dir` Ñ\83казÑ\8bваеÑ\82 `pip` не Ñ\81оÑ\85Ñ\80анÑ\8fÑ\82Ñ\8c загÑ\80Ñ\83жаемÑ\8bе библиоÑ\82еки на локалÑ\8cной маÑ\88ине длÑ\8f иÑ\81полÑ\8cзованиÑ\8f иÑ\85 в Ñ\81лÑ\83Ñ\87ае повÑ\82оÑ\80ной загÑ\80Ñ\83зки. Ð\92 конÑ\82ейнеÑ\80е, в Ñ\81лÑ\83Ñ\87ае пеÑ\80еÑ\81боÑ\80ки Ñ\8dÑ\82ого Ñ\88ага, они вÑ\81Ñ\91 Ñ\80авно бÑ\83дÑ\83Ñ\82 Ñ\83даленÑ\8b.
+ Ð\9eпÑ\86иÑ\8f `--no-cache-dir` Ñ\83казÑ\8bваеÑ\82 `pip` не Ñ\81оÑ\85Ñ\80анÑ\8fÑ\82Ñ\8c загÑ\80Ñ\83женнÑ\8bе пакеÑ\82Ñ\8b локалÑ\8cно, Ñ\82.к. Ñ\8dÑ\82о нÑ\83жно Ñ\82олÑ\8cко еÑ\81ли `pip` бÑ\83деÑ\82 запÑ\83Ñ\81каÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81нова длÑ\8f Ñ\83Ñ\81Ñ\82ановки Ñ\82еÑ\85 же пакеÑ\82ов, а пÑ\80и Ñ\80абоÑ\82е Ñ\81 конÑ\82ейнеÑ\80ами Ñ\8dÑ\82о обÑ\8bÑ\87но не Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f.
/// note | Заметка
- Опция `--no-cache-dir` нужна только для `pip`, она никак не влияет на Docker или контейнеры.
+ `--no-cache-dir` относится только к `pip` и не имеет отношения к Docker или контейнерам.
///
- Ð\9eпÑ\86иÑ\8f `--upgrade` Ñ\83казÑ\8bваеÑ\82 `pip` обновиÑ\82Ñ\8c библиоÑ\82еки, емли они уже установлены.
+ Ð\9eпÑ\86иÑ\8f `--upgrade` Ñ\83казÑ\8bваеÑ\82 `pip` обновлÑ\8fÑ\82Ñ\8c пакеÑ\82Ñ\8b, еÑ\81ли они уже установлены.
- Ð\9aак и в пÑ\80едÑ\8bдÑ\83Ñ\89ем Ñ\88аге Ñ\81 копиÑ\80ованием Ñ\84айла, Ñ\8dÑ\82оÑ\82 Ñ\88аг Ñ\82акже бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c **кÑ\8dÑ\88 Docker** в Ñ\81лÑ\83Ñ\87ае оÑ\82Ñ\81Ñ\83Ñ\82Ñ\81Ñ\82виÑ\8f изменений.
+ Ð\9fоÑ\81колÑ\8cкÑ\83 пÑ\80едÑ\8bдÑ\83Ñ\89ий Ñ\88аг Ñ\81 копиÑ\80ованием Ñ\84айла можеÑ\82 бÑ\8bÑ\82Ñ\8c обÑ\80абоÑ\82ан **кÑ\8dÑ\88ем Docker**, Ñ\8dÑ\82оÑ\82 Ñ\88аг Ñ\82акже **иÑ\81полÑ\8cзÑ\83еÑ\82 кÑ\8dÑ\88 Docker**, когда Ñ\8dÑ\82о возможно.
- Использование кэша, особенно на этом шаге, позволит вам **сэкономить** кучу времени при повторной сборке образа, так как зависимости будут сохранены в кеше, а не **загружаться и устанавливаться каждый раз**.
+ Использование кэша на этом шаге **сэкономит** вам много **времени** при повторных сборках образа во время разработки, вместо того чтобы **загружать и устанавливать** все зависимости **каждый раз**.
-5. СкопиÑ\80Ñ\83йÑ\82е диÑ\80екÑ\82оÑ\80иÑ\8e `./app` внÑ\83Ñ\82Ñ\80Ñ\8c диÑ\80екÑ\82оÑ\80ии `/code` (в конÑ\82ейнеÑ\80е).
+5. Ð\9aопиÑ\80Ñ\83ем диÑ\80екÑ\82оÑ\80иÑ\8e `./app` внÑ\83Ñ\82Ñ\80Ñ\8c диÑ\80екÑ\82оÑ\80ии `/code`.
- Так как в Ñ\8dÑ\82ой диÑ\80екÑ\82оÑ\80ии Ñ\80аÑ\81положен код, коÑ\82оÑ\80Ñ\8bй **Ñ\87аÑ\81Ñ\82о изменÑ\8fеÑ\82Ñ\81Ñ\8f**, Ñ\82о иÑ\81полÑ\8cзование **кÑ\8dÑ\88а** на Ñ\8dÑ\82ом Ñ\88аге бÑ\83деÑ\82 наименее Ñ\8dÑ\84Ñ\84екÑ\82ивно, а знаÑ\87иÑ\82 лÑ\83Ñ\87Ñ\88е помеÑ\81Ñ\82иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\88аг **ближе к конÑ\86Ñ\83** `Dockerfile`, дабÑ\8b не Ñ\82еÑ\80Ñ\8fÑ\82Ñ\8c вÑ\8bгодÑ\83 оÑ\82 опÑ\82имизаÑ\86ии пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 Ñ\88агов.
+ Так как здеÑ\81Ñ\8c веÑ\81Ñ\8c код, коÑ\82оÑ\80Ñ\8bй **менÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\89е вÑ\81его**, кÑ\8dÑ\88 Docker **вÑ\80Ñ\8fд ли** бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f длÑ\8f Ñ\8dÑ\82ого Ñ\88агa или **поÑ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ñ\88агов**.
-6. Укажите **команду**, запускающую сервер `uvicorn`.
+ Поэтому важно разместить этот шаг **ближе к концу** `Dockerfile`, чтобы оптимизировать время сборки образа контейнера.
- `CMD` принимает список строк, разделённых запятыми, но при выполнении объединит их через пробел, собрав из них одну команду, которую вы могли бы написать в терминале.
+6. Указываем **команду** для запуска `fastapi run`, под капотом используется Uvicorn.
- Эта команда будет выполнена в **текущей рабочей директории**, а именно в директории `/code`, которая указана в команде `WORKDIR /code`.
+ `CMD` принимает список строк, каждая из которых — это то, что вы бы ввели в командной строке, разделяя пробелами.
- Так как команда вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80и диÑ\80екÑ\82оÑ\80ии `/code`, в коÑ\82оÑ\80Ñ\83Ñ\8e мÑ\8b помеÑ\81Ñ\82или папкÑ\83 `./app` Ñ\81 пÑ\80иложением, Ñ\82о **Uvicorn** Ñ\81можеÑ\82 найÑ\82и и **импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c** обÑ\8aекÑ\82 `app` из Ñ\84айла `app.main`.
+ ÐÑ\82а команда бÑ\83деÑ\82 вÑ\8bполнена из **Ñ\82екÑ\83Ñ\89ей Ñ\80абоÑ\87ей диÑ\80екÑ\82оÑ\80ии**, Ñ\82ой Ñ\81амой `/code`, коÑ\82оÑ\80Ñ\83Ñ\8e вÑ\8b задали вÑ\8bÑ\88е `WORKDIR /code`.
/// tip | Подсказка
-Если ткнёте на кружок с плюсом, то увидите пояснения. 👆
+Посмотрите, что делает каждая строка, кликнув по номеру рядом со строкой. 👆
+
+///
+
+/// warning | Предупреждение
+
+Всегда используйте **exec-форму** инструкции `CMD`, как описано ниже.
///
-На данном этапе структура проекта должны выглядеть так:
+#### Используйте `CMD` — exec-форма { #use-cmd-exec-form }
+
+Инструкцию Docker <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> можно писать в двух формах:
+
+✅ **Exec**-форма:
+
+```Dockerfile
+# ✅ Делайте так
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+⛔️ **Shell**-форма:
+
+```Dockerfile
+# ⛔️ Не делайте так
+CMD fastapi run app/main.py --port 80
+```
+
+Обязательно используйте **exec**-форму, чтобы FastAPI мог корректно завершаться и чтобы срабатывали [события lifespan](../advanced/events.md){.internal-link target=_blank}.
+
+Подробнее об этом читайте в <a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">документации Docker о shell- и exec-формах</a>.
+
+Это особенно заметно при использовании `docker compose`. См. раздел FAQ Docker Compose с техническими подробностями: <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Почему мои сервисы пересоздаются или останавливаются 10 секунд?</a>.
+
+#### Структура директорий { #directory-structure }
+
+Теперь у вас должна быть такая структура:
```
.
└── requirements.txt
```
-#### Ð\98Ñ\81полÑ\8cзование пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80а
+#### Ð\97а пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80ом TLS Ñ\82еÑ\80минаÑ\86ии { #behind-a-tls-termination-proxy }
-Если вы запускаете контейнер за прокси-сервером завершения TLS (балансирующего нагрузку), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`, которая укажет Uvicorn, что он работает позади прокси-сервера и может доверять заголовкам отправляемым им.
+Если вы запускаете контейнер за прокси-сервером завершения TLS (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.
```Dockerfile
-CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
+CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
```
-#### Кэш Docker'а
+#### Кэш Docker { #docker-cache }
-В нашем `Dockerfile` использована полезная хитрость, когда сначала копируется **только файл с зависимостями**, а не вся папка с кодом приложения.
+В этом `Dockerfile` есть важная хитрость: мы сначала копируем **только файл с зависимостями**, а не весь код. Вот зачем.
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
-Docker и подобнÑ\8bе емÑ\83 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b **Ñ\81оздаÑ\8eÑ\82** обÑ\80азÑ\8b конÑ\82ейнеÑ\80ов **поÑ\88агово**, добавлÑ\8fÑ\8f **один Ñ\81лой над дÑ\80Ñ\83гим**, наÑ\87инаÑ\8f Ñ\81 пеÑ\80вой Ñ\81Ñ\82Ñ\80оки `Dockerfile` и добавлÑ\8fÑ\8f Ñ\84айлÑ\8b, Ñ\81оздаваемÑ\8bе пÑ\80и вÑ\8bполнении каждой инÑ\81Ñ\82Ñ\80Ñ\83кÑ\86ии из `Dockerfile`.
+Docker и подобнÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b **Ñ\81Ñ\82Ñ\80оÑ\8fÑ\82** обÑ\80азÑ\8b конÑ\82ейнеÑ\80ов **инкÑ\80еменÑ\82алÑ\8cно**, добавлÑ\8fÑ\8f **Ñ\81лой за Ñ\81лоем**, наÑ\87инаÑ\8f Ñ\81 пеÑ\80вой Ñ\81Ñ\82Ñ\80оки `Dockerfile` и добавлÑ\8fÑ\8f лÑ\8eбÑ\8bе Ñ\84айлÑ\8b, Ñ\81оздаваемÑ\8bе каждой инÑ\81Ñ\82Ñ\80Ñ\83кÑ\86ией `Dockerfile`.
-При создании образа используется **внутренний кэш** и если в файлах нет изменений с момента последней сборки образа, то будет **переиспользован** ранее созданный слой образа, а не повторное копирование файлов и создание слоя с нуля.
-Заметьте, что так как слой следующего шага зависит от слоя предыдущего, то изменения внесённые в промежуточный слой, также повлияют на последующие.
+Docker и подобные инструменты также используют **внутренний кэш** при сборке образа: если файл не изменился с момента предыдущей сборки, будет **переиспользован слой**, созданный в прошлый раз, вместо повторного копирования файла и создания нового слоя с нуля.
-Ð\98збегание копиÑ\80ованиÑ\8f Ñ\84айлов не обÑ\8fзаÑ\82елÑ\8cно Ñ\83лÑ\83Ñ\87Ñ\88иÑ\82 Ñ\81иÑ\82Ñ\83аÑ\86иÑ\8e, но иÑ\81полÑ\8cзование кÑ\8dÑ\88а на одном Ñ\88аге, позволиÑ\82 **иÑ\81полÑ\8cзоваÑ\82Ñ\8c кÑ\8dÑ\88 и на Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ñ\88агаÑ\85**. Ð\9dапÑ\80имеÑ\80, можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c кÑ\8dÑ\88 пÑ\80и Ñ\83Ñ\81Ñ\82ановке зависимостей:
+Само по Ñ\81ебе избегание копиÑ\80ованиÑ\8f вÑ\81еÑ\85 Ñ\84айлов не вÑ\81егда даÑ\91Ñ\82 много, но благодаÑ\80Ñ\8f иÑ\81полÑ\8cзованиÑ\8e кÑ\8dÑ\88а на Ñ\8dÑ\82ом Ñ\88аге Docker Ñ\81можеÑ\82 **иÑ\81полÑ\8cзоваÑ\82Ñ\8c кÑ\8dÑ\88 и на Ñ\81ледÑ\83Ñ\8eÑ\89ем Ñ\88аге**. Ð\9dапÑ\80имеÑ\80, на Ñ\88аге Ñ\83Ñ\81Ñ\82ановки зависимостей:
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
-Файл со списком зависимостей **изменяется довольно редко**. Так что выполнив команду копирования только этого файла, Docker сможет **использовать кэш** на этом шаге.
+Файл с зависимостями **меняется нечасто**. Поэтому, копируя только его, Docker сможет **использовать кэш** для этого шага.
-А затем **использовать кэш и на следующем шаге**, загружающем и устанавливающем зависимости. И вот тут-то мы и **сэкономим много времени**. ✨ ...а не будем томиться в тягостном ожидании. 😪😆
+А затем Docker сможет **использовать кэш и на следующем шаге**, где скачиваются и устанавливаются зависимости. Здесь мы как раз **экономим много времени**. ✨ ...и не скучаем в ожидании. 😪😆
-Ð\94лÑ\8f загÑ\80Ñ\83зки и Ñ\83Ñ\81Ñ\82ановки необÑ\85одимÑ\8bÑ\85 библиоÑ\82ек **можеÑ\82 понадобиÑ\82Ñ\8cÑ\81Ñ\8f неÑ\81колÑ\8cко минÑ\83Ñ\82**, но иÑ\81полÑ\8cзование **кÑ\8dÑ\88а** занимаеÑ\82 неÑ\81колÑ\8cко **Ñ\81екÑ\83нд** макÑ\81имÑ\83м.
+СкаÑ\87ивание и Ñ\83Ñ\81Ñ\82ановка завиÑ\81имоÑ\81Ñ\82ей **можеÑ\82 занÑ\8fÑ\82Ñ\8c минÑ\83Ñ\82Ñ\8b**, но иÑ\81полÑ\8cзование **кÑ\8dÑ\88а** â\80\94 **Ñ\81екÑ\83ндÑ\8b**.
-Ð\98 Ñ\82ак как во вÑ\80емÑ\8f Ñ\80азÑ\80абоÑ\82ки вÑ\8b бÑ\83деÑ\82е Ñ\87аÑ\81Ñ\82о пеÑ\80еÑ\81обиÑ\80аÑ\82Ñ\8c конÑ\82ейнеÑ\80 длÑ\8f пÑ\80овеÑ\80ки Ñ\80абоÑ\82оÑ\81поÑ\81обноÑ\81Ñ\82и внеÑ\81Ñ\91ннÑ\8bÑ\85 изменений, Ñ\82о Ñ\81Ñ\8dкономленнÑ\8bе минÑ\83Ñ\82Ñ\8b Ñ\81ложаÑ\82Ñ\81Ñ\8f в Ñ\87аÑ\81Ñ\8b, а Ñ\82о и дни.
+Ð\9fоÑ\81колÑ\8cкÑ\83 во вÑ\80емÑ\8f Ñ\80азÑ\80абоÑ\82ки вÑ\8b бÑ\83деÑ\82е пеÑ\80еÑ\81обиÑ\80аÑ\82Ñ\8c обÑ\80аз Ñ\81нова и Ñ\81нова, Ñ\87Ñ\82обÑ\8b пÑ\80овеÑ\80иÑ\82Ñ\8c изменениÑ\8f в коде, Ñ\81Ñ\83ммаÑ\80но Ñ\8dÑ\82о Ñ\81Ñ\8dкономиÑ\82 немало вÑ\80емени.
-Так как папка Ñ\81 кодом пÑ\80иложениÑ\8f **изменÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\89е вÑ\81его**, Ñ\82о мÑ\8b Ñ\80аÑ\81положили еÑ\91 в конÑ\86е `Dockerfile`, ведÑ\8c поÑ\81ле внеÑ\81Ñ\91ннÑ\8bÑ\85 в код изменений кÑ\8dÑ\88 не бÑ\83деÑ\82 иÑ\81полÑ\8cзован на Ñ\8dÑ\82ом и Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ñ\88агаÑ\85.
+Ð\97аÑ\82ем, ближе к конÑ\86Ñ\83 `Dockerfile`, мÑ\8b копиÑ\80Ñ\83ем веÑ\81Ñ\8c код. Так как он **менÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\89е вÑ\81его**, мÑ\8b Ñ\81Ñ\82авим Ñ\8dÑ\82оÑ\82 Ñ\88аг в конеÑ\86, поÑ\82омÑ\83 Ñ\87Ñ\82о поÑ\87Ñ\82и вÑ\81егда вÑ\81Ñ\91, Ñ\87Ñ\82о поÑ\81ле него, Ñ\83же не Ñ\81можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c кÑ\8dÑ\88.
```Dockerfile
COPY ./app /code/app
```
-### СоздаÑ\82Ñ\8c Docker-обÑ\80аз
+### СобÑ\80аÑ\82Ñ\8c Docker-обÑ\80аз { #build-the-docker-image }
-Теперь, когда все файлы на своих местах, давайте создадим образ контейнера.
+Теперь, когда все файлы на месте, соберём образ контейнера.
-* Ð\9fеÑ\80ейдиÑ\82е в диÑ\80екÑ\82оÑ\80иÑ\8e пÑ\80оекÑ\82а (в Ñ\82Ñ\83, где Ñ\80аÑ\81положенÑ\8b `Dockerfile` и папка `app` Ñ\81 пÑ\80иложением).
-* Создай обÑ\80аз пÑ\80иложениÑ\8f FastAPI:
+* Ð\9fеÑ\80ейдиÑ\82е в диÑ\80екÑ\82оÑ\80иÑ\8e пÑ\80оекÑ\82а (где ваÑ\88 `Dockerfile` и диÑ\80екÑ\82оÑ\80иÑ\8f `app`).
+* СобеÑ\80иÑ\82е обÑ\80аз FastAPI:
<div class="termy">
/// tip | Подсказка
-Обратите внимание, что в конце написана точка - `.`, это то же самое что и `./`, тем самым мы указываем Docker директорию, из которой нужно выполнять сборку образа контейнера.
+Обратите внимание на точку `.` в конце — это то же самое, что `./`. Так мы указываем Docker, из какой директории собирать образ контейнера.
-Ð\92 данном Ñ\81лÑ\83Ñ\87ае Ñ\8dÑ\82о Ñ\82а же Ñ\81амая директория (`.`).
+Ð\92 данном Ñ\81лÑ\83Ñ\87ае Ñ\8dÑ\82о Ñ\82екÑ\83Ñ\89ая директория (`.`).
///
-### Запуск Docker-контейнера
+### Запустить Docker-контейнер { #start-the-docker-container }
-* Запустите контейнер, основанный на вашем образе:
+* Запустите контейнер на основе вашего образа:
<div class="termy">
</div>
-## Проверка
+## Проверка { #check-it }
-Ð\92Ñ\8b можеÑ\82е пÑ\80овеÑ\80иÑ\82Ñ\8c, Ñ\87Ñ\82о Ð\92аÑ\88 Docker-конÑ\82ейнеÑ\80 Ñ\80абоÑ\82аеÑ\82 пеÑ\80ейдÑ\8f по Ñ\81Ñ\81Ñ\8bлке: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> или <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (или поÑ\85ожей, коÑ\82оÑ\80Ñ\83Ñ\8e иÑ\81полÑ\8cзÑ\83еÑ\82 Ð\92аÑ\88 Docker-Ñ\85оÑ\81Ñ\82).
+Ð\9fÑ\80овеÑ\80Ñ\8cÑ\82е Ñ\80абоÑ\82Ñ\83 по адÑ\80еÑ\81Ñ\83 ваÑ\88его Docker-Ñ\85оÑ\81Ñ\82а, напÑ\80имеÑ\80: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> или <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (или аналогиÑ\87нÑ\8bй URL ваÑ\88его Docker-Ñ\85оÑ\81Ñ\82а).
-Там вÑ\8b Ñ\83видиÑ\82е:
+Ð\92Ñ\8b Ñ\83видиÑ\82е Ñ\87Ñ\82о-Ñ\82о вÑ\80оде:
```JSON
{"item_id": 5, "q": "somequery"}
```
-## Интерактивная документация API
+## Интерактивная документация API { #interactive-api-docs }
-ТепеÑ\80Ñ\8c пеÑ\80ейдиÑ\82е по Ñ\81Ñ\81Ñ\8bлке <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> или <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (или поÑ\85ожей, коÑ\82оÑ\80Ñ\83Ñ\8e иÑ\81полÑ\8cзÑ\83еÑ\82 Ð\92аÑ\88 Docker-Ñ\85оÑ\81Ñ\82).
+ТепеÑ\80Ñ\8c зайдиÑ\82е на <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> или <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (или аналогиÑ\87нÑ\8bй URL ваÑ\88его Docker-Ñ\85оÑ\81Ñ\82а).
-Ð\97деÑ\81Ñ\8c вÑ\8b Ñ\83видиÑ\82е авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e инÑ\82еÑ\80акÑ\82ивнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e API (пÑ\80едоÑ\81Ñ\82авлÑ\8fемÑ\83Ñ\8e <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
+Ð\92Ñ\8b Ñ\83видиÑ\82е авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e инÑ\82еÑ\80акÑ\82ивнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e API (на базе <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):

-## Альтернативная документация API
+## Альтернативная документация API { #alternative-api-docs }
-Также вÑ\8b можеÑ\82е пеÑ\80ейÑ\82и по Ñ\81Ñ\81Ñ\8bлке <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (или поÑ\85ожей, коÑ\82оÑ\80Ñ\83Ñ\8e иÑ\81полÑ\8cзÑ\83еÑ\82 Ð\92аÑ\88 Docker-Ñ\85оÑ\81Ñ\82).
+Также можно оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8c <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> или <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (или аналогиÑ\87нÑ\8bй URL ваÑ\88его Docker-Ñ\85оÑ\81Ñ\82а).
-Ð\97деÑ\81Ñ\8c вÑ\8b Ñ\83видиÑ\82е алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\83Ñ\8e авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e API (пÑ\80едоÑ\81Ñ\82авлÑ\8fемÑ\83Ñ\8e <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
+Ð\92Ñ\8b Ñ\83видиÑ\82е алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\83Ñ\8e авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e (на базе <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):

-## Создание Docker-обÑ\80аза на оÑ\81нове одноÑ\84айлового пÑ\80иложениÑ\8f FastAPI
+## СобÑ\80аÑ\82Ñ\8c Docker-обÑ\80аз длÑ\8f одноÑ\84айлового FastAPI { #build-a-docker-image-with-a-single-file-fastapi }
-Если ваше приложение FastAPI помещено в один файл, например, `main.py` и структура Ваших файлов похожа на эту:
+Если ваше приложение FastAPI — один файл, например `main.py` без директории `./app`, структура файлов может быть такой:
```
.
└── requirements.txt
```
-Ð\92ам нÑ\83жно измениÑ\82Ñ\8c в `Dockerfile` Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89ие пÑ\83Ñ\82и копиÑ\80ованиÑ\8f Ñ\84айлов:
+Тогда в `Dockerfile` нÑ\83жно измениÑ\82Ñ\8c пÑ\83Ñ\82и копиÑ\80ованиÑ\8f:
```{ .dockerfile .annotate hl_lines="10 13" }
FROM python:3.9
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-# (1)
+# (1)!
COPY ./main.py /code/
-# (2)
-CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
+# (2)!
+CMD ["fastapi", "run", "main.py", "--port", "80"]
```
-1. СкопиÑ\80Ñ\83йÑ\82е непоÑ\81Ñ\80едÑ\81Ñ\82венно Ñ\84айл `main.py` в диÑ\80екÑ\82оÑ\80иÑ\8e `/code` (не Ñ\83казÑ\8bвайÑ\82е `./app`).
+1. Ð\9aопиÑ\80Ñ\83ем Ñ\84айл `main.py` напÑ\80Ñ\8fмÑ\83Ñ\8e в `/code` (без диÑ\80екÑ\82оÑ\80ии `./app`).
-2. Ð\9fÑ\80и запÑ\83Ñ\81ке Uvicorn Ñ\83кажиÑ\82е емÑ\83, Ñ\87Ñ\82о обÑ\8aекÑ\82 `app` нÑ\83жно импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c из Ñ\84айла `main` (вмеÑ\81Ñ\82о импоÑ\80Ñ\82иÑ\80ованиÑ\8f из `app.main`).
+2. Ð\98Ñ\81полÑ\8cзÑ\83ем `fastapi run` длÑ\8f запÑ\83Ñ\81ка пÑ\80иложениÑ\8f из одного Ñ\84айла `main.py`.
-Ð\9dаÑ\81Ñ\82Ñ\80ойÑ\82е Uvicorn на иÑ\81полÑ\8cзование `main` вмеÑ\81Ñ\82о `app.main` длÑ\8f импоÑ\80Ñ\82а обÑ\8aекÑ\82а `app`.
+Ð\9aогда вÑ\8b пеÑ\80едаÑ\91Ñ\82е Ñ\84айл в `fastapi run`, он авÑ\82омаÑ\82иÑ\87еÑ\81ки опÑ\80еделиÑ\82, Ñ\87Ñ\82о Ñ\8dÑ\82о одиноÑ\87нÑ\8bй Ñ\84айл, а не Ñ\87аÑ\81Ñ\82Ñ\8c пакеÑ\82а, и поймÑ\91Ñ\82, как его импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c ваÑ\88е FastAPI-пÑ\80иложение. ð\9f\98\8e
-## Концепции развёртывания
+## Концепции развертывания { #deployment-concepts }
-Ð\94авайÑ\82е вÑ\81помним о [Ð\9aонÑ\86епÑ\86иÑ\8fÑ\85 Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bваниÑ\8f](concepts.md){.internal-link target=_blank} и пÑ\80именим иÑ\85 к контейнерам.
+Ð\95Ñ\89Ñ\91 Ñ\80аз Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им [конÑ\86епÑ\86ии Ñ\80азвеÑ\80Ñ\82Ñ\8bваниÑ\8f](concepts.md){.internal-link target=_blank} пÑ\80имениÑ\82елÑ\8cно к контейнерам.
-Контейнеры - это, в основном, инструмент упрощающий **сборку и развёртывание** приложения и они не обязывают к применению какой-то определённой **концепции развёртывания**, а значит мы можем выбирать нужную стратегию.
+Контейнеры главным образом упрощают **сборку и развёртывание** приложения, но не навязывают конкретный подход к этим **концепциям развертывания**, и существует несколько стратегий.
-**ХоÑ\80оÑ\88аÑ\8f новоÑ\81Ñ\82Ñ\8c** в Ñ\82ом, Ñ\87Ñ\82о незавиÑ\81имо оÑ\82 вÑ\8bбÑ\80анной Ñ\81Ñ\82Ñ\80аÑ\82егии, мÑ\8b вÑ\81Ñ\91 Ñ\80авно можем покÑ\80Ñ\8bÑ\82Ñ\8c вÑ\81е конÑ\86епÑ\86ии Ñ\80азвÑ\91ртывания. 🎉
+**ХоÑ\80оÑ\88аÑ\8f новоÑ\81Ñ\82Ñ\8c** в Ñ\82ом, Ñ\87Ñ\82о пÑ\80и лÑ\8eбой Ñ\81Ñ\82Ñ\80аÑ\82егии еÑ\81Ñ\82Ñ\8c Ñ\81поÑ\81об оÑ\85ваÑ\82иÑ\82Ñ\8c вÑ\81е конÑ\86епÑ\86ии Ñ\80азвертывания. 🎉
-Рассмотрим эти **концепции развёртывания** применительно к контейнерам:
+Рассмотрим эти **концепции развертывания** в терминах контейнеров:
-* Использование более безопасного протокола HTTPS
-* Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка пÑ\80иложениÑ\8f
-* Ð\9fеÑ\80езагÑ\80Ñ\83зка пÑ\80иложениÑ\8f
-* Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f
-* УпÑ\80авление памÑ\8fÑ\82Ñ\8cÑ\8e
-* Ð\98Ñ\81полÑ\8cзование пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий пеÑ\80ед запÑ\83Ñ\81ком пÑ\80иложениÑ\8f
+* HTTPS
+* Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е
+* Ð\9fеÑ\80езапÑ\83Ñ\81ки
+* РепликаÑ\86иÑ\8f (колиÑ\87еÑ\81Ñ\82во запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов)
+* Ð\9fамÑ\8fÑ\82Ñ\8c
+* Ð\9fÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком
-## Использование более безопасного протокола HTTPS
+## HTTPS { #https }
-Если мы определимся, что **образ контейнера** будет содержать только приложение FastAPI, то работу с HTTPS можно организовать **снаружи** контейнера при помощи другого инструмента.
+Если мы рассматриваем только **образ контейнера** для приложения FastAPI (и далее запущенный **контейнер**), то HTTPS обычно обрабатывается **внешним** инструментом.
-ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c дÑ\80Ñ\83гой конÑ\82ейнеÑ\80, в коÑ\82оÑ\80ом еÑ\81Ñ\82Ñ\8c, напÑ\80имеÑ\80, <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, Ñ\80абоÑ\82аÑ\8eÑ\89ий Ñ\81 **HTTPS** и **Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно** обновлÑ\8fÑ\8eÑ\89ий **Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b**.
+ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c дÑ\80Ñ\83гой конÑ\82ейнеÑ\80, напÑ\80имеÑ\80 Ñ\81 <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, коÑ\82оÑ\80Ñ\8bй беÑ\80Ñ\91Ñ\82 на Ñ\81ебÑ\8f **HTTPS** и **авÑ\82омаÑ\82иÑ\87еÑ\81кое** полÑ\83Ñ\87ение **Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов**.
/// tip | Подсказка
-Traefik совместим с Docker, Kubernetes и им подобными инструментами. Он очень прост в установке и настройке использования HTTPS для Ваших контейнеров.
+У Traefik есть интеграции с Docker, Kubernetes и другими, поэтому очень легко настроить и сконфигурировать HTTPS для ваших контейнеров.
///
-В качестве альтернативы, работу с HTTPS можно доверить облачному провайдеру, если он предоставляет такую услугу.
+В качестве альтернативы HTTPS может быть реализован как сервис облачного провайдера (при этом приложение всё равно работает в контейнере).
-## Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка и пеÑ\80езагÑ\80Ñ\83зки пÑ\80иложениÑ\8f
+## Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е и пеÑ\80езапÑ\83Ñ\81ки { #running-on-startup-and-restarts }
-Обычно **запуском контейнера с приложением** занимается какой-то отдельный инструмент.
+Обычно есть другой инструмент, отвечающий за **запуск и работу** вашего контейнера.
-Это может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный провайдер** и т.п.
+Это может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный сервис** и т.п.
-В большинстве случаев это простейшие настройки запуска и перезагрузки приложения (при падении). Например, команде запуска Docker-контейнера можно добавить опцию `--restart`.
+В большинстве (или во всех) случаев есть простая опция, чтобы включить запуск контейнера при старте системы и перезапуски при сбоях. Например, в Docker это опция командной строки `--restart`.
-УпÑ\80авление запÑ\83Ñ\81ком и пеÑ\80езагÑ\80Ñ\83зкой пÑ\80иложений без иÑ\81полÑ\8cзованиÑ\8f конÑ\82ейнеÑ\80ов - веÑ\81Ñ\8cма заÑ\82Ñ\80Ñ\83дниÑ\82елÑ\8cно. Ð\9dо пÑ\80и **Ñ\80абоÑ\82е Ñ\81 конÑ\82ейнеÑ\80ами** - Ñ\8dÑ\82о вÑ\81его лиÑ\88Ñ\8c Ñ\84Ñ\83нкÑ\86ионал доÑ\81Ñ\82Ñ\83пнÑ\8bй по умолчанию. ✨
+Ð\91ез конÑ\82ейнеÑ\80ов обеÑ\81пеÑ\87иÑ\82Ñ\8c запÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е и пеÑ\80езапÑ\83Ñ\81ки можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\81ложно. Ð\9dо пÑ\80и **Ñ\80абоÑ\82е Ñ\81 конÑ\82ейнеÑ\80ами** в болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев Ñ\8dÑ\82оÑ\82 Ñ\84Ñ\83нкÑ\86ионал доÑ\81Ñ\82Ñ\83пен по умолчанию. ✨
-## Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f - Указание колиÑ\87еÑ\81Ñ\82ва пÑ\80оÑ\86еÑ\81Ñ\81ов
+## РепликаÑ\86иÑ\8f â\80\94 колиÑ\87еÑ\81Ñ\82во пÑ\80оÑ\86еÑ\81Ñ\81ов { #replication-number-of-processes }
-Ð\95Ñ\81ли Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c <abbr title="Ð\9dеÑ\81колÑ\8cко Ñ\81еÑ\80веÑ\80ов наÑ\81Ñ\82Ñ\80оеннÑ\8bÑ\85 длÑ\8f Ñ\81овмеÑ\81Ñ\82ной Ñ\80абоÑ\82Ñ\8b.">клаÑ\81Ñ\82еÑ\80</abbr> маÑ\88ин под Ñ\83пÑ\80авлением **Kubernetes**, Docker Swarm Mode, Nomad или аналогиÑ\87ной Ñ\81ложной Ñ\81иÑ\81Ñ\82емой оÑ\80кеÑ\81Ñ\82Ñ\80аÑ\86ии конÑ\82ейнеÑ\80ов, Ñ\81коÑ\80ее вÑ\81его, вмеÑ\81Ñ\82о иÑ\81полÑ\8cзованиÑ\8f менеджеÑ\80а пÑ\80оÑ\86еÑ\81Ñ\81ов (Ñ\82ипа Gunicorn и его воÑ\80кеÑ\80Ñ\8b) в каждом конÑ\82ейнеÑ\80е, вÑ\8b заÑ\85оÑ\82иÑ\82е **Ñ\83пÑ\80авлÑ\8fÑ\82Ñ\8c колиÑ\87еÑ\81Ñ\82вом запÑ\83Ñ\89еннÑ\8bÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f** на **Ñ\83Ñ\80овне клаÑ\81Ñ\82еÑ\80а**.
+Ð\95Ñ\81ли Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c <abbr title="Ð\93Ñ\80Ñ\83ппа маÑ\88ин, наÑ\81Ñ\82Ñ\80оеннÑ\8bÑ\85 Ñ\82ак, Ñ\87Ñ\82обÑ\8b бÑ\8bÑ\82Ñ\8c Ñ\81оединеннÑ\8bми и Ñ\80абоÑ\82аÑ\82Ñ\8c вмеÑ\81Ñ\82е опÑ\80еделеннÑ\8bм обÑ\80азом.">клаÑ\81Ñ\82еÑ\80</abbr> маÑ\88ин Ñ\81 **Kubernetes**, Docker Swarm Mode, Nomad или дÑ\80Ñ\83гой поÑ\85ожей Ñ\81иÑ\81Ñ\82емой длÑ\8f Ñ\83пÑ\80авлениÑ\8f Ñ\80аÑ\81пÑ\80еделÑ\91ннÑ\8bми конÑ\82ейнеÑ\80ами на неÑ\81колÑ\8cкиÑ\85 маÑ\88инаÑ\85, Ñ\81коÑ\80ее вÑ\81его вÑ\8b бÑ\83деÑ\82е **Ñ\83пÑ\80авлÑ\8fÑ\82Ñ\8c Ñ\80епликаÑ\86ией** на **Ñ\83Ñ\80овне клаÑ\81Ñ\82еÑ\80а**, а не иÑ\81полÑ\8cзоваÑ\82Ñ\8c **менеджеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81ов** (напÑ\80имеÑ\80, Uvicorn Ñ\81 воÑ\80кеÑ\80ами) в каждом конÑ\82ейнеÑ\80е.
-Ð\92 лÑ\8eбÑ\83Ñ\8e из Ñ\8dÑ\82иÑ\85 Ñ\81иÑ\81Ñ\82ем Ñ\83пÑ\80авлениÑ\8f конÑ\82ейнеÑ\80ами обÑ\8bÑ\87но вÑ\81Ñ\82Ñ\80оен Ñ\81поÑ\81об Ñ\83пÑ\80авлениÑ\8f **колиÑ\87еÑ\81Ñ\82вом запÑ\83Ñ\89еннÑ\8bÑ\85 конÑ\82ейнеÑ\80ов** длÑ\8f Ñ\80аÑ\81пÑ\80еделениÑ\8f **нагÑ\80Ñ\83зки** оÑ\82 вÑ\85одÑ\8fÑ\89иÑ\85 запÑ\80оÑ\81ов на **уровне кластера**.
+Ð\9eдна из Ñ\82акиÑ\85 Ñ\81иÑ\81Ñ\82ем Ñ\83пÑ\80авлениÑ\8f Ñ\80аÑ\81пÑ\80еделÑ\91ннÑ\8bми конÑ\82ейнеÑ\80ами, как Kubernetes, обÑ\8bÑ\87но имееÑ\82 вÑ\81Ñ\82Ñ\80оеннÑ\8bй Ñ\81поÑ\81об Ñ\83пÑ\80авлÑ\8fÑ\82Ñ\8c **Ñ\80епликаÑ\86ией конÑ\82ейнеÑ\80ов**, поддеÑ\80живаÑ\8f **баланÑ\81иÑ\80овкÑ\83 нагÑ\80Ñ\83зки** длÑ\8f вÑ\85одÑ\8fÑ\89иÑ\85 запÑ\80оÑ\81ов â\80\94 вÑ\81Ñ\91 Ñ\8dÑ\82о на **уровне кластера**.
-Ð\92 Ñ\82акой Ñ\81иÑ\82Ñ\83аÑ\86ии Ð\92Ñ\8b, веÑ\80оÑ\8fÑ\82но, заÑ\85оÑ\82иÑ\82е Ñ\81оздаÑ\82Ñ\8c **обÑ\80аз Docker**, как [опиÑ\81ано вÑ\8bÑ\88е](#dockerfile), Ñ\81 Ñ\83Ñ\81Ñ\82ановленнÑ\8bми завиÑ\81имоÑ\81Ñ\82Ñ\8fми и запÑ\83Ñ\81каÑ\8eÑ\89ий **один пÑ\80оÑ\86еÑ\81Ñ\81 Uvicorn** вмеÑ\81Ñ\82о Ñ\82ого, Ñ\87Ñ\82обÑ\8b запÑ\83Ñ\81каÑ\82Ñ\8c Gunicorn Ñ\83пÑ\80авлÑ\8fÑ\8eÑ\89ий неÑ\81колÑ\8cкими воÑ\80кеÑ\80ами Uvicorn.
+Ð\92 Ñ\82акиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вÑ\8b, Ñ\81коÑ\80ее вÑ\81его, заÑ\85оÑ\82иÑ\82е Ñ\81обÑ\80аÑ\82Ñ\8c **Docker-обÑ\80аз Ñ\81 нÑ\83лÑ\8f**, как [опиÑ\81ано вÑ\8bÑ\88е](#dockerfile), Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82и и запÑ\83Ñ\81каÑ\82Ñ\8c **один пÑ\80оÑ\86еÑ\81Ñ\81 Uvicorn** вмеÑ\81Ñ\82о множеÑ\81Ñ\82ва воÑ\80кеÑ\80ов Uvicorn.
-### Балансировщик нагрузки
+### Балансировщик нагрузки { #load-balancer }
-Ð\9eбÑ\8bÑ\87но пÑ\80и иÑ\81полÑ\8cзовании конÑ\82ейнеÑ\80ов один компоненÑ\82 **пÑ\80оÑ\81лÑ\83Ñ\88иваеÑ\82 главнÑ\8bй поÑ\80Ñ\82**. ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c конÑ\82ейнеÑ\80 Ñ\81одеÑ\80жаÑ\89ий **пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80 завеÑ\80Ñ\88ениÑ\8f Ñ\80абоÑ\82Ñ\8b TLS** длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 **HTTPS** или Ñ\87Ñ\82о-Ñ\82о подобное.
+Ð\9fÑ\80и иÑ\81полÑ\8cзовании конÑ\82ейнеÑ\80ов обÑ\8bÑ\87но еÑ\81Ñ\82Ñ\8c компоненÑ\82, **Ñ\81лÑ\83Ñ\88аÑ\8eÑ\89ий главнÑ\8bй поÑ\80Ñ\82**. ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c дÑ\80Ñ\83гой конÑ\82ейнеÑ\80 â\80\94 **пÑ\80окÑ\81и завеÑ\80Ñ\88ениÑ\8f TLS** длÑ\8f обÑ\80абоÑ\82ки **HTTPS** или поÑ\85ожий инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82.
-Поскольку этот компонент **принимает запросы** и равномерно **распределяет** их между компонентами, его также называют **балансировщиком нагрузки**.
+Поскольку этот компонент принимает **нагрузку** запросов и распределяет её между воркерами **сбалансированно**, его часто называют **балансировщиком нагрузки**.
/// tip | Подсказка
-**Прокси-сервер завершения работы TLS** одновременно может быть **балансировщиком нагрузки**.
+Тот же компонент **прокси завершения TLS**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**.
///
-СиÑ\81Ñ\82ема оÑ\80кеÑ\81Ñ\82Ñ\80аÑ\86ии, коÑ\82оÑ\80Ñ\83Ñ\8e вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е длÑ\8f запÑ\83Ñ\81ка и Ñ\83пÑ\80авлениÑ\8f конÑ\82ейнеÑ\80ами, имееÑ\82 вÑ\81Ñ\82Ñ\80оеннÑ\8bй инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82 **Ñ\81еÑ\82евого взаимодейÑ\81Ñ\82виÑ\8f** (напÑ\80имеÑ\80, длÑ\8f пеÑ\80едаÑ\87и HTTP-запÑ\80оÑ\81ов) междÑ\83 конÑ\82ейнеÑ\80ами Ñ\81 Ð\92аÑ\88ими пÑ\80иложениÑ\8fми и **баланÑ\81иÑ\80овÑ\89иком нагÑ\80Ñ\83зки** (коÑ\82оÑ\80Ñ\8bй Ñ\82акже можеÑ\82 бÑ\8bÑ\82Ñ\8c **пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80ом**).
+Ð\9fÑ\80и Ñ\80абоÑ\82е Ñ\81 конÑ\82ейнеÑ\80ами Ñ\81иÑ\81Ñ\82ема, коÑ\82оÑ\80Ñ\83Ñ\8e вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е длÑ\8f запÑ\83Ñ\81ка и Ñ\83пÑ\80авлениÑ\8f ими, Ñ\83же имееÑ\82 внÑ\83Ñ\82Ñ\80енние Ñ\81Ñ\80едÑ\81Ñ\82ва длÑ\8f пеÑ\80едаÑ\87и **Ñ\81еÑ\82евого взаимодейÑ\81Ñ\82виÑ\8f** (напÑ\80имеÑ\80, HTTP-запÑ\80оÑ\81ов) оÑ\82 **баланÑ\81иÑ\80овÑ\89ика нагÑ\80Ñ\83зки** (коÑ\82оÑ\80Ñ\8bй Ñ\82акже можеÑ\82 бÑ\8bÑ\82Ñ\8c **пÑ\80окÑ\81и завеÑ\80Ñ\88ениÑ\8f TLS**) к конÑ\82ейнеÑ\80Ñ\83(-ам) Ñ\81 ваÑ\88им пÑ\80иложением.
-### Один балансировщик - Множество контейнеров
+### Один балансировщик — несколько контейнеров-воркеров { #one-load-balancer-multiple-worker-containers }
-Ð\9fÑ\80и Ñ\80абоÑ\82е Ñ\81 **Kubernetes** или аналогиÑ\87нÑ\8bми Ñ\81иÑ\81Ñ\82емами оÑ\80кеÑ\81Ñ\82Ñ\80аÑ\86ии иÑ\81полÑ\8cзование иÑ\85 внÑ\83Ñ\82Ñ\80енней Ñ\81еÑ\82и позволÑ\8fеÑ\82 имеÑ\82Ñ\8c один **баланÑ\81иÑ\80овÑ\89ик нагÑ\80Ñ\83зки**, коÑ\82оÑ\80Ñ\8bй пÑ\80оÑ\81лÑ\83Ñ\88иваеÑ\82 **главнÑ\8bй** поÑ\80Ñ\82 и пеÑ\80едаÑ\91Ñ\82 запÑ\80оÑ\81Ñ\8b **множеÑ\81Ñ\82вÑ\83 запÑ\83Ñ\89еннÑ\8bÑ\85 конÑ\82ейнеÑ\80ов** Ñ\81 Ð\92аÑ\88ими пÑ\80иложениÑ\8fми.
+Ð\9fÑ\80и Ñ\80абоÑ\82е Ñ\81 **Kubernetes** или поÑ\85ожими Ñ\81иÑ\81Ñ\82емами Ñ\83пÑ\80авлениÑ\8f Ñ\80аÑ\81пÑ\80еделÑ\91ннÑ\8bми конÑ\82ейнеÑ\80ами иÑ\85 внÑ\83Ñ\82Ñ\80енние меÑ\85анизмÑ\8b Ñ\81еÑ\82и позволÑ\8fÑ\8eÑ\82 одномÑ\83 **баланÑ\81иÑ\80овÑ\89икÑ\83 нагÑ\80Ñ\83зки**, Ñ\81лÑ\83Ñ\88аÑ\8eÑ\89емÑ\83 главнÑ\8bй **поÑ\80Ñ\82**, пеÑ\80едаваÑ\82Ñ\8c запÑ\80оÑ\81Ñ\8b в **неÑ\81колÑ\8cко конÑ\82ейнеÑ\80ов**, где запÑ\83Ñ\89ено ваÑ\88е пÑ\80иложение.
-Ð\92 каждом из конÑ\82ейнеÑ\80ов обÑ\8bÑ\87но Ñ\80абоÑ\82аеÑ\82 **Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81** (напÑ\80имеÑ\80, пÑ\80оÑ\86еÑ\81Ñ\81 Uvicorn Ñ\83пÑ\80авлÑ\8fÑ\8eÑ\89ий Ð\92аÑ\88им пÑ\80иложением FastAPI). Ð\9aонÑ\82ейнеÑ\80Ñ\8b могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c **иденÑ\82иÑ\87нÑ\8bми**, запÑ\83Ñ\89еннÑ\8bми на оÑ\81нове одного и Ñ\82ого же обÑ\80аза, но Ñ\83 каждого бÑ\83дÑ\83Ñ\82 Ñ\81вои оÑ\82делÑ\8cнÑ\8bе пÑ\80оÑ\86еÑ\81Ñ\81, памÑ\8fÑ\82Ñ\8c и Ñ\82.п. Таким обÑ\80азом мÑ\8b полÑ\83Ñ\87аем пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82ва **Ñ\80аÑ\81паÑ\80аллеливаниÑ\8f** Ñ\80абоÑ\82Ñ\8b по **Ñ\80азнÑ\8bм Ñ\8fдÑ\80ам** пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а или даже **разным машинам**.
+Ð\9aаждÑ\8bй Ñ\82акой конÑ\82ейнеÑ\80 Ñ\81 ваÑ\88им пÑ\80иложением обÑ\8bÑ\87но имееÑ\82 **Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81** (напÑ\80имеÑ\80, пÑ\80оÑ\86еÑ\81Ñ\81 Uvicorn Ñ\81 ваÑ\88им пÑ\80иложением FastAPI). Ð\92Ñ\81е они â\80\94 **одинаковÑ\8bе конÑ\82ейнеÑ\80Ñ\8b**, запÑ\83Ñ\81каÑ\8eÑ\89ие одно и Ñ\82о же, но Ñ\83 каждого Ñ\81вой пÑ\80оÑ\86еÑ\81Ñ\81, памÑ\8fÑ\82Ñ\8c и Ñ\82.п. Так вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е **паÑ\80аллелизм** по **Ñ\80азнÑ\8bм Ñ\8fдÑ\80ам** CPU или даже **разным машинам**.
-СиÑ\81Ñ\82ема Ñ\83пÑ\80авлениÑ\8f конÑ\82ейнеÑ\80ами Ñ\81 **баланÑ\81иÑ\80овÑ\89иком нагÑ\80Ñ\83зки** бÑ\83деÑ\82 **Ñ\80аÑ\81пÑ\80еделÑ\8fÑ\82Ñ\8c запÑ\80оÑ\81Ñ\8b** к конÑ\82ейнеÑ\80ам Ñ\81 пÑ\80иложениÑ\8fми **по оÑ\87еÑ\80еди**. То еÑ\81Ñ\82Ñ\8c каждÑ\8bй запÑ\80оÑ\81 бÑ\83деÑ\82 обÑ\80абоÑ\82ан одним из множеÑ\81Ñ\82ва **одинаковÑ\8bÑ\85 конÑ\82ейнеÑ\80ов** Ñ\81 одним и Ñ\82ем же пÑ\80иложением.
+СиÑ\81Ñ\82ема Ñ\80аÑ\81пÑ\80еделÑ\91ннÑ\8bÑ\85 конÑ\82ейнеÑ\80ов Ñ\81 **баланÑ\81иÑ\80овÑ\89иком нагÑ\80Ñ\83зки** бÑ\83деÑ\82 **Ñ\80аÑ\81пÑ\80еделÑ\8fÑ\82Ñ\8c запÑ\80оÑ\81Ñ\8b** междÑ\83 конÑ\82ейнеÑ\80ами Ñ\81 ваÑ\88им пÑ\80иложением **по оÑ\87еÑ\80еди**. То еÑ\81Ñ\82Ñ\8c каждÑ\8bй запÑ\80оÑ\81 можеÑ\82 обÑ\80абаÑ\82Ñ\8bваÑ\82Ñ\8cÑ\81Ñ\8f одним из неÑ\81колÑ\8cкиÑ\85 **Ñ\80еплиÑ\86иÑ\80ованнÑ\8bÑ\85 конÑ\82ейнеÑ\80ов**.
-**Балансировщик нагрузки** может обрабатывать запросы к *разным* приложениям, расположенным в вашем кластере (например, если у них разные домены или префиксы пути) и передавать запросы нужному контейнеру с требуемым приложением.
+Обычно такой **балансировщик нагрузки** может также обрабатывать запросы к *другим* приложениям в вашем кластере (например, к другому домену или под другим префиксом пути URL) и направлять их к нужным контейнерам этого *другого* приложения.
-### Один процесс на контейнер
+### Один процесс на контейнер { #one-process-per-container }
-Ð\92 Ñ\8dÑ\82ом ваÑ\80ианÑ\82е **в одном конÑ\82ейнеÑ\80е бÑ\83деÑ\82 запÑ\83Ñ\89ен Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 (Uvicorn)**, а Ñ\83пÑ\80авление изменением колиÑ\87еÑ\81Ñ\82ва запÑ\83Ñ\89еннÑ\8bÑ\85 копий пÑ\80иложениÑ\8f пÑ\80оиÑ\81Ñ\85одиÑ\82 на уровне кластера.
+Ð\92 Ñ\82аком Ñ\81Ñ\86енаÑ\80ии, Ñ\81коÑ\80ее вÑ\81его, вÑ\8b заÑ\85оÑ\82иÑ\82е имеÑ\82Ñ\8c **один (Uvicorn) пÑ\80оÑ\86еÑ\81Ñ\81 на конÑ\82ейнеÑ\80**, Ñ\82ак как Ñ\80епликаÑ\86иÑ\8f Ñ\83же Ñ\83пÑ\80авлÑ\8fеÑ\82Ñ\81Ñ\8f на уровне кластера.
-Ð\97деÑ\81Ñ\8c **не нÑ\83жен** менеджеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81ов Ñ\82ипа Gunicorn, Ñ\83пÑ\80авлÑ\8fÑ\8eÑ\89ий пÑ\80оÑ\86еÑ\81Ñ\81ами Uvicorn, или же Uvicorn, Ñ\83пÑ\80авлÑ\8fÑ\8eÑ\89ий дÑ\80Ñ\83гими пÑ\80оÑ\86еÑ\81Ñ\81ами Uvicorn. Ð\94оÑ\81Ñ\82аÑ\82оÑ\87но **Ñ\82олÑ\8cко одного пÑ\80оÑ\86еÑ\81Ñ\81а Uvicorn** на конÑ\82ейнеÑ\80 (но запÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов не запÑ\80еÑ\89Ñ\91н).
+Ð\9fоÑ\8dÑ\82омÑ\83 в конÑ\82ейнеÑ\80е **не нÑ\83жно** поднимаÑ\82Ñ\8c неÑ\81колÑ\8cко воÑ\80кеÑ\80ов, напÑ\80имеÑ\80 Ñ\87еÑ\80ез опÑ\86иÑ\8e командной Ñ\81Ñ\82Ñ\80оки `--workers`. Ð\9dÑ\83жен **один пÑ\80оÑ\86еÑ\81Ñ\81 Uvicorn** на конÑ\82ейнеÑ\80 (но, возможно, неÑ\81колÑ\8cко конÑ\82ейнеÑ\80ов).
-Ð\98Ñ\81полÑ\8cзование менеджеÑ\80а пÑ\80оÑ\86еÑ\81Ñ\81ов (Gunicorn или Uvicorn) внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а Ñ\82олÑ\8cко добавлÑ\8fеÑ\82 **излиÑ\88нее Ñ\83Ñ\81ложнение**, Ñ\82ак как Ñ\83пÑ\80авление Ñ\81ледÑ\83еÑ\82 оÑ\81Ñ\83Ñ\89еÑ\81Ñ\82влÑ\8fÑ\82Ñ\8c Ñ\81иÑ\81Ñ\82емой оÑ\80кеÑ\81Ñ\82Ñ\80аÑ\86ии.
+Ð\9dалиÑ\87ие оÑ\82делÑ\8cного менеджеÑ\80а пÑ\80оÑ\86еÑ\81Ñ\81ов внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а (как пÑ\80и неÑ\81колÑ\8cкиÑ\85 воÑ\80кеÑ\80аÑ\85) Ñ\82олÑ\8cко добавиÑ\82 **лиÑ\88нÑ\8eÑ\8e Ñ\81ложноÑ\81Ñ\82Ñ\8c**, коÑ\82оÑ\80Ñ\83Ñ\8e, веÑ\80оÑ\8fÑ\82но, Ñ\83же беÑ\80Ñ\91Ñ\82 на Ñ\81ебÑ\8f ваÑ\88а клаÑ\81Ñ\82еÑ\80наÑ\8f Ñ\81иÑ\81Ñ\82ема.
-### Ð\9cножеÑ\81Ñ\82во пÑ\80оÑ\86еÑ\81Ñ\81ов внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а длÑ\8f оÑ\81обÑ\8bÑ\85 Ñ\81лÑ\83Ñ\87аев
+### Ð\9aонÑ\82ейнеÑ\80Ñ\8b Ñ\81 неÑ\81колÑ\8cкими пÑ\80оÑ\86еÑ\81Ñ\81ами и оÑ\81обÑ\8bе Ñ\81лÑ\83Ñ\87аи { #containers-with-multiple-processes-and-special-cases }
-Ð\91езÑ\83Ñ\81ловно, бÑ\8bваÑ\8eÑ\82 **оÑ\81обÑ\8bе Ñ\81лÑ\83Ñ\87аи**, когда можеÑ\82 понадобиÑ\82Ñ\8cÑ\81Ñ\8f внÑ\83Ñ\82Ñ\80и конÑ\82ейнеÑ\80а запÑ\83Ñ\81каÑ\82Ñ\8c **менеджеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81ов Gunicorn**, Ñ\83пÑ\80авлÑ\8fÑ\8eÑ\89ий неÑ\81колÑ\8cкими **пÑ\80оÑ\86еÑ\81Ñ\81ами Uvicorn**.
+Ð\9aонеÑ\87но, еÑ\81Ñ\82Ñ\8c **оÑ\81обÑ\8bе Ñ\81лÑ\83Ñ\87аи**, когда можеÑ\82 понадобиÑ\82Ñ\8cÑ\81Ñ\8f **конÑ\82ейнеÑ\80** Ñ\81 неÑ\81колÑ\8cкими **воÑ\80кеÑ\80ами Uvicorn** внÑ\83Ñ\82Ñ\80и.
-Ð\94лÑ\8f Ñ\82акиÑ\85 Ñ\81лÑ\83Ñ\87аев вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c **оÑ\84иÑ\86иалÑ\8cнÑ\8bй Docker-обÑ\80аз** (пÑ\80им. пеÑ\80: - *здеÑ\81Ñ\8c и далее на Ñ\8dÑ\82ой Ñ\81Ñ\82Ñ\80аниÑ\86е, еÑ\81ли вÑ\8b вÑ\81Ñ\82Ñ\80еÑ\82иÑ\82е Ñ\81оÑ\87еÑ\82ание "оÑ\84иÑ\86иалÑ\8cнÑ\8bй Docker-обÑ\80аз" без Ñ\83Ñ\82оÑ\87нений, Ñ\82о авÑ\82оÑ\80 имееÑ\82 в видÑ\83 именно пÑ\80едоÑ\81Ñ\82авлÑ\8fемÑ\8bй им обÑ\80аз*), где в каÑ\87еÑ\81Ñ\82ве менеджеÑ\80а пÑ\80оÑ\86еÑ\81Ñ\81ов иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f **Gunicorn**, запÑ\83Ñ\81каÑ\8eÑ\89ий неÑ\81колÑ\8cко **пÑ\80оÑ\86еÑ\81Ñ\81ов Uvicorn** и некоÑ\82оÑ\80Ñ\8bе наÑ\81Ñ\82Ñ\80ойки по Ñ\83молÑ\87аниÑ\8e, авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\83Ñ\81Ñ\82анавливаÑ\8eÑ\89ие колиÑ\87еÑ\81Ñ\82во запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов в завиÑ\81имоÑ\81Ñ\82и оÑ\82 колиÑ\87еÑ\81Ñ\82ва Ñ\8fдеÑ\80 ваÑ\88его пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а. Я Ñ\80аÑ\81Ñ\81кажÑ\83 вам об Ñ\8dÑ\82ом подÑ\80обнее Ñ\82Ñ\83Ñ\82: [Ð\9eÑ\84иÑ\86иалÑ\8cнÑ\8bй Docker-обÑ\80аз Ñ\81о вÑ\81Ñ\82Ñ\80оеннÑ\8bми Gunicorn и Uvicorn](#docker-gunicorn-uvicorn).
+Ð\92 Ñ\82акиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c опÑ\86иÑ\8e командной Ñ\81Ñ\82Ñ\80оки `--workers`, Ñ\87Ñ\82обÑ\8b Ñ\83казаÑ\82Ñ\8c нÑ\83жное колиÑ\87еÑ\81Ñ\82во воÑ\80кеÑ\80ов:
-Некоторые примеры подобных случаев:
+```{ .dockerfile .annotate }
+FROM python:3.9
-#### Простое приложение
+WORKDIR /code
-Вы можете использовать менеджер процессов внутри контейнера, если ваше приложение **настолько простое**, что у вас нет необходимости (по крайней мере, пока нет) в тщательных настройках количества процессов и вам достаточно имеющихся настроек по умолчанию (если используется официальный Docker-образ) для запуска приложения **только на одном сервере**, а не в кластере.
+COPY ./requirements.txt /code/requirements.txt
-#### Docker Compose
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-С помощью **Docker Compose** можно разворачивать несколько контейнеров на **одном сервере** (не кластере), но при это у вас не будет простого способа управления количеством запущенных контейнеров с одновременным сохранением общей сети и **балансировки нагрузки**.
+COPY ./app /code/app
-В этом случае можно использовать **менеджер процессов**, управляющий **несколькими процессами**, внутри **одного контейнера**.
+# (1)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
+```
-#### Prometheus и прочие причины
+1. Здесь мы используем опцию `--workers`, чтобы установить число воркеров равным 4.
-У ваÑ\81 могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c и **дÑ\80Ñ\83гие пÑ\80иÑ\87инÑ\8b**, когда иÑ\81полÑ\8cзование **множеÑ\81Ñ\82ва пÑ\80оÑ\86еÑ\81Ñ\81ов** внÑ\83Ñ\82Ñ\80и **одного конÑ\82ейнеÑ\80а** бÑ\83деÑ\82 пÑ\80оÑ\89е, нежели запÑ\83Ñ\81к **неÑ\81колÑ\8cкиÑ\85 конÑ\82ейнеÑ\80ов** Ñ\81 **единÑ\81Ñ\82веннÑ\8bм пÑ\80оÑ\86еÑ\81Ñ\81ом** в каждом из ниÑ\85.
+Ð\9fÑ\80имеÑ\80Ñ\8b, когда Ñ\8dÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\83меÑ\81Ñ\82но:
-Например (в зависимости от конфигурации), у вас могут быть инструменты подобные экспортёру Prometheus, которые должны иметь доступ к **каждому запросу** приходящему в контейнер.
+#### Простое приложение { #a-simple-app }
-Ð\95Ñ\81ли Ñ\83 ваÑ\81 бÑ\83деÑ\82 **неÑ\81колÑ\8cко конÑ\82ейнеÑ\80ов**, Ñ\82о Prometheus, по Ñ\83молÑ\87аниÑ\8e, **пÑ\80и Ñ\81боÑ\80е меÑ\82Ñ\80ик** полÑ\83Ñ\87иÑ\82 иÑ\85 **Ñ\82олÑ\8cко Ñ\81 одного конÑ\82ейнеÑ\80а**, коÑ\82оÑ\80Ñ\8bй обÑ\80абаÑ\82Ñ\8bваеÑ\82 конкÑ\80еÑ\82нÑ\8bй запÑ\80оÑ\81, вмеÑ\81Ñ\82о **Ñ\81боÑ\80а меÑ\82Ñ\80ик** Ñ\81о вÑ\81еÑ\85 Ñ\80абоÑ\82аÑ\8eÑ\89иÑ\85 конÑ\82ейнеÑ\80ов.
+Ð\92ам можеÑ\82 понадобиÑ\82Ñ\8cÑ\81Ñ\8f менеджеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81ов в конÑ\82ейнеÑ\80е, еÑ\81ли пÑ\80иложение **доÑ\81Ñ\82аÑ\82оÑ\87но пÑ\80оÑ\81Ñ\82ое**, Ñ\87Ñ\82обÑ\8b запÑ\83Ñ\81каÑ\82Ñ\8cÑ\81Ñ\8f на **одном Ñ\81еÑ\80веÑ\80е**, а не в клаÑ\81Ñ\82еÑ\80е.
-В таком случае может быть проще иметь **один контейнер** со **множеством процессов**, с нужным инструментом (таким как экспортёр Prometheus) в этом же контейнере и собирающем метрики со всех внутренних процессов этого контейнера.
+#### Docker Compose { #docker-compose }
+
+Вы можете развёртывать на **одном сервере** (не кластере) с **Docker Compose**, и у вас не будет простого способа управлять репликацией контейнеров (в Docker Compose), сохраняя общую сеть и **балансировку нагрузки**.
+
+Тогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркеров** внутри.
---
-Самое главное - **ни одно** из пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 пÑ\80авил не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f **вÑ\8bÑ\81еÑ\87еннÑ\8bм на камне** и вÑ\8b не обÑ\8fзанÑ\8b Ñ\81лепо иÑ\85 повÑ\82оÑ\80Ñ\8fÑ\82Ñ\8c. вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82и идеи пÑ\80и **Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80ении ваÑ\88его конкÑ\80еÑ\82ного Ñ\81лÑ\83Ñ\87аÑ\8f** и Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно Ñ\80еÑ\88аÑ\82Ñ\8c, какаÑ\8f из конÑ\86епÑ\86ии подÑ\85одиÑ\82 лÑ\83Ñ\87Ñ\88е:
+Ð\93лавное â\80\94 **ни одно** из Ñ\8dÑ\82иÑ\85 пÑ\80авил не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f **Ñ\81Ñ\82Ñ\80ого обÑ\8fзаÑ\82елÑ\8cнÑ\8bм**. Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е Ñ\8dÑ\82и идеи, Ñ\87Ñ\82обÑ\8b **оÑ\86ениÑ\82Ñ\8c Ñ\81вой конкÑ\80еÑ\82нÑ\8bй Ñ\81лÑ\83Ñ\87ай** и Ñ\80еÑ\88иÑ\82Ñ\8c, какой подÑ\85од лÑ\83Ñ\87Ñ\88е длÑ\8f ваÑ\88ей Ñ\81иÑ\81Ñ\82емÑ\8b, Ñ\83Ñ\87иÑ\82Ñ\8bваÑ\8f:
-* Ð\98Ñ\81полÑ\8cзование более безопаÑ\81ного пÑ\80оÑ\82окола HTTPS
-* Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка пÑ\80иложениÑ\8f
-* Ð\9fеÑ\80езагÑ\80Ñ\83зка пÑ\80иложениÑ\8f
-* Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f
-* УпÑ\80авление памÑ\8fÑ\82Ñ\8cÑ\8e
-* Ð\98Ñ\81полÑ\8cзование пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий пеÑ\80ед запÑ\83Ñ\81ком пÑ\80иложениÑ\8f
+* Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c â\80\94 HTTPS
+* Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е
+* Ð\9fеÑ\80езапÑ\83Ñ\81ки
+* РепликаÑ\86иÑ\8e (колиÑ\87еÑ\81Ñ\82во запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов)
+* Ð\9fамÑ\8fÑ\82Ñ\8c
+* Ð\9fÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком
-## УпÑ\80авление памÑ\8fÑ\82Ñ\8cÑ\8e
+## Ð\9fамÑ\8fÑ\82Ñ\8c { #memory }
-Ð\9fÑ\80и **запÑ\83Ñ\81ке одного пÑ\80оÑ\86еÑ\81Ñ\81а на конÑ\82ейнеÑ\80** вÑ\8b полÑ\83Ñ\87аеÑ\82е оÑ\82ноÑ\81иÑ\82елÑ\8cно понÑ\8fÑ\82нÑ\8bй, Ñ\81Ñ\82абилÑ\8cнÑ\8bй и огÑ\80аниÑ\87еннÑ\8bй обÑ\8aÑ\91м памÑ\8fÑ\82и, поÑ\82Ñ\80еблÑ\8fемÑ\8bй одним конÑ\82ейнеÑ\80ом.
+Ð\95Ñ\81ли вÑ\8b запÑ\83Ñ\81каеÑ\82е **один пÑ\80оÑ\86еÑ\81Ñ\81 на конÑ\82ейнеÑ\80**, Ñ\83 каждого конÑ\82ейнеÑ\80а бÑ\83деÑ\82 более-менее Ñ\87Ñ\91Ñ\82ко опÑ\80еделÑ\91ннÑ\8bй, Ñ\81Ñ\82абилÑ\8cнÑ\8bй и огÑ\80аниÑ\87еннÑ\8bй обÑ\8aÑ\91м поÑ\82Ñ\80еблÑ\8fемой памÑ\8fÑ\82и (конÑ\82ейнеÑ\80ов можеÑ\82 бÑ\8bÑ\82Ñ\8c неÑ\81колÑ\8cко пÑ\80и Ñ\80епликаÑ\86ии).
-Ð\92Ñ\8b можеÑ\82е Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c аналогиÑ\87нÑ\8bе огÑ\80аниÑ\87ениÑ\8f по памÑ\8fÑ\82и пÑ\80и конÑ\84игÑ\83Ñ\80иÑ\80овании Ñ\81воей Ñ\81иÑ\81Ñ\82емÑ\8b Ñ\83пÑ\80авлениÑ\8f конÑ\82ейнеÑ\80ами (напÑ\80имеÑ\80, **Kubernetes**). Таким обÑ\80азом Ñ\81иÑ\81Ñ\82ема Ñ\81можеÑ\82 **изменÑ\8fÑ\82Ñ\8c колиÑ\87еÑ\81Ñ\82во конÑ\82ейнеÑ\80ов** на **доÑ\81Ñ\82Ñ\83пнÑ\8bÑ\85 ей маÑ\88инаÑ\85** пÑ\80иводÑ\8f в Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вие колиÑ\87еÑ\81Ñ\82во памÑ\8fÑ\82и нÑ\83жной конÑ\82ейнеÑ\80ам Ñ\81 колиÑ\87еÑ\81Ñ\82вом памÑ\8fÑ\82и доÑ\81Ñ\82Ñ\83пной в клаÑ\81Ñ\82еÑ\80е (набоÑ\80е доÑ\81Ñ\82Ñ\83пнÑ\8bÑ\85 маÑ\88ин).
+Ð\97аÑ\82ем вÑ\8b можеÑ\82е задаÑ\82Ñ\8c Ñ\82акие же лимиÑ\82Ñ\8b и Ñ\82Ñ\80ебованиÑ\8f по памÑ\8fÑ\82и в конÑ\84игÑ\83Ñ\80аÑ\86ии ваÑ\88ей Ñ\81иÑ\81Ñ\82емÑ\8b Ñ\83пÑ\80авлениÑ\8f конÑ\82ейнеÑ\80ами (напÑ\80имеÑ\80, в **Kubernetes**). Так Ñ\81иÑ\81Ñ\82ема Ñ\81можеÑ\82 **Ñ\80еплиÑ\86иÑ\80оваÑ\82Ñ\8c конÑ\82ейнеÑ\80Ñ\8b** на **доÑ\81Ñ\82Ñ\83пнÑ\8bÑ\85 маÑ\88инаÑ\85**, Ñ\83Ñ\87иÑ\82Ñ\8bваÑ\8f обÑ\8aÑ\91м необÑ\85одимой памÑ\8fÑ\82и и доÑ\81Ñ\82Ñ\83пной памÑ\8fÑ\82и в маÑ\88инаÑ\85 клаÑ\81Ñ\82еÑ\80а.
-Если у вас **простенькое** приложение, вероятно у вас не будет **необходимости** устанавливать жёсткие ограничения на выделяемую ему память. Но если приложение **использует много памяти** (например, оно использует модели **машинного обучения**), вам следует проверить, как много памяти ему требуется и отрегулировать **количество контейнеров** запущенных на **каждой машине** (может быть даже добавить машин в кластер).
+Если приложение **простое**, это, вероятно, **не будет проблемой**, и жёсткие лимиты памяти можно не указывать. Но если вы **используете много памяти** (например, с моделями **Машинного обучения**), проверьте, сколько памяти потребляется, и отрегулируйте **число контейнеров** на **каждой машине** (и, возможно, добавьте машины в кластер).
-Если вы запускаете **несколько процессов в контейнере**, то должны быть уверены, что эти процессы не **займут памяти больше**, чем доступно для контейнера.
+Если вы запускаете **несколько процессов в контейнере**, нужно убедиться, что их суммарное потребление **не превысит доступную память**.
-## Подготовительные шаги при запуске контейнеров
+## Предварительные шаги перед запуском и контейнеры { #previous-steps-before-starting-and-containers }
-Есть два основных подхода, которые вы можете использовать при запуске контейнеров (Docker, Kubernetes и т.п.).
+Если вы используете контейнеры (например, Docker, Kubernetes), есть два основных подхода.
-### Ð\9cножеÑ\81Ñ\82во конÑ\82ейнеÑ\80ов
+### Ð\9dеÑ\81колÑ\8cко конÑ\82ейнеÑ\80ов { #multiple-containers }
-Ð\9aогда вÑ\8b запÑ\83Ñ\81каеÑ\82е **множеÑ\81Ñ\82во конÑ\82ейнеÑ\80ов**, в каждом из коÑ\82оÑ\80Ñ\8bÑ\85 Ñ\80абоÑ\82аеÑ\82 **Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81** (напÑ\80имеÑ\80, в клаÑ\81Ñ\82еÑ\80е **Kubernetes**), можеÑ\82 возникнÑ\83Ñ\82Ñ\8c необÑ\85одимоÑ\81Ñ\82Ñ\8c имеÑ\82Ñ\8c **оÑ\82делÑ\8cнÑ\8bй конÑ\82ейнеÑ\80**, коÑ\82оÑ\80Ñ\8bй оÑ\81Ñ\83Ñ\89еÑ\81Ñ\82виÑ\82 **пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком** оÑ\81Ñ\82алÑ\8cнÑ\8bÑ\85 конÑ\82ейнеÑ\80ов (напÑ\80имеÑ\80, пÑ\80именÑ\8fеÑ\82 мигÑ\80аÑ\86ии к базе даннÑ\8bÑ\85).
+Ð\95Ñ\81ли Ñ\83 ваÑ\81 **неÑ\81колÑ\8cко конÑ\82ейнеÑ\80ов**, и, веÑ\80оÑ\8fÑ\82но, каждÑ\8bй запÑ\83Ñ\81каеÑ\82 **один пÑ\80оÑ\86еÑ\81Ñ\81** (напÑ\80имеÑ\80, в клаÑ\81Ñ\82еÑ\80е **Kubernetes**), Ñ\82о вÑ\8b, Ñ\81коÑ\80ее вÑ\81его, заÑ\85оÑ\82иÑ\82е имеÑ\82Ñ\8c **оÑ\82делÑ\8cнÑ\8bй конÑ\82ейнеÑ\80**, вÑ\8bполнÑ\8fÑ\8eÑ\89ий **пÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги** в одном конÑ\82ейнеÑ\80е и одном пÑ\80оÑ\86еÑ\81Ñ\81е **до** запÑ\83Ñ\81ка Ñ\80еплиÑ\86иÑ\80ованнÑ\8bÑ\85 конÑ\82ейнеÑ\80ов-воÑ\80кеÑ\80ов.
/// info | Информация
-Ð\9fÑ\80и иÑ\81полÑ\8cзовании Kubernetes, Ñ\8dÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Ð\98ниÑ\86иализиÑ\80Ñ\83Ñ\8eÑ\89ий конÑ\82ейнеÑ\80</a>.
+Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Kubernetes, Ñ\8dÑ\82о, веÑ\80оÑ\8fÑ\82но, бÑ\83деÑ\82 <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
///
-При отсутствии такой необходимости (допустим, не нужно применять миграции к базе данных, а только проверить, что она готова принимать соединения), вы можете проводить такую проверку в каждом контейнере перед запуском его основного процесса и запускать все контейнеры **одновременно**.
-
-### Только один контейнер
-
-Если у вас несложное приложение для работы которого достаточно **одного контейнера**, но в котором работает **несколько процессов** (или один процесс), то прохождение предварительных шагов можно осуществить в этом же контейнере до запуска основного процесса. Официальный Docker-образ поддерживает такие действия.
+Если в вашем случае нет проблемы с тем, чтобы выполнять эти предварительные шаги **многократно и параллельно** (например, вы не запускаете миграции БД, а только проверяете готовность БД), вы можете просто выполнить их в каждом контейнере прямо перед стартом основного процесса.
-## Официальный Docker-образ с Gunicorn и Uvicorn
+### Один контейнер { #single-container }
-Я подгоÑ\82овил длÑ\8f ваÑ\81 Docker-обÑ\80аз, в коÑ\82оÑ\80Ñ\8bй вклÑ\8eÑ\87Ñ\91н Gunicorn Ñ\83пÑ\80авлÑ\8fÑ\8eÑ\89ий пÑ\80оÑ\86еÑ\81Ñ\81ами (воÑ\80кеÑ\80ами) Uvicorn, в Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вии Ñ\81 конÑ\86епÑ\86иÑ\8fми Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80еннÑ\8bми в пÑ\80едÑ\8bдÑ\83Ñ\89ей главе: [РабоÑ\87ие пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b Ñ\81еÑ\80веÑ\80а (воÑ\80кеÑ\80Ñ\8b) - Gunicorn Ñ\81овмеÑ\81Ñ\82но Ñ\81 Uvicorn](server-workers.md){.internal-link target=_blank}.
+Ð\95Ñ\81ли Ñ\83 ваÑ\81 пÑ\80оÑ\81Ñ\82аÑ\8f Ñ\81Ñ\85ема Ñ\81 **одним конÑ\82ейнеÑ\80ом**, коÑ\82оÑ\80Ñ\8bй заÑ\82ем запÑ\83Ñ\81каеÑ\82 неÑ\81колÑ\8cко **воÑ\80кеÑ\80ов** (или один пÑ\80оÑ\86еÑ\81Ñ\81), можно вÑ\8bполниÑ\82Ñ\8c подгоÑ\82овиÑ\82елÑ\8cнÑ\8bе Ñ\88аги в Ñ\8dÑ\82ом же конÑ\82ейнеÑ\80е непоÑ\81Ñ\80едÑ\81Ñ\82венно пеÑ\80ед запÑ\83Ñ\81ком пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 пÑ\80иложением.
-Этот образ может быть полезен для ситуаций описанных тут: [Множество процессов внутри контейнера для особых случаев](#_11).
-
-* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
-
-/// warning | Предупреждение
+### Базовый Docker-образ { #base-docker-image }
-СкоÑ\80ее вÑ\81его Ñ\83 ваÑ\81 **неÑ\82 необÑ\85одимоÑ\81Ñ\82и** в иÑ\81полÑ\8cзовании Ñ\8dÑ\82ого обÑ\80аза или подобного емÑ\83 и лÑ\83Ñ\87Ñ\88е Ñ\81оздаÑ\82Ñ\8c Ñ\81вой обÑ\80аз Ñ\81 нÑ\83лÑ\8f как опиÑ\81ано Ñ\82Ñ\83Ñ\82: [СоздаÑ\82Ñ\8c Docker-обÑ\80аз длÑ\8f FastAPI](#docker-fastapi).
+Ранее Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вовал оÑ\84иÑ\86иалÑ\8cнÑ\8bй Docker-обÑ\80аз FastAPI: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. СейÑ\87аÑ\81 он помеÑ\87ен как Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ий. â\9b\94ï¸\8f
-///
+Скорее всего, вам **не стоит** использовать этот базовый образ (или какой-либо аналогичный).
-Ð\92 Ñ\8dÑ\82ом обÑ\80азе еÑ\81Ñ\82Ñ\8c **авÑ\82омаÑ\82иÑ\87еÑ\81кий** меÑ\85анизм подÑ\81Ñ\82Ñ\80ойки длÑ\8f запÑ\83Ñ\81ка **необÑ\85одимого колиÑ\87еÑ\81Ñ\82ва пÑ\80оÑ\86еÑ\81Ñ\81ов** в Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вии Ñ\81 доÑ\81Ñ\82Ñ\83пнÑ\8bм колиÑ\87еÑ\81Ñ\82вом Ñ\8fдеÑ\80 пÑ\80оÑ\86еÑ\81Ñ\81оÑ\80а.
+Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е **Kubernetes** (или дÑ\80Ñ\83гое) и Ñ\83же наÑ\81Ñ\82Ñ\80аиваеÑ\82е **Ñ\80епликаÑ\86иÑ\8e** на Ñ\83Ñ\80овне клаÑ\81Ñ\82еÑ\80а Ñ\87еÑ\80ез неÑ\81колÑ\8cко **конÑ\82ейнеÑ\80ов**, в Ñ\8dÑ\82иÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 лÑ\83Ñ\87Ñ\88е **Ñ\81обÑ\80аÑ\82Ñ\8c обÑ\80аз Ñ\81 нÑ\83лÑ\8f**, как опиÑ\81ано вÑ\8bÑ\88е: [СоздаÑ\82Ñ\8c Docker-обÑ\80аз длÑ\8f FastAPI](#build-a-docker-image-for-fastapi).
-Ð\92 нÑ\91м Ñ\83Ñ\81Ñ\82ановленÑ\8b **Ñ\80азÑ\83мнÑ\8bе знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e**, но можно изменÑ\8fÑ\82Ñ\8c и обновлÑ\8fÑ\82Ñ\8c конÑ\84игÑ\83Ñ\80аÑ\86иÑ\8e Ñ\81 помоÑ\89Ñ\8cÑ\8e **пеÑ\80еменнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8f** или конÑ\84игÑ\83Ñ\80аÑ\86ионнÑ\8bÑ\85 Ñ\84айлов.
+Ð\90 еÑ\81ли вам нÑ\83жнÑ\8b неÑ\81колÑ\8cко воÑ\80кеÑ\80ов, пÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83йÑ\82е опÑ\86иÑ\8e командной Ñ\81Ñ\82Ñ\80оки `--workers`.
-Он также поддерживает прохождение <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**Подготовительных шагов при запуске контейнеров**</a> при помощи скрипта.
+/// note | Технические подробности
-/// tip | Подсказка
+Этот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркеров Uvicorn.
-Ð\94лÑ\8f пÑ\80оÑ\81моÑ\82Ñ\80а вÑ\81еÑ\85 возможнÑ\8bÑ\85 наÑ\81Ñ\82Ñ\80оек пеÑ\80ейдиÑ\82е на Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83 Ñ\8dÑ\82ого Docker-обÑ\80аза: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
+Ð\9dо Ñ\82епеÑ\80Ñ\8c, когда Uvicorn (и команда `fastapi`) поддеÑ\80живаÑ\8eÑ\82 `--workers`, неÑ\82 пÑ\80иÑ\87ин иÑ\81полÑ\8cзоваÑ\82Ñ\8c базовÑ\8bй Docker-обÑ\80аз вмеÑ\81Ñ\82о Ñ\81боÑ\80ки Ñ\81воего (кода полÑ\83Ñ\87аеÑ\82Ñ\81Ñ\8f пÑ\80имеÑ\80но Ñ\81Ñ\82олÑ\8cко же ð\9f\98\85).
///
-### Количество процессов в официальном Docker-образе
-
-**Количество процессов** в этом образе **вычисляется автоматически** и зависит от доступного количества **ядер** центрального процессора.
-
-Это означает, что он будет пытаться **выжать** из процессора как можно больше **производительности**.
-
-Но вы можете изменять и обновлять конфигурацию с помощью **переменных окружения** и т.п.
-
-Поскольку количество процессов зависит от процессора, на котором работает контейнер, **объём потребляемой памяти** также будет зависеть от этого.
-
-А значит, если вашему приложению требуется много оперативной памяти (например, оно использует модели машинного обучения) и Ваш сервер имеет центральный процессор с большим количеством ядер, но **не слишком большим объёмом оперативной памяти**, то может дойти до того, что контейнер попытается занять памяти больше, чем доступно, из-за чего будет падение производительности (или сервер вовсе упадёт). 🚨
-
-
-### Написание `Dockerfile`
-
-Итак, теперь мы можем написать `Dockerfile` основанный на этом официальном Docker-образе:
-
-```Dockerfile
-FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
-
-COPY ./requirements.txt /app/requirements.txt
-
-RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
-
-COPY ./app /app
-```
-
-### Большие приложения
-
-Если вы успели ознакомиться с разделом [Приложения содержащие много файлов](../tutorial/bigger-applications.md){.internal-link target=_blank}, состоящие из множества файлов, Ваш Dockerfile может выглядеть так:
-
-```Dockerfile hl_lines="7"
-FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
-
-COPY ./requirements.txt /app/requirements.txt
+## Развёртывание образа контейнера { #deploy-the-container-image }
-RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
-
-COPY ./app /app/app
-```
-
-### Как им пользоваться
-
-Если вы используете **Kubernetes** (или что-то вроде того), скорее всего вам **не нужно** использовать официальный Docker-образ (или другой похожий) в качестве основы, так как управление **количеством запущенных контейнеров** должно быть настроено на уровне кластера. В таком случае лучше **создать образ с нуля**, как описано в разделе Создать [Docker-образ для FastAPI](#docker-fastapi).
-
-Официальный образ может быть полезен в отдельных случаях, описанных выше в разделе [Множество процессов внутри контейнера для особых случаев](#_11). Например, если ваше приложение **достаточно простое**, не требует запуска в кластере и способно уместиться в один контейнер, то его настройки по умолчанию будут работать довольно хорошо. Или же вы развертываете его с помощью **Docker Compose**, работаете на одном сервере и т. д
-
-## Развёртывание образа контейнера
-
-После создания образа контейнера существует несколько способов его развёртывания.
+После того как у вас есть образ контейнера (Docker), его можно развёртывать несколькими способами.
Например:
-* С использованием **Docker Compose** при развёртывании на одном сервере
-* С использованием **Kubernetes** в кластере
-* С использованием режима Docker Swarm в кластере
-* С использованием других инструментов, таких как Nomad
-* С использованием облачного сервиса, который будет управлять разворачиванием вашего контейнера
-
-## Docker-образ и Poetry
-
-Если вы пользуетесь <a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a> для управления зависимостями вашего проекта, то можете использовать многоэтапную сборку образа:
-
-```{ .dockerfile .annotate }
-# (1)
-FROM python:3.9 as requirements-stage
-
-# (2)
-WORKDIR /tmp
-
-# (3)
-RUN pip install poetry
-
-# (4)
-COPY ./pyproject.toml ./poetry.lock* /tmp/
-
-# (5)
-RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
-
-# (6)
-FROM python:3.9
-
-# (7)
-WORKDIR /code
-
-# (8)
-COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
-
-# (9)
-RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-
-# (10)
-COPY ./app /code/app
-
-# (11)
-CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
-```
-
-1. Это первый этап, которому мы дадим имя `requirements-stage`.
-
-2. Установите директорию `/tmp` в качестве рабочей директории.
+* С **Docker Compose** на одном сервере
+* В кластере **Kubernetes**
+* В кластере Docker Swarm Mode
+* С другим инструментом, например Nomad
+* С облачным сервисом, который принимает ваш образ контейнера и разворачивает его
- В ней будет создан файл `requirements.txt`
-
-3. На этом шаге установите Poetry.
-
-4. Скопируйте файлы `pyproject.toml` и `poetry.lock` в директорию `/tmp`.
-
- Поскольку название файла написано как `./poetry.lock*` (с `*` в конце), то ничего не сломается, если такой файл не будет найден.
-
-5. Создайте файл `requirements.txt`.
-
-6. Это второй (и последний) этап сборки, который и создаст окончательный образ контейнера.
-
-7. Установите директорию `/code` в качестве рабочей.
-
-8. Скопируйте файл `requirements.txt` в директорию `/code`.
-
- Этот файл находится в образе, созданном на предыдущем этапе, которому мы дали имя requirements-stage, потому при копировании нужно написать `--from-requirements-stage`.
-
-9. Установите зависимости, указанные в файле `requirements.txt`.
-
-10. Скопируйте папку `app` в папку `/code`.
-
-11. Запустите `uvicorn`, указав ему использовать объект `app`, расположенный в `app.main`.
-
-/// tip | Подсказка
-
-Если ткнёте на кружок с плюсом, то увидите объяснения, что происходит в этой строке.
-
-///
-
-**Этапы сборки Docker-образа** являются частью `Dockerfile` и работают как **временные образы контейнеров**. Они нужны только для создания файлов, используемых в дальнейших этапах.
-
-Первый этап был нужен только для **установки Poetry** и **создания файла `requirements.txt`**, в которым прописаны зависимости вашего проекта, взятые из файла `pyproject.toml`.
-
-На **следующем этапе** `pip` будет использовать файл `requirements.txt`.
-
-В итоговом образе будет содержаться **только последний этап сборки**, предыдущие этапы будут отброшены.
-
-При использовании Poetry, имеет смысл использовать **многоэтапную сборку Docker-образа**, потому что на самом деле вам не нужен Poetry и его зависимости в окончательном образе контейнера, вам **нужен только** сгенерированный файл `requirements.txt` для установки зависимостей вашего проекта.
-
-А на последнем этапе, придерживаясь описанных ранее правил, создаётся итоговый образ
-
-### Использование прокси-сервера завершения TLS и Poetry
-
-И снова повторюсь, если используете прокси-сервер (балансировщик нагрузки), такой как Nginx или Traefik, добавьте в команду запуска опцию `--proxy-headers`:
-
-```Dockerfile
-CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
-```
+## Docker-образ с `uv` { #docker-image-with-uv }
-## Резюме
+Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> для установки и управления проектом, следуйте их <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">руководству по Docker для uv</a>.
-При помощи систем контейнеризации (таких, как **Docker** и **Kubernetes**), становится довольно просто обрабатывать все **концепции развертывания**:
+## Резюме { #recap }
-* Использование более безопасного протокола HTTPS
-* Настройки запуска приложения
-* Перезагрузка приложения
-* Запуск нескольких экземпляров приложения
-* Управление памятью
-* Использование перечисленных функций перед запуском приложения
+Используя системы контейнеризации (например, **Docker** и **Kubernetes**), довольно просто закрыть все **концепции развертывания**:
-В большинстве случаев Вам, вероятно, не нужно использовать какой-либо базовый образ, **лучше создать образ контейнера с нуля** на основе официального Docker-образа Python.
+* HTTPS
+* Запуск при старте
+* Перезапуски
+* Репликация (количество запущенных процессов)
+* Память
+* Предварительные шаги перед запуском
-Ð\9fозабоÑ\82ивÑ\88иÑ\81Ñ\8c о **поÑ\80Ñ\8fдке напиÑ\81аниÑ\8f** инÑ\81Ñ\82Ñ\80Ñ\83кÑ\86ий в `Dockerfile`, вÑ\8b Ñ\81можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c **кÑ\8dÑ\88 Docker'а**, **минимизиÑ\80овав вÑ\80емÑ\8f Ñ\81боÑ\80ки**, макÑ\81ималÑ\8cно повÑ\8bÑ\81ив Ñ\81воÑ\8e пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (и не заÑ\81кÑ\83Ñ\87аÑ\82Ñ\8c). ð\9f\98\8e
+Ð\92 болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев вÑ\8b, веÑ\80оÑ\8fÑ\82но, не заÑ\85оÑ\82иÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c какой-либо базовÑ\8bй обÑ\80аз, а вмеÑ\81Ñ\82о Ñ\8dÑ\82ого **Ñ\81обеÑ\80Ñ\91Ñ\82е обÑ\80аз конÑ\82ейнеÑ\80а Ñ\81 нÑ\83лÑ\8f** на оÑ\81нове оÑ\84иÑ\86иалÑ\8cного Docker-обÑ\80аза Python.
-Ð\92 некоÑ\82оÑ\80Ñ\8bÑ\85 оÑ\81обÑ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c оÑ\84иÑ\86иалÑ\8cнÑ\8bй обÑ\80аз Docker длÑ\8f FastAPI. ð\9f¤\93
+Ð\97абоÑ\82Ñ\8fÑ\81Ñ\8c о **поÑ\80Ñ\8fдке** инÑ\81Ñ\82Ñ\80Ñ\83кÑ\86ий в `Dockerfile`и иÑ\81полÑ\8cзÑ\83Ñ\8f **кÑ\8dÑ\88 Docker**, вÑ\8b можеÑ\82е **минимизиÑ\80оваÑ\82Ñ\8c вÑ\80емÑ\8f Ñ\81боÑ\80ки**, Ñ\87Ñ\82обÑ\8b повÑ\8bÑ\81иÑ\82Ñ\8c пÑ\80одÑ\83кÑ\82ивноÑ\81Ñ\82Ñ\8c (и не Ñ\81кÑ\83Ñ\87аÑ\82Ñ\8c). ð\9f\98\8e
-# Об HTTPS
+# Об HTTPS { #about-https }
-Ð\9eбÑ\8bÑ\87но пÑ\80едÑ\81Ñ\82авлÑ\8fеÑ\82Ñ\81Ñ\8f, Ñ\87Ñ\82о HTTPS Ñ\8dÑ\82о некаÑ\8f опÑ\86иÑ\8f, коÑ\82оÑ\80аÑ\8f либо "вклÑ\8eÑ\87ена", либо нет.
+Ð\9bегко пÑ\80едположиÑ\82Ñ\8c, Ñ\87Ñ\82о HTTPS â\80\94 Ñ\8dÑ\82о Ñ\87Ñ\82о-Ñ\82о, Ñ\87Ñ\82о пÑ\80оÑ\81Ñ\82о «вклÑ\8eÑ\87ено» или нет.
-Ð\9dо вÑ\81Ñ\91 неÑ\81колÑ\8cко сложнее.
+Ð\9dо на Ñ\81амом деле вÑ\81Ñ\91 гоÑ\80аздо сложнее.
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-Если вы торопитесь или вам не интересно, можете перейти на следующую страницу этого пошагового руководства по размещению приложений на серверах с использованием различных технологий.
+Если вы торопитесь или вам это не важно, переходите к следующим разделам с пошаговыми инструкциями по настройке всего разными способами.
///
-Чтобы **изучить основы HTTPS** для клиента, перейдите по ссылке <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
-
-Здесь же представлены некоторые концепции, которые **разработчик** должен иметь в виду при размышлениях об HTTPS:
-
-* Протокол HTTPS предполагает, что **серверу** нужно **располагать "сертификатами"** сгенерированными **третьей стороной**.
- * На самом деле эти сертификаты **приобретены** у третьей стороны, а не "сгенерированы".
-* У сертификатов есть **срок годности**.
- * Срок годности **истекает**.
- * По истечении срока годности их нужно **обновить**, то есть **снова получить** у третьей стороны.
-* Шифрование соединения происходит **на уровне протокола TCP**.
- * Протокол TCP находится на один уровень **ниже протокола HTTP**.
- * Поэтому **проверка сертификатов и шифрование** происходит **до HTTP**.
-* **TCP не знает о "доменах"**, но знает об IP-адресах.
- * Информация о **запрашиваемом домене** извлекается из запроса **на уровне HTTP**.
-* **Сертификаты HTTPS** "сертифицируют" **конкретный домен**, но проверка сертификатов и шифрование данных происходит на уровне протокола TCP, то есть **до того**, как станет известен домен-получатель данных.
-* **По умолчанию** это означает, что у вас может быть **только один сертификат HTTPS на один IP-адрес**.
- * Не важно, насколько большой у вас сервер и насколько маленькие приложения на нём могут быть.
- * Однако, у этой проблемы есть **решение**.
-* Существует **расширение** протокола **TLS** (который работает на уровне TCP, то есть до HTTP) называемое **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Указание имени сервера">SNI</abbr></a>**.
- * Расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько сертификатов HTTPS** и обслуживать **множество HTTPS-доменов/приложений**.
- * Чтобы эта конструкция работала, **один** её компонент (программа) запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все сертификаты HTTPS** для этого сервера.
-* **После** установления защищённого соединения, протоколом передачи данных **остаётся HTTP**.
- * Но данные теперь **зашифрованы**, несмотря на то, что они передаются по **протоколу HTTP**.
-
-Обычной практикой является иметь **одну программу/HTTP-сервер** запущенную на сервере (машине, хосте и т.д.) и **ответственную за всю работу с HTTPS**:
-
-* получение **зашифрованных HTTPS-запросов**
-* отправка **расшифрованных HTTP запросов** в соответствующее HTTP-приложение, работающее на том же сервере (в нашем случае, это приложение **FastAPI**)
-* получение **HTTP-ответа** от приложения
-* **шифрование ответа** используя подходящий **сертификат HTTPS**
-* отправка зашифрованного **HTTPS-ответа клиенту**.
-Такой сервер часто называют **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Прокси-сервер завершения работы TLS</a>** или просто "прокси-сервер".
-
-Вот некоторые варианты, которые вы можете использовать в качестве такого прокси-сервера:
-
-* Traefik (может обновлять сертификаты)
-* Caddy (может обновлять сертификаты)
+Чтобы **изучить основы HTTPS** с точки зрения пользователя, загляните на <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
+
+Теперь, со стороны **разработчика**, вот несколько вещей, которые стоит держать в голове, размышляя об HTTPS:
+
+* Для HTTPS **серверу** нужно **иметь «сертификаты»**, сгенерированные **третьей стороной**.
+ * Эти сертификаты на самом деле **приобретаются** у третьей стороны, а не «генерируются».
+* У сертификатов есть **срок действия**.
+ * Они **истекают**.
+ * После этого их нужно **обновлять**, то есть **получать заново** у третьей стороны.
+* Шифрование соединения происходит на **уровне TCP**.
+ * Это на один уровень **ниже HTTP**.
+ * Поэтому **сертификаты и шифрование** обрабатываются **до HTTP**.
+* **TCP не знает о «доменах»**. Только об IP-адресах.
+ * Информация о **конкретном домене** передаётся в **данных HTTP**.
+* **HTTPS-сертификаты** «сертифицируют» **определённый домен**, но протокол и шифрование происходят на уровне TCP, **до того как** становится известен домен, с которым идёт работа.
+* **По умолчанию** это означает, что вы можете иметь **лишь один HTTPS-сертификат на один IP-адрес**.
+ * Неважно, насколько мощный у вас сервер или насколько маленькие приложения на нём работают.
+ * Однако у этого есть **решение**.
+* Есть **расширение** протокола **TLS** (того самого, что занимается шифрованием на уровне TCP, до HTTP) под названием **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication – Указание имени сервера">SNI</abbr></a>**.
+ * Это расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько HTTPS-сертификатов** и обслуживать **несколько HTTPS-доменов/приложений**.
+ * Чтобы это работало, **один** компонент (программа), запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все HTTPS-сертификаты** на этом сервере.
+* **После** установления защищённого соединения, протокол обмена данными — **всё ещё HTTP**.
+ * Содержимое **зашифровано**, несмотря на то, что оно отправляется по **протоколу HTTP**.
+
+Обычно на сервере (машине, хосте и т.п.) запускают **одну программу/HTTP‑сервер**, которая **управляет всей частью, связанной с HTTPS**: принимает **зашифрованные HTTPS-запросы**, отправляет **расшифрованные HTTP-запросы** в само HTTP‑приложение, работающее на том же сервере (в нашем случае это приложение **FastAPI**), получает **HTTP-ответ** от приложения, **шифрует его** с использованием подходящего **HTTPS‑сертификата** и отправляет клиенту по **HTTPS**. Такой сервер часто называют **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">прокси‑сервером TLS-терминации</a>**.
+
+Некоторые варианты, которые вы можете использовать как прокси‑сервер TLS-терминации:
+
+* Traefik (умеет обновлять сертификаты)
+* Caddy (умеет обновлять сертификаты)
* Nginx
* HAProxy
-## Let's Encrypt (центр сертификации)
+## Let's Encrypt { #lets-encrypt }
-До появления Let's Encrypt **сертификаты HTTPS** приходилось покупать у третьих сторон.
+До появления Let's Encrypt эти **HTTPS-сертификаты** продавались доверенными третьими сторонами.
-Ð\9fÑ\80оÑ\86еÑ\81Ñ\81 полÑ\83Ñ\87ениÑ\8f Ñ\82акого Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82а бÑ\8bл Ñ\82Ñ\80Ñ\83доÑ\91мким, Ñ\82Ñ\80ебовал пÑ\80едоÑ\81Ñ\82авлениÑ\8f подÑ\82веÑ\80ждаÑ\8eÑ\89иÑ\85 докÑ\83менÑ\82ов и Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b Ñ\81Ñ\82оили доÑ\80ого.
+Ð\9fÑ\80оÑ\86еÑ\81Ñ\81 полÑ\83Ñ\87ениÑ\8f Ñ\82акиÑ\85 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов бÑ\8bл неÑ\83добнÑ\8bм, Ñ\82Ñ\80ебовал бÑ\83мажной волокиÑ\82Ñ\8b, а Ñ\81ами Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b бÑ\8bли доволÑ\8cно доÑ\80огими.
-Ð\9dо заÑ\82ем конÑ\81оÑ\80Ñ\86иÑ\83мом Linux Foundation бÑ\8bл Ñ\81оздан пÑ\80оекÑ\82 **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>**.
+Ð\97аÑ\82ем поÑ\8fвилÑ\81Ñ\8f **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>**.
-Ð\9eн авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80едоÑ\81Ñ\82авлÑ\8fеÑ\82 **беÑ\81плаÑ\82нÑ\8bе Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b HTTPS**. ÐÑ\82и Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 вÑ\81е Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе кÑ\80ипÑ\82огÑ\80аÑ\84иÑ\87еÑ\81кие Ñ\81поÑ\81обÑ\8b Ñ\88иÑ\84Ñ\80ованиÑ\8f. Ð\9eни имеÑ\8eÑ\82 неболÑ\8cÑ\88ой Ñ\81Ñ\80ок годноÑ\81Ñ\82и (около 3 меÑ\81Ñ\8fÑ\86ев), благодаÑ\80Ñ\8f Ñ\87емÑ\83 они даже **более безопаÑ\81нÑ\8b**.
+ÐÑ\82о пÑ\80оекÑ\82 Linux Foundation. Ð\9eн пÑ\80едоÑ\81Ñ\82авлÑ\8fеÑ\82 **HTTPSâ\80\91Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b беÑ\81плаÑ\82но**, в авÑ\82омаÑ\82иÑ\87еÑ\81ком Ñ\80ежиме. ÐÑ\82и Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе кÑ\80ипÑ\82огÑ\80аÑ\84иÑ\87еÑ\81кие меÑ\85анизмÑ\8b и имеÑ\8eÑ\82 коÑ\80оÑ\82кий Ñ\81Ñ\80ок дейÑ\81Ñ\82виÑ\8f (около 3 меÑ\81Ñ\8fÑ\86ев), поÑ\8dÑ\82омÑ\83 **безопаÑ\81ноÑ\81Ñ\82Ñ\8c Ñ\84акÑ\82иÑ\87еÑ\81ки вÑ\8bÑ\88е** благодаÑ\80Ñ\8f Ñ\83менÑ\8cÑ\88енномÑ\83 Ñ\81Ñ\80окÑ\83 жизни.
-Ð\9fÑ\80и запÑ\80оÑ\81е на полÑ\83Ñ\87ение Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82а, он авÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f и домен пÑ\80овеÑ\80Ñ\8fеÑ\82Ñ\81Ñ\8f на безопаÑ\81ноÑ\81Ñ\82Ñ\8c. ÐÑ\82о позволÑ\8fеÑ\82 обновлÑ\8fÑ\82Ñ\8c Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b авÑ\82омаÑ\82иÑ\87еÑ\81ки.
+Ð\94оменÑ\8b безопаÑ\81но пÑ\80овеÑ\80Ñ\8fÑ\8eÑ\82Ñ\81Ñ\8f, а Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b вÑ\8bдаÑ\8eÑ\82Ñ\81Ñ\8f авÑ\82омаÑ\82иÑ\87еÑ\81ки. ÐÑ\82о Ñ\82акже позволÑ\8fеÑ\82 авÑ\82омаÑ\82изиÑ\80оваÑ\82Ñ\8c пÑ\80оÑ\86еÑ\81Ñ\81 иÑ\85 пÑ\80одлениÑ\8f.
-СÑ\83Ñ\82Ñ\8c идеи в авÑ\82омаÑ\82иÑ\87еÑ\81ком полÑ\83Ñ\87ении и обновлении Ñ\8dÑ\82иÑ\85 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов, Ñ\87Ñ\82обÑ\8b вÑ\81е могли полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f **безопаÑ\81нÑ\8bм HTTPS. Ð\91еÑ\81плаÑ\82но. Ð\92 лÑ\8eбое вÑ\80емÑ\8f.**
+Ð\98деÑ\8f â\80\94 авÑ\82омаÑ\82изиÑ\80оваÑ\82Ñ\8c полÑ\83Ñ\87ение и пÑ\80одление Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов, Ñ\87Ñ\82обÑ\8b Ñ\83 ваÑ\81 бÑ\8bл **безопаÑ\81нÑ\8bй HTTPS, беÑ\81плаÑ\82но и навÑ\81егда**.
-## HTTPS для разработчиков
+## HTTPS для разработчиков { #https-for-developers }
-Ниже, шаг за шагом, с заострением внимания на идеях, важных для разработчика, описано, как может выглядеть HTTPS API.
+Ниже приведён пример того, как может выглядеть HTTPS‑API, шаг за шагом, с акцентом на идеях, важных для разработчиков.
-### Имя домена
+### Имя домена { #domain-name }
-Чаще всего, всё начинается с **приобретения имени домена**. Затем нужно настроить DNS-сервер (вероятно у того же провайдера, который выдал вам домен).
+Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера).
-Ð\94алее, возможно, вÑ\8b полÑ\83Ñ\87аеÑ\82е "облаÑ\87нÑ\8bй" Ñ\81еÑ\80веÑ\80 (виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e маÑ\88инÑ\83) или Ñ\87Ñ\82о-Ñ\82о Ñ\82ипа Ñ\8dÑ\82ого, Ñ\83 коÑ\82оÑ\80ого еÑ\81Ñ\82Ñ\8c <abbr title="Ð\9dе изменÑ\8fемÑ\8bй">постоянный</abbr> **публичный IP-адрес**.
+СкоÑ\80ее вÑ\81его, вÑ\8b полÑ\83Ñ\87иÑ\82е облаÑ\87нÑ\8bй Ñ\81еÑ\80веÑ\80 (виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e маÑ\88инÑ\83) или Ñ\87Ñ\82о-Ñ\82о подобное, и Ñ\83 него бÑ\83деÑ\82 <abbr title="Ð\9dе изменÑ\8fеÑ\82Ñ\81Ñ\8f">постоянный</abbr> **публичный IP-адрес**.
-На DNS-сервере (серверах) вам следует настроить соответствующую ресурсную запись ("`запись A`"), указав, что **Ваш домен** связан с публичным **IP-адресом вашего сервера**.
+На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**.
-Обычно эту запись достаточно указать один раз, при первоначальной настройке всего сервера.
+Обычно это делается один раз — при первоначальной настройке всего.
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-УÑ\80овни пÑ\80оÑ\82околов, Ñ\80абоÑ\82аÑ\8eÑ\89иÑ\85 Ñ\81 именами доменов, намного ниже HTTPS, но об Ñ\8dÑ\82ом Ñ\81ледÑ\83еÑ\82 Ñ\83помÑ\8fнÑ\83Ñ\82Ñ\8c здеÑ\81Ñ\8c, Ñ\82ак как вÑ\81Ñ\91 завиÑ\81иÑ\82 оÑ\82 доменов и IP-адÑ\80еÑ\81ов.
+ЧаÑ\81Ñ\82Ñ\8c пÑ\80о доменное имÑ\8f оÑ\82ноÑ\81иÑ\82Ñ\81Ñ\8f к Ñ\8dÑ\82апам задолго до HTTPS, но Ñ\82ак как вÑ\81Ñ\91 завиÑ\81иÑ\82 оÑ\82 домена и IPâ\80\91адÑ\80еÑ\81а, здеÑ\81Ñ\8c Ñ\81Ñ\82оиÑ\82 Ñ\8dÑ\82о Ñ\83помÑ\8fнÑ\83Ñ\82Ñ\8c.
///
-### DNS
+### DNS { #dns }
-Теперь давайте сфокусируемся на работе с HTTPS.
+Теперь сфокусируемся на собственно частях, связанных с HTTPS.
-Ð\92Ñ\81Ñ\91 наÑ\87инаеÑ\82Ñ\81Ñ\8f Ñ\81 Ñ\82ого, Ñ\87Ñ\82о бÑ\80аÑ\83зеÑ\80 Ñ\81пÑ\80аÑ\88иваеÑ\82 Ñ\83 **DNS-Ñ\81еÑ\80веÑ\80ов**, какой **IP-адÑ\80еÑ\81 Ñ\81вÑ\8fзан Ñ\81 доменом**, длÑ\8f пÑ\80имеÑ\80а возÑ\8cмÑ\91м домен `someapp.example.com`.
+СнаÑ\87ала бÑ\80аÑ\83зеÑ\80 Ñ\81пÑ\80оÑ\81иÑ\82 Ñ\83 **DNSâ\80\91Ñ\81еÑ\80веÑ\80ов**, какой **IP Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83еÑ\82 доменÑ\83**, в наÑ\88ем пÑ\80имеÑ\80е `someapp.example.com`.
-DNS-сервера присылают браузеру определённый **IP-адрес**, тот самый публичный IP-адрес вашего сервера, который вы указали в ресурсной "записи А" при настройке.
+DNS‑серверы ответят браузеру, какой **конкретный IP‑адрес** использовать. Это будет публичный IP‑адрес вашего сервера, который вы указали в настройках DNS.
<img src="/img/deployment/https/https01.drawio.svg">
-### Ð Ñ\83копожаÑ\82ие TLS
+### Ð\9dаÑ\87ало TLS-Ñ\80Ñ\83копожаÑ\82иÑ\8f { #tls-handshake-start }
-Ð\92 далÑ\8cнейÑ\88ем бÑ\80аÑ\83зеÑ\80 бÑ\83деÑ\82 взаимодейÑ\81Ñ\82воваÑ\82Ñ\8c Ñ\81 Ñ\8dÑ\82им IP-адÑ\80еÑ\81ом Ñ\87еÑ\80ез **port 443** (обÑ\89епÑ\80инÑ\8fÑ\82Ñ\8bй номеÑ\80 поÑ\80Ñ\82а длÑ\8f HTTPS).
+Ð\94алее бÑ\80аÑ\83зеÑ\80 бÑ\83деÑ\82 обÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81 Ñ\8dÑ\82им IPâ\80\91адÑ\80еÑ\81ом на **поÑ\80Ñ\82Ñ\83 443** (поÑ\80Ñ\82 HTTPS).
-Первым шагом будет установление соединения между клиентом (браузером) и сервером и выбор криптографического ключа (для шифрования).
+Первая часть взаимодействия — установить соединение между клиентом и сервером и договориться о криптографических ключах и т.п.
<img src="/img/deployment/https/https02.drawio.svg">
-ÐÑ\82а Ñ\87аÑ\81Ñ\82Ñ\8c клиенÑ\82-Ñ\81еÑ\80веÑ\80ного взаимодейÑ\81Ñ\82виÑ\8f Ñ\83Ñ\81Ñ\82анавливаеÑ\82 TLS-Ñ\81оединение и назÑ\8bваеÑ\82Ñ\81Ñ\8f **TLS-рукопожатием**.
+ÐÑ\82о взаимодейÑ\81Ñ\82вие клиенÑ\82а и Ñ\81еÑ\80веÑ\80а длÑ\8f Ñ\83Ñ\81Ñ\82ановлениÑ\8f TLSâ\80\91Ñ\81оединениÑ\8f назÑ\8bваеÑ\82Ñ\81Ñ\8f **TLSâ\80\91рукопожатием**.
-### TLS с расширением SNI
+### TLS с расширением SNI { #tls-with-sni-extension }
-На сервере **только один процесс** может прослушивать определённый **порт** определённого **IP-адреса**. На сервере могут быть и другие процессы, слушающие другие порты этого же IP-адреса, но никакой процесс не может быть привязан к уже занятой комбинации IP-адрес:порт. Эта комбинация называется "сокет".
+На сервере **только один процесс** может слушать конкретный **порт** на конкретном **IP‑адресе**. Могут быть другие процессы, слушающие другие порты на том же IP‑адресе, но не более одного процесса на каждую комбинацию IP‑адреса и порта.
-Ð\9fо Ñ\83молÑ\87аниÑ\8e TLS (HTTPS) иÑ\81полÑ\8cзÑ\83еÑ\82 поÑ\80Ñ\82 `443`. Ð\9fоÑ\82омÑ\83 Ñ\8dÑ\82оÑ\82 же поÑ\80Ñ\82 бÑ\83дем иÑ\81полÑ\8cзоваÑ\82Ñ\8c и мÑ\8b.
+Ð\9fо Ñ\83молÑ\87аниÑ\8e TLS (HTTPS) иÑ\81полÑ\8cзÑ\83еÑ\82 поÑ\80Ñ\82 `443`. Ð\97наÑ\87иÑ\82, он нам и нÑ\83жен.
-Ð\98 Ñ\80аз Ñ\83ж Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 Ñ\81лÑ\83Ñ\88аÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 поÑ\80Ñ\82, Ñ\82о Ñ\8dÑ\82о бÑ\83деÑ\82 пÑ\80оÑ\86еÑ\81Ñ\81 **пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80а завеÑ\80Ñ\88ениÑ\8f Ñ\80абоÑ\82Ñ\8b TLS**.
+Так как Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 Ñ\81лÑ\83Ñ\88аÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 поÑ\80Ñ\82, делаÑ\82Ñ\8c Ñ\8dÑ\82о бÑ\83деÑ\82 **пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80 TLS-Ñ\82еÑ\80минаÑ\86ии**.
-Ð\9fÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80 завеÑ\80Ñ\88ениÑ\8f Ñ\80абоÑ\82Ñ\8b TLS бÑ\83деÑ\82 имеÑ\82Ñ\8c доÑ\81Ñ\82Ñ\83п к одномÑ\83 или неÑ\81колÑ\8cким **TLS-Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ам** (Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b HTTPS).
+У пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80а TLS-Ñ\82еÑ\80минаÑ\86ии бÑ\83деÑ\82 доÑ\81Ñ\82Ñ\83п к одномÑ\83 или неÑ\81колÑ\8cким **TLSâ\80\91Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ам** (HTTPSâ\80\91Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ам).
-Используя **расширение SNI** упомянутое выше, прокси-сервер из имеющихся сертификатов TLS (HTTPS) выберет тот, который соответствует имени домена, указанному в запросе от клиента.
+Используя **расширение SNI**, упомянутое выше, прокси‑сервер TLS-терминации определит, какой из доступных TLS (HTTPS)‑сертификатов нужно использовать для этого соединения, выбрав тот, который соответствует домену, ожидаемому клиентом.
-То еÑ\81Ñ\82Ñ\8c бÑ\83деÑ\82 вÑ\8bбÑ\80ан Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 длÑ\8f домена `someapp.example.com`.
+Ð\92 наÑ\88ем Ñ\81лÑ\83Ñ\87ае Ñ\8dÑ\82о бÑ\83деÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 длÑ\8f `someapp.example.com`.
<img src="/img/deployment/https/https03.drawio.svg">
-Клиент уже **доверяет** тому, кто выдал этот TLS-сертификат (в нашем случае - Let's Encrypt, но мы ещё обсудим это), потому может **проверить**, действителен ли полученный от сервера сертификат.
+Клиент уже **доверяет** организации, выдавшей этот TLS‑сертификат (в нашем случае — Let's Encrypt, но об этом позже), поэтому может **проверить**, что сертификат действителен.
-Ð\97аÑ\82ем, иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\8dÑ\82оÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82, клиенÑ\82 и пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80 **вÑ\8bбиÑ\80аÑ\8eÑ\82 Ñ\81поÑ\81об Ñ\88иÑ\84Ñ\80ованиÑ\8f** даннÑ\8bÑ\85 длÑ\8f Ñ\83Ñ\81Ñ\82анавливаемого **TCP-Ñ\81оединениÑ\8f**. Ð\9dа Ñ\8dÑ\82ом опеÑ\80аÑ\86иÑ\8f **TLS-Ñ\80Ñ\83копожаÑ\82иÑ\8f** завеÑ\80Ñ\88ена.
+Ð\97аÑ\82ем, иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82, клиенÑ\82 и пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80 TLS-Ñ\82еÑ\80минаÑ\86ии **договаÑ\80иваÑ\8eÑ\82Ñ\81Ñ\8f о Ñ\81поÑ\81обе Ñ\88иÑ\84Ñ\80ованиÑ\8f** оÑ\81Ñ\82алÑ\8cной **TCPâ\80\91коммÑ\83никаÑ\86ии**. Ð\9dа Ñ\8dÑ\82ом **TLSâ\80\91Ñ\80Ñ\83копожаÑ\82ие** завеÑ\80Ñ\88ено.
-Ð\92 далÑ\8cнейÑ\88ем клиенÑ\82 и Ñ\81еÑ\80веÑ\80 бÑ\83дÑ\83Ñ\82 взаимодейÑ\81Ñ\82воваÑ\82Ñ\8c по **заÑ\88иÑ\84Ñ\80ованномÑ\83 TCP-Ñ\81оединениÑ\8e**, как пÑ\80едлагаеÑ\82Ñ\81Ñ\8f в пÑ\80оÑ\82околе TLS. Ð\98 на оÑ\81нове Ñ\8dÑ\82ого TCP-Ñ\81оедениниÑ\8f бÑ\83деÑ\82 Ñ\81оздано **HTTP-Ñ\81оединение**.
+Ð\9fоÑ\81ле Ñ\8dÑ\82ого Ñ\83 клиенÑ\82а и Ñ\81еÑ\80веÑ\80а еÑ\81Ñ\82Ñ\8c **заÑ\88иÑ\84Ñ\80ованное TCPâ\80\91Ñ\81оединение** â\80\94 Ñ\8dÑ\82о и пÑ\80едоÑ\81Ñ\82авлÑ\8fеÑ\82 TLS. Ð\98 они могÑ\83Ñ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82о Ñ\81оединение, Ñ\87Ñ\82обÑ\8b наÑ\87аÑ\82Ñ\8c Ñ\81обÑ\81Ñ\82венно **HTTPâ\80\91обмен**.
-Таким обÑ\80азом, **HTTPS** Ñ\8dÑ\82о Ñ\82оÑ\82 же **HTTP**, но внÑ\83Ñ\82Ñ\80и **безопаÑ\81ного TLS-Ñ\81оединениÑ\8f** вмеÑ\81Ñ\82о Ñ\87иÑ\81Ñ\82ого (незаÑ\88иÑ\84Ñ\80ованного) TCP-соединения.
+СобÑ\81Ñ\82венно, **HTTPS** â\80\94 Ñ\8dÑ\82о обÑ\8bÑ\87нÑ\8bй **HTTP** внÑ\83Ñ\82Ñ\80и **заÑ\89иÑ\89Ñ\91нного TLSâ\80\91Ñ\81оединениÑ\8f**, вмеÑ\81Ñ\82о Ñ\87иÑ\81Ñ\82ого (незаÑ\88иÑ\84Ñ\80ованного) TCPâ\80\91соединения.
-/// tip | Ð\97амеÑ\82ка
+/// tip | СовеÑ\82
-Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о Ñ\88иÑ\84Ñ\80ование пÑ\80оиÑ\81Ñ\85одиÑ\82 на **Ñ\83Ñ\80овне TCP**, а не на более вÑ\8bÑ\81оком уровне HTTP.
+Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о Ñ\88иÑ\84Ñ\80ование обмена пÑ\80оиÑ\81Ñ\85одиÑ\82 на **Ñ\83Ñ\80овне TCP**, а не на уровне HTTP.
///
-### HTTPS-запрос
+### HTTPS‑запрос { #https-request }
-Теперь, когда между клиентом и сервером (в нашем случае, браузером и прокси-сервером) создано **зашифрованное TCP-соединение**, они могут начать **обмен данными по протоколу HTTP**.
+Теперь, когда у клиента и сервера (конкретно у браузера и прокси‑сервера TLS-терминации) есть **зашифрованное TCP‑соединение**, они могут начать **HTTP‑обмен**.
-Так клиенÑ\82 оÑ\82пÑ\80авлÑ\8fеÑ\82 **HTTPS-запÑ\80оÑ\81**. То еÑ\81Ñ\82Ñ\8c обÑ\8bÑ\87нÑ\8bй HTTP-запÑ\80оÑ\81, но Ñ\87еÑ\80ез заÑ\88иÑ\84Ñ\80ованное TLS-Ñ\81одинение.
+Ð\9aлиенÑ\82 оÑ\82пÑ\80авлÑ\8fеÑ\82 **HTTPSâ\80\91запÑ\80оÑ\81**. ÐÑ\82о обÑ\8bÑ\87нÑ\8bй HTTPâ\80\91запÑ\80оÑ\81 Ñ\87еÑ\80ез заÑ\88иÑ\84Ñ\80ованное TLSâ\80\91Ñ\81оединение.
<img src="/img/deployment/https/https04.drawio.svg">
-### Расшифровка запроса
+### Расшифровка запроса { #decrypt-the-request }
-Прокси-сервер, используя согласованный с клиентом ключ, расшифрует полученный **зашифрованный запрос** и передаст **обычный (незашифрованный) HTTP-запрос** процессу, запускающему приложение (например, процессу Uvicorn запускающему приложение FastAPI).
+Прокси‑сервер TLS-терминации использует согласованное шифрование, чтобы **расшифровать запрос**, и передаёт **обычный (расшифрованный) HTTP‑запрос** процессу, запускающему приложение (например, процессу с Uvicorn, который запускает приложение FastAPI).
<img src="/img/deployment/https/https05.drawio.svg">
-### HTTP-ответ
+### HTTP‑ответ { #http-response }
-Ð\9fÑ\80иложение обÑ\80абоÑ\82аеÑ\82 запÑ\80оÑ\81 и веÑ\80нÑ\91Ñ\82 **обÑ\8bÑ\87нÑ\8bй (незаÑ\88иÑ\84Ñ\80ованнÑ\8bй) HTTP-оÑ\82веÑ\82** пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80Ñ\83.
+Ð\9fÑ\80иложение обÑ\80абоÑ\82аеÑ\82 запÑ\80оÑ\81 и оÑ\82пÑ\80авиÑ\82 **обÑ\8bÑ\87нÑ\8bй (незаÑ\88иÑ\84Ñ\80ованнÑ\8bй) HTTPâ\80\91оÑ\82веÑ\82** пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80Ñ\83 TLS-Ñ\82еÑ\80минаÑ\86ии.
<img src="/img/deployment/https/https06.drawio.svg">
-### HTTPS-ответ
+### HTTPS‑ответ { #https-response }
-Ð\9fÑ\80коÑ\81и-Ñ\81еÑ\80веÑ\80 **заÑ\88иÑ\84Ñ\80Ñ\83еÑ\82 оÑ\82веÑ\82** иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\80анее Ñ\81оглаÑ\81ованнÑ\8bй Ñ\81 клиенÑ\82ом Ñ\81поÑ\81об Ñ\88иÑ\84Ñ\80ованиÑ\8f (коÑ\82оÑ\80Ñ\8bе Ñ\81одеÑ\80жаÑ\82Ñ\81Ñ\8f в Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82е длÑ\8f домена `someapp.example.com`) и оÑ\82пÑ\80авиÑ\82 его бÑ\80аÑ\83зеÑ\80Ñ\83.
+Ð\97аÑ\82ем пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80 TLS-Ñ\82еÑ\80минаÑ\86ии **заÑ\88иÑ\84Ñ\80Ñ\83еÑ\82 оÑ\82веÑ\82** Ñ\81 иÑ\81полÑ\8cзованием Ñ\80анее Ñ\81оглаÑ\81ованного Ñ\81поÑ\81оба Ñ\88иÑ\84Ñ\80ованиÑ\8f (коÑ\82оÑ\80Ñ\8bй наÑ\87али иÑ\81полÑ\8cзоваÑ\82Ñ\8c длÑ\8f Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82а длÑ\8f `someapp.example.com`) и оÑ\82пÑ\80авиÑ\82 его обÑ\80аÑ\82но в бÑ\80аÑ\83зеÑ\80.
-Ð\9dаконеÑ\86, бÑ\80аÑ\83зеÑ\80 пÑ\80овеÑ\80иÑ\82 оÑ\82веÑ\82, в Ñ\82ом Ñ\87иÑ\81ле, Ñ\87Ñ\82о Ñ\82оÑ\82 заÑ\88иÑ\84Ñ\80ован Ñ\81 нÑ\83жнÑ\8bм клÑ\8eÑ\87ом, **Ñ\80аÑ\81Ñ\88иÑ\84Ñ\80Ñ\83еÑ\82 его** и обÑ\80абоÑ\82аеÑ\82.
+Ð\94алее бÑ\80аÑ\83зеÑ\80 пÑ\80овеÑ\80иÑ\82, Ñ\87Ñ\82о оÑ\82веÑ\82 коÑ\80Ñ\80екÑ\82ен и заÑ\88иÑ\84Ñ\80ован пÑ\80авилÑ\8cнÑ\8bм кÑ\80ипÑ\82огÑ\80аÑ\84иÑ\87еÑ\81ким клÑ\8eÑ\87ом и Ñ\82.п., заÑ\82ем **Ñ\80аÑ\81Ñ\88иÑ\84Ñ\80Ñ\83еÑ\82 оÑ\82веÑ\82** и обÑ\80абоÑ\82аеÑ\82 его.
<img src="/img/deployment/https/https07.drawio.svg">
-Клиент (браузер) знает, что ответ пришёл от правильного сервера, так как использует методы шифрования, согласованные ими раннее через **HTTPS-сертификат**.
+Клиент (браузер) узнает, что ответ пришёл от правильного сервера, потому что используется способ шифрования, о котором они договорились ранее с помощью **HTTPS‑сертификата**.
-### Ð\9cножеÑ\81Ñ\82во пÑ\80иложений
+### Ð\9dеÑ\81колÑ\8cко пÑ\80иложений { #multiple-applications }
-Ð\9dа одном и Ñ\82ом же Ñ\81еÑ\80веÑ\80е (или Ñ\81еÑ\80веÑ\80аÑ\85) можно Ñ\80азмеÑ\81Ñ\82иÑ\82Ñ\8c **множеÑ\81Ñ\82во пÑ\80иложений**, напÑ\80имеÑ\80, дÑ\80Ñ\83гие пÑ\80огÑ\80аммÑ\8b Ñ\81 API или базÑ\8b данных.
+Ð\9dа одном и Ñ\82ом же Ñ\81еÑ\80веÑ\80е (или Ñ\81еÑ\80веÑ\80аÑ\85) могÑ\83Ñ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c **неÑ\81колÑ\8cко пÑ\80иложений**, напÑ\80имеÑ\80 дÑ\80Ñ\83гие пÑ\80огÑ\80аммÑ\8b Ñ\81 API или база данных.
-Напомню, что только один процесс (например, прокси-сервер) может прослушивать определённый порт определённого IP-адреса.
-Но другие процессы и приложения тоже могут работать на этом же сервере (серверах), если они не пытаются использовать уже занятую **комбинацию IP-адреса и порта** (сокет).
+Только один процесс может обрабатывать конкретную комбинацию IP и порта (в нашем примере — прокси‑сервер TLS-терминации), но остальные приложения/процессы тоже могут работать на сервере(ах), пока они не пытаются использовать ту же **комбинацию публичного IP и порта**.
<img src="/img/deployment/https/https08.drawio.svg">
-Таким образом, сервер завершения TLS может обрабатывать HTTPS-запросы и использовать сертификаты для **множества доменов** или приложений и передавать запросы правильным адресатам (другим приложениям).
+Таким образом, прокси‑сервер TLS-терминации может обрабатывать HTTPS и сертификаты для **нескольких доменов** (для нескольких приложений), а затем передавать запросы нужному приложению в каждом случае.
-### Ð\9eбновление Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82а
+### Ð\9fÑ\80одление Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82а { #certificate-renewal }
-Ð\92 недалÑ\91ком бÑ\83дÑ\83Ñ\89ем лÑ\8eбой Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81Ñ\82анеÑ\82 **пÑ\80оÑ\81Ñ\80оÑ\87еннÑ\8bм** (пÑ\80имеÑ\80но Ñ\87еÑ\80ез Ñ\82Ñ\80и месяца после получения).
+Со вÑ\80еменем каждÑ\8bй Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 **иÑ\81Ñ\82еÑ\87Ñ\91Ñ\82** (пÑ\80имеÑ\80но Ñ\87еÑ\80ез 3 месяца после получения).
-Ð\9aогда Ñ\8dÑ\82о пÑ\80оизойдÑ\91Ñ\82, можно запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c дÑ\80Ñ\83гÑ\83Ñ\8e пÑ\80огÑ\80аммÑ\83, коÑ\82оÑ\80аÑ\8f подклÑ\8eÑ\87иÑ\82Ñ\81Ñ\8f к Let's Encrypt и обновиÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82(Ñ\8b). СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83Ñ\8eÑ\82 пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80Ñ\8b, коÑ\82оÑ\80Ñ\8bе могÑ\83Ñ\82 Ñ\81делаÑ\82Ñ\8c Ñ\8dÑ\82о дейÑ\81Ñ\82вие Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно.
+Ð\97аÑ\82ем бÑ\83деÑ\82 дÑ\80Ñ\83гаÑ\8f пÑ\80огÑ\80амма (иногда Ñ\8dÑ\82о оÑ\82делÑ\8cнаÑ\8f пÑ\80огÑ\80амма, иногда â\80\94 Ñ\82оÑ\82 же пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80 TLS-Ñ\82еÑ\80минаÑ\86ии), коÑ\82оÑ\80аÑ\8f Ñ\81вÑ\8fжеÑ\82Ñ\81Ñ\8f Ñ\81 Let's Encrypt и пÑ\80одлиÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82(Ñ\8b).
<img src="/img/deployment/https/https.drawio.svg">
-**TLS-сертификаты** не привязаны к IP-адресу, но **связаны с именем домена**.
+**TLS‑сертификаты** **связаны с именем домена**, а не с IP‑адресом.
-Так Ñ\87Ñ\82о пÑ\80и обновлении Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов пÑ\80огÑ\80амма должна **подÑ\82веÑ\80диÑ\82Ñ\8c** Ñ\86енÑ\82Ñ\80Ñ\83 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\86ии (Let's Encrypt), Ñ\87Ñ\82о обновление запÑ\80оÑ\81ил **"владелеÑ\86", коÑ\82оÑ\80Ñ\8bй контролирует этот домен**.
+Ð\9fоÑ\8dÑ\82омÑ\83, Ñ\87Ñ\82обÑ\8b пÑ\80одлиÑ\82Ñ\8c Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b, пÑ\80огÑ\80амма пÑ\80одлениÑ\8f должна **доказаÑ\82Ñ\8c** Ñ\83доÑ\81Ñ\82овеÑ\80Ñ\8fÑ\8eÑ\89емÑ\83 Ñ\86енÑ\82Ñ\80Ñ\83 (Let's Encrypt), Ñ\87Ñ\82о она дейÑ\81Ñ\82виÑ\82елÑ\8cно **«владееÑ\82» и контролирует этот домен**.
-Ð\95Ñ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко пÑ\83Ñ\82ей оÑ\81Ñ\83Ñ\89еÑ\81Ñ\82влениÑ\8f Ñ\8dÑ\82ого. СамÑ\8bе популярные из них:
+Ð\94лÑ\8f Ñ\8dÑ\82ого, Ñ\83Ñ\87иÑ\82Ñ\8bваÑ\8f Ñ\80азнÑ\8bе поÑ\82Ñ\80ебноÑ\81Ñ\82и пÑ\80иложений, еÑ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко Ñ\81поÑ\81обов. Ð\9fопулярные из них:
-* **Ð\98зменение запиÑ\81ей DNS**.
- * Ð\94лÑ\8f Ñ\82акого ваÑ\80ианÑ\82а Ð\92аÑ\88а пÑ\80огÑ\80амма обновлениÑ\8f должна Ñ\83меÑ\82Ñ\8c Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 API DNS-пÑ\80овайдеÑ\80а, обÑ\81лÑ\83живаÑ\8eÑ\89его Ð\92аÑ\88и DNS-запиÑ\81и. Ð\9dе Ñ\83 вÑ\81еÑ\85 пÑ\80овайдеÑ\80ов еÑ\81Ñ\82Ñ\8c Ñ\82акой API, Ñ\82ак Ñ\87Ñ\82о Ñ\8dÑ\82оÑ\82 Ñ\81поÑ\81об не вÑ\81егда пÑ\80именим.
-* **Запуск в качестве программы-сервера** (как минимум, на время обновления сертификатов) на публичном IP-адресе домена.
- * Ð\9aак Ñ\83же не Ñ\80аз Ñ\83поминалоÑ\81Ñ\8c, Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 пÑ\80оÑ\81лÑ\83Ñ\88иваÑ\82Ñ\8c опÑ\80еделÑ\91ннÑ\8bй поÑ\80Ñ\82 опÑ\80еделÑ\91нного IP-адÑ\80еÑ\81а.
- * Это одна из причин использования прокси-сервера ещё и в качестве программы обновления сертификатов.
- * В случае, если обновлением сертификатов занимается другая программа, вам понадобится остановить прокси-сервер, запустить программу обновления сертификатов на сокете, предназначенном для прокси-сервера, настроить прокси-сервер на работу с новыми сертификатами и перезапустить его. Эта схема далека от идеальной, так как Ваши приложения будут недоступны на время отключения прокси-сервера.
+* **Ð\98змениÑ\82Ñ\8c некоÑ\82оÑ\80Ñ\8bе DNSâ\80\91запиÑ\81и**.
+ * Ð\94лÑ\8f Ñ\8dÑ\82ого пÑ\80огÑ\80амма пÑ\80одлениÑ\8f должна поддеÑ\80живаÑ\82Ñ\8c API DNSâ\80\91пÑ\80овайдеÑ\80а, поÑ\8dÑ\82омÑ\83, в завиÑ\81имоÑ\81Ñ\82и оÑ\82 иÑ\81полÑ\8cзÑ\83емого пÑ\80овайдеÑ\80а DNS, Ñ\8dÑ\82оÑ\82 ваÑ\80ианÑ\82 можеÑ\82 бÑ\8bÑ\82Ñ\8c доÑ\81Ñ\82Ñ\83пен или неÑ\82.
+* **Запуститься как сервер** (как минимум на время получения сертификатов) на публичном IP‑адресе, связанном с доменом.
+ * Ð\9aак Ñ\81казано вÑ\8bÑ\88е, Ñ\82олÑ\8cко один пÑ\80оÑ\86еÑ\81Ñ\81 можеÑ\82 Ñ\81лÑ\83Ñ\88аÑ\82Ñ\8c конкÑ\80еÑ\82нÑ\8bй IP и поÑ\80Ñ\82.
+ * Это одна из причин, почему очень удобно, когда тот же прокси‑сервер TLS-терминации также занимается процессом продления сертификатов.
+ * В противном случае вам, возможно, придётся временно остановить прокси‑сервер TLS-терминации, запустить программу продления для получения сертификатов, затем настроить их в прокси‑сервере TLS-терминации и перезапустить его. Это не идеально, так как ваше приложение(я) будут недоступны, пока прокси‑сервер TLS-терминации остановлен.
-Ð\92еÑ\81Ñ\8c Ñ\8dÑ\82оÑ\82 пÑ\80оÑ\86еÑ\81Ñ\81 обновлениÑ\8f, одновÑ\80еменнÑ\8bй Ñ\81 обÑ\81лÑ\83живанием запÑ\80оÑ\81ов, Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f одной из оÑ\81новнÑ\8bÑ\85 пÑ\80иÑ\87ин, по коÑ\82оÑ\80ой желаÑ\82елÑ\8cно имеÑ\82Ñ\8c **оÑ\82делÑ\8cнÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 HTTPS** в виде пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80а завеÑ\80Ñ\88ениÑ\8f TLS, а не пÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\8b TLS непоÑ\81Ñ\80едÑ\81Ñ\82венно Ñ\81 Ñ\81еÑ\80веÑ\80ом пÑ\80иложений (например, Uvicorn).
+Ð\92еÑ\81Ñ\8c Ñ\8dÑ\82оÑ\82 пÑ\80оÑ\86еÑ\81Ñ\81 пÑ\80одлениÑ\8f, Ñ\81овмеÑ\89Ñ\91ннÑ\8bй Ñ\81 обÑ\81лÑ\83живанием пÑ\80иложениÑ\8f, â\80\94 одна из главнÑ\8bÑ\85 пÑ\80иÑ\87ин имеÑ\82Ñ\8c **оÑ\82делÑ\8cнÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 HTTPS** в виде пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80а TLS-Ñ\82еÑ\80минаÑ\86ии, вмеÑ\81Ñ\82о иÑ\81полÑ\8cзованиÑ\8f TLSâ\80\91Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов напÑ\80Ñ\8fмÑ\83Ñ\8e в Ñ\81еÑ\80веÑ\80е пÑ\80иложениÑ\8f (например, Uvicorn).
-## РезÑ\8eме
+## Ð\9fеÑ\80еÑ\81Ñ\8bлаемÑ\8bе HTTP-заголовки пÑ\80окÑ\81и { #proxy-forwarded-headers }
-Ð\9dалиÑ\87ие **HTTPS** оÑ\87енÑ\8c важно и доволÑ\8cно **кÑ\80иÑ\82иÑ\87но** в болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев. Ð\9eднако, Ð\92ам, как Ñ\80азÑ\80абоÑ\82Ñ\87икÑ\83, не нÑ\83жно Ñ\82Ñ\80аÑ\82иÑ\82Ñ\8c много Ñ\81ил на Ñ\8dÑ\82о, доÑ\81Ñ\82аÑ\82оÑ\87но **понимаÑ\82Ñ\8c Ñ\8dÑ\82и конÑ\86епÑ\86ии** и пÑ\80инÑ\86ипÑ\8b иÑ\85 Ñ\80абоÑ\82Ñ\8b.
+Ð\9aогда вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е пÑ\80окÑ\81и длÑ\8f обÑ\80абоÑ\82ки HTTPS, ваÑ\88 **Ñ\81еÑ\80веÑ\80 пÑ\80иложениÑ\8f** (напÑ\80имеÑ\80, Uvicorn Ñ\87еÑ\80ез FastAPI CLI) ниÑ\87его не знаеÑ\82 о пÑ\80оÑ\86еÑ\81Ñ\81е HTTPS, он обÑ\89аеÑ\82Ñ\81Ñ\8f обÑ\8bÑ\87нÑ\8bм HTTP Ñ\81 **пÑ\80окÑ\81иâ\80\91Ñ\81еÑ\80веÑ\80ом TLS-Ñ\82еÑ\80минаÑ\86ии**.
-Ð\9dо Ñ\83знав базовÑ\8bе оÑ\81новÑ\8b **HTTPS** вÑ\8b можеÑ\82е легко Ñ\81овмеÑ\89аÑ\82Ñ\8c Ñ\80азнÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b, коÑ\82оÑ\80Ñ\8bе помогÑ\83Ñ\82 вам в далÑ\8cнейÑ\88ей Ñ\80азÑ\80абоÑ\82ке.
+Ð\9eбÑ\8bÑ\87но Ñ\8dÑ\82оÑ\82 **пÑ\80окÑ\81и** на леÑ\82Ñ\83 добавлÑ\8fеÑ\82 некоÑ\82оÑ\80Ñ\8bе HTTPâ\80\91заголовки пеÑ\80ед Ñ\82ем, как пеÑ\80еÑ\81лаÑ\82Ñ\8c запÑ\80оÑ\81 на **Ñ\81еÑ\80веÑ\80 пÑ\80иложениÑ\8f**, Ñ\87Ñ\82обÑ\8b Ñ\82оÑ\82 знал, Ñ\87Ñ\82о запÑ\80оÑ\81 бÑ\8bл **пÑ\80окÑ\81иÑ\80ован**.
-В следующих главах я покажу вам несколько примеров, как настраивать **HTTPS** для приложений **FastAPI**. 🔒
+/// note | Технические детали
+
+Заголовки прокси:
+
+* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
+* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
+* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
+
+///
+
+Тем не менее, так как **сервер приложения** не знает, что он находится за доверенным **прокси**, по умолчанию он не будет доверять этим заголовкам.
+
+Но вы можете настроить **сервер приложения**, чтобы он доверял *пересылаемым* заголовкам, отправленным **прокси**. Если вы используете FastAPI CLI, вы можете использовать *опцию CLI* `--forwarded-allow-ips`, чтобы указать, с каких IP‑адресов следует доверять этим *пересылаемым* заголовкам.
+
+Например, если **сервер приложения** получает запросы только от доверенного **прокси**, вы можете установить `--forwarded-allow-ips="*"`, чтобы доверять всем входящим IP, так как он всё равно будет получать запросы только с IP‑адреса, используемого **прокси**.
+
+Таким образом, приложение сможет знать свой публичный URL, использует ли оно HTTPS, какой домен и т.п.
+
+Это будет полезно, например, для корректной обработки редиректов.
+
+/// tip | Совет
+
+Подробнее об этом вы можете узнать в документации: [За прокси — Включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
+
+///
+
+## Резюме { #recap }
+
+Наличие **HTTPS** очень важно и во многих случаях довольно **критично**. Большая часть усилий, которые вам, как разработчику, нужно приложить вокруг HTTPS, — это просто **понимание этих концепций** и того, как они работают.
+
+Зная базовую информацию о **HTTPS для разработчиков**, вы сможете легко комбинировать и настраивать разные инструменты, чтобы управлять всем этим простым способом.
+
+В некоторых из следующих глав я покажу вам несколько конкретных примеров настройки **HTTPS** для приложений **FastAPI**. 🔒
-# Развёртывание
+# Развёртывание { #deployment }
Развернуть приложение **FastAPI** довольно просто.
-## Ð\94а Ñ\87Ñ\82о Ñ\82акое Ñ\8dÑ\82о ваÑ\88е - "Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвание"?!
+## ЧÑ\82о ознаÑ\87аеÑ\82 Ñ\80азвÑ\91Ñ\80Ñ\82Ñ\8bвание { #what-does-deployment-mean }
Термин **развёртывание** (приложения) означает выполнение необходимых шагов, чтобы сделать приложение **доступным для пользователей**.
-Ð\9eбÑ\8bÑ\87но **веб-пÑ\80иложениÑ\8f** Ñ\80азмеÑ\89аÑ\8eÑ\82 на Ñ\83далÑ\91нном компÑ\8cÑ\8eÑ\82еÑ\80е Ñ\81 Ñ\81еÑ\80веÑ\80ной пÑ\80огÑ\80аммой, коÑ\82оÑ\80аÑ\8f обеÑ\81пеÑ\87иваеÑ\82 Ñ\85оÑ\80оÑ\88Ñ\83Ñ\8e пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c, Ñ\81Ñ\82абилÑ\8cноÑ\81Ñ\82Ñ\8c и Ñ\82. д., ЧÑ\82обÑ\8b ваÑ\88и полÑ\8cзоваÑ\82ели могли Ñ\8dÑ\84Ñ\84екÑ\82ивно, беÑ\81пÑ\80еÑ\80Ñ\8bвно и беÑ\81пÑ\80облемно обÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f к пÑ\80иложениÑ\8e.
+Ð\94лÑ\8f **веб-API** Ñ\8dÑ\82о обÑ\8bÑ\87но ознаÑ\87аеÑ\82 Ñ\80азмеÑ\89ение его на **Ñ\83далÑ\91нной маÑ\88ине** Ñ\81 **Ñ\81еÑ\80веÑ\80ной пÑ\80огÑ\80аммой**, обеÑ\81пеÑ\87иваÑ\8eÑ\89ей Ñ\85оÑ\80оÑ\88Ñ\83Ñ\8e пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c, Ñ\81Ñ\82абилÑ\8cноÑ\81Ñ\82Ñ\8c и Ñ\82.д., Ñ\87Ñ\82обÑ\8b ваÑ\88и **полÑ\8cзоваÑ\82ели** могли **полÑ\83Ñ\87аÑ\82Ñ\8c доÑ\81Ñ\82Ñ\83п** к пÑ\80иложениÑ\8e Ñ\8dÑ\84Ñ\84екÑ\82ивно и без пеÑ\80ебоев или пÑ\80облем.
-Это отличается от **разработки**, когда вы постоянно меняете код, делаете в нём намеренные ошибки и исправляете их, останавливаете и перезапускаете сервер разработки и т. д.
+Это отличается от этапов **разработки**, когда вы постоянно меняете код, ломаете его и исправляете, останавливаете и перезапускаете сервер разработки и т.д.
-## Стратегии развёртывания
+## Стратегии развёртывания { #deployment-strategies }
В зависимости от вашего конкретного случая, есть несколько способов сделать это.
-# Запуск сервера вручную - Uvicorn
+# Запуск сервера вручную { #run-a-server-manually }
-Для запуска приложения **FastAPI** на удалённой серверной машине вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**.
+## Используйте команду `fastapi run` { #use-the-fastapi-run-command }
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 Ñ\82Ñ\80и наиболее Ñ\80аÑ\81пÑ\80оÑ\81Ñ\82Ñ\80анÑ\91ннÑ\8bе алÑ\8cÑ\82еÑ\80наÑ\82ивÑ\8b:
+Ð\9aоÑ\80оÑ\82ко: иÑ\81полÑ\8cзÑ\83йÑ\82е `fastapi run`, Ñ\87Ñ\82обÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c ваÑ\88е пÑ\80иложение FastAPI:
-* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>: высокопроизводительный ASGI сервер.
-* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: ASGI сервер, помимо прочего поддерживающий HTTP/2 и Trio.
-* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: ASGI сервер, созданный для Django Channels.
-
-## Сервер как машина и сервер как программа
-
-В этих терминах есть некоторые различия и вам следует запомнить их. 💡
-
-Слово "**сервер**" чаще всего используется в двух контекстах:
+<div class="termy">
-- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина).
-- программа, запущенная на таком компьютере (например, Uvicorn).
+```console
+$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
-Просто запомните, если вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов.
+ <span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
-Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором вы запускаете программы.
+ Searching for package file structure from directories
+ with <font color="#3465A4">__init__.py</font> files
+ Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
-## Установка программного сервера
+ <span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
-Вы можете установить сервер, совместимый с протоколом ASGI, так:
+ <span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
+ the following code:
-//// tab | Uvicorn
+ <u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
-* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, очень быстрый ASGI сервер, основанный на библиотеках uvloop и httptools.
+ <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
-<div class="termy">
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
-```console
-$ pip install "uvicorn[standard]"
+ Logs:
----> 100%
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C
+ to quit<b>)</b>
```
</div>
-/// tip | Подсказка
-
-С опцией `standard`, Uvicorn будет устанавливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями.
-
-В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ.
-
-///
-
-////
+В большинстве случаев этого достаточно. 😎
-//// tab | Hypercorn
+Этой командой, например, можно запускать приложение **FastAPI** в контейнере, на сервере и т.д.
-* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, ASGI сервер, поддерживающий протокол HTTP/2.
+## ASGI‑серверы { #asgi-servers }
-<div class="termy">
+Давайте немного углубимся в детали.
-```console
-$ pip install hypercorn
+FastAPI использует стандарт для построения Python‑веб‑фреймворков и серверов под названием <abbr title="Asynchronous Server Gateway Interface – Асинхронный шлюзовый интерфейс сервера">ASGI</abbr>. FastAPI — ASGI-веб‑фреймворк.
----> 100%
-```
+Главное, что вам нужно, чтобы запустить приложение **FastAPI** (или любое другое ASGI‑приложение) на удалённой серверной машине, — это программа ASGI‑сервера, такая как **Uvicorn**; именно он используется по умолчанию в команде `fastapi`.
-</div>
+Есть несколько альтернатив, например:
-...или какой-либо другой ASGI сервер.
+* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>: высокопроизводительный ASGI‑сервер.
+* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: ASGI‑сервер, среди прочего совместимый с HTTP/2 и Trio.
+* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: ASGI‑сервер, созданный для Django Channels.
+* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a>: HTTP‑сервер на Rust для Python‑приложений.
+* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a>: NGINX Unit — лёгкая и многофункциональная среда выполнения веб‑приложений.
-////
+## Сервер как машина и сервер как программа { #server-machine-and-server-program }
-## Запуск серверной программы
+Есть небольшой нюанс в терминологии, о котором стоит помнить. 💡
-Ð\97аÑ\82ем запÑ\83Ñ\81Ñ\82иÑ\82е ваÑ\88е пÑ\80иложение Ñ\82ак же, как бÑ\8bло Ñ\83казано в Ñ\80Ñ\83ководÑ\81Ñ\82ве Ñ\80анее, но без опÑ\86ии `--reload`:
+Слово «Ñ\81еÑ\80веÑ\80» обÑ\8bÑ\87но иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 и длÑ\8f обознаÑ\87ениÑ\8f Ñ\83далÑ\91нного/облаÑ\87ного компÑ\8cÑ\8eÑ\82еÑ\80а (Ñ\84изиÑ\87еÑ\81кой или виÑ\80Ñ\82Ñ\83алÑ\8cной маÑ\88инÑ\8b), и длÑ\8f пÑ\80огÑ\80аммÑ\8b, Ñ\80абоÑ\82аÑ\8eÑ\89ей на Ñ\8dÑ\82ой маÑ\88ине (напÑ\80имеÑ\80, Uvicorn).
-//// tab | Uvicorn
+Имейте в виду, что слово «сервер» в целом может означать любое из этих двух.
-<div class="termy">
+Когда речь идёт об удалённой машине, её зачастую называют **сервер**, а также **машина**, **VM** (виртуальная машина), **нода**. Всё это — варианты названия удалённой машины, обычно под управлением Linux, на которой вы запускаете программы.
-```console
-$ uvicorn main:app --host 0.0.0.0 --port 80
+## Установка серверной программы { #install-the-server-program }
-<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
-```
+При установке FastAPI он поставляется с продакшн‑сервером Uvicorn, и вы можете запустить его командой `fastapi run`.
-</div>
+Но вы также можете установить ASGI‑сервер вручную.
-////
+Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите серверное приложение.
-//// tab | Hypercorn
+Например, чтобы установить Uvicorn:
<div class="termy">
```console
-$ hypercorn main:app --bind 0.0.0.0:80
+$ pip install "uvicorn[standard]"
-Running on 0.0.0.0:8080 over http (CTRL + C to quit)
+---> 100%
```
</div>
-////
+Аналогично устанавливаются и другие ASGI‑серверы.
-/// warning | Предупреждение
+/// tip | Совет
-Ð\9dе забÑ\83дÑ\8cÑ\82е Ñ\83далиÑ\82Ñ\8c опÑ\86иÑ\8e `--reload`, еÑ\81ли Ñ\80анее полÑ\8cзовалиÑ\81Ñ\8c еÑ\8e.
+С добавлением `standard` Uvicorn Ñ\83Ñ\81Ñ\82ановиÑ\82 и бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\80Ñ\8fд Ñ\80екомендованнÑ\8bÑ\85 дополниÑ\82елÑ\8cнÑ\8bÑ\85 завиÑ\81имоÑ\81Ñ\82ей.
-Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности.
+В их числе `uvloop` — высокопроизводительная замена `asyncio`, дающая серьёзный прирост производительности при параллельной работе.
-Ð\9eна Ñ\81илÑ\8cно помогаеÑ\82 во вÑ\80емÑ\8f **Ñ\80азÑ\80абоÑ\82ки**, но **не Ñ\81ледÑ\83еÑ\82** иÑ\81полÑ\8cзоваÑ\82Ñ\8c еÑ\91 пÑ\80и **Ñ\80еалÑ\8cной Ñ\80абоÑ\82е** пÑ\80иложениÑ\8f.
+Ð\95Ñ\81ли вÑ\8b Ñ\83Ñ\81Ñ\82анавливаеÑ\82е FastAPI, напÑ\80имеÑ\80 Ñ\82ак: `pip install "fastapi[standard]"`, вÑ\8b Ñ\83же полÑ\83Ñ\87аеÑ\82е и `uvicorn[standard]`.
///
-## Hypercorn с Trio
-
-Starlette и **FastAPI** основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, которая делает их совместимыми как с <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> - стандартной библиотекой Python, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
-
+## Запуск серверной программы { #run-the-server-program }
-Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a>, высокопроизводительной заменой `asyncio`.
-
-Но если вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨
-
-### Установка Hypercorn с Trio
-
-Для начала, вам нужно установить Hypercorn с поддержкой Trio:
+Если вы установили ASGI‑сервер вручную, обычно нужно передать строку импорта в специальном формате, чтобы он смог импортировать ваше приложение FastAPI:
<div class="termy">
```console
-$ pip install "hypercorn[trio]"
----> 100%
+$ uvicorn main:app --host 0.0.0.0 --port 80
+
+<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
```
</div>
-### Запуск с Trio
+/// note | Примечание
-Ð\94алее запÑ\83Ñ\81Ñ\82иÑ\82е Hypercorn Ñ\81 опÑ\86ией `--worker-class` и аÑ\80гÑ\83менÑ\82ом `trio`:
+Ð\9aоманда `uvicorn main:app` ознаÑ\87аеÑ\82:
-<div class="termy">
+* `main`: файл `main.py` (Python‑«модуль»).
+* `app`: объект, созданный в `main.py` строкой `app = FastAPI()`.
-```console
-$ hypercorn main:app --worker-class trio
+Эквивалентно:
+
+```Python
+from main import app
```
-</div>
+///
-Hypercorn, в свою очередь, запустит ваше приложение использующее Trio.
+У каждого альтернативного ASGI‑сервера будет похожая команда; подробнее см. в их документации.
-Таким образом, вы сможете использовать Trio в своём приложении. Но лучше использовать AnyIO, для сохранения совместимости и с Trio, и с asyncio. 🎉
+/// warning | Предупреждение
+
+Uvicorn и другие серверы поддерживают опцию `--reload`, полезную в период разработки.
+
+Опция `--reload` потребляет значительно больше ресурсов, менее стабильна и т.п.
+
+Она сильно помогает во время **разработки**, но в **продакшн** её использовать **не следует**.
+
+///
-## Концепции развёртывания
+## Концепции развёртывания { #deployment-concepts }
-В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`).
+В этих примерах серверная программа (например, Uvicorn) запускает **один процесс**, слушающий все IP‑адреса (`0.0.0.0`) на заранее заданном порту (например, `80`).
-ÐÑ\82о оÑ\81новнаÑ\8f идеÑ\8f. Ð\9dо возможно, вÑ\8b озабоÑ\82иÑ\82еÑ\81Ñ\8c добавлением дополниÑ\82елÑ\8cнÑ\8bÑ\85 возможноÑ\81Ñ\82ей, Ñ\82акиÑ\85 как:
+ÐÑ\82о базоваÑ\8f идеÑ\8f. Ð\9dо, веÑ\80оÑ\8fÑ\82но, вам понадобиÑ\82Ñ\81Ñ\8f позабоÑ\82иÑ\82Ñ\8cÑ\81Ñ\8f и о некоÑ\82оÑ\80Ñ\8bÑ\85 дополниÑ\82елÑ\8cнÑ\8bÑ\85 веÑ\89аÑ\85, напÑ\80имеÑ\80:
-* Ð\98Ñ\81полÑ\8cзование более безопаÑ\81ного пÑ\80оÑ\82окола HTTPS
-* Ð\9dаÑ\81Ñ\82Ñ\80ойки запÑ\83Ñ\81ка пÑ\80иложениÑ\8f
-* Ð\9fеÑ\80езагÑ\80Ñ\83зка пÑ\80иложениÑ\8f
-* Ð\97апÑ\83Ñ\81к неÑ\81колÑ\8cкиÑ\85 Ñ\8dкземплÑ\8fÑ\80ов пÑ\80иложениÑ\8f
-* УпÑ\80авление памÑ\8fÑ\82Ñ\8cÑ\8e
-* Ð\98Ñ\81полÑ\8cзование пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий пеÑ\80ед запÑ\83Ñ\81ком пÑ\80иложениÑ\8f.
+* Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c â\80\94 HTTPS
+* Ð\97апÑ\83Ñ\81к пÑ\80и Ñ\81Ñ\82аÑ\80Ñ\82е Ñ\81иÑ\81Ñ\82емÑ\8b
+* Ð\9fеÑ\80езапÑ\83Ñ\81ки
+* РепликаÑ\86иÑ\8f (колиÑ\87еÑ\81Ñ\82во запÑ\83Ñ\89еннÑ\8bÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81ов)
+* Ð\9fамÑ\8fÑ\82Ñ\8c
+* Ð\9fÑ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bе Ñ\88аги пеÑ\80ед запÑ\83Ñ\81ком
-Я Ñ\80аÑ\81Ñ\81кажÑ\83 вам болÑ\8cÑ\88е о каждой из Ñ\8dÑ\82иÑ\85 конÑ\86епÑ\86ий в Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 главаÑ\85, Ñ\81 конкÑ\80еÑ\82нÑ\8bми пÑ\80имеÑ\80ами Ñ\81Ñ\82Ñ\80аÑ\82егий Ñ\80абоÑ\82Ñ\8b Ñ\81 ними. 🚀
+Ð\92 Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 главаÑ\85 Ñ\8f Ñ\80аÑ\81Ñ\81кажÑ\83 подÑ\80обнее пÑ\80о каждÑ\83Ñ\8e из Ñ\8dÑ\82иÑ\85 конÑ\86епÑ\86ий, о Ñ\82ом, как о ниÑ\85 дÑ\83маÑ\82Ñ\8c, и пÑ\80иведÑ\83 конкÑ\80еÑ\82нÑ\8bе пÑ\80имеÑ\80Ñ\8b Ñ\81о Ñ\81Ñ\82Ñ\80аÑ\82егиÑ\8fми, как Ñ\81 ними Ñ\80абоÑ\82аÑ\82Ñ\8c. 🚀
-# О версиях FastAPI
+# О версиях FastAPI { #about-fastapi-versions }
-**FastAPI** Ñ\83же иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f в пÑ\80одакÑ\88ене во многиÑ\85 пÑ\80иложениÑ\8fÑ\85 и Ñ\81иÑ\81Ñ\82емаÑ\85. Ð\9fокÑ\80Ñ\8bÑ\82ие Ñ\82еÑ\81Ñ\82ами поддеÑ\80живаеÑ\82Ñ\81Ñ\8f на Ñ\83Ñ\80овне 100%. Ð\9eднако его Ñ\80азÑ\80абоÑ\82ка вÑ\81е еÑ\89е пÑ\80одолжаеÑ\82Ñ\81Ñ\8f.
+**FastAPI** Ñ\83же иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f в пÑ\80одакÑ\88ене во многиÑ\85 пÑ\80иложениÑ\8fÑ\85 и Ñ\81иÑ\81Ñ\82емаÑ\85. Ð\9fокÑ\80Ñ\8bÑ\82ие Ñ\82еÑ\81Ñ\82ами поддеÑ\80живаеÑ\82Ñ\81Ñ\8f на Ñ\83Ñ\80овне 100%. Ð\9dо его Ñ\80азÑ\80абоÑ\82ка вÑ\81Ñ\91 еÑ\89Ñ\91 движеÑ\82Ñ\81Ñ\8f бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bми Ñ\82емпами.
Часто добавляются новые функции, регулярно исправляются баги, код продолжает постоянно совершенствоваться.
-По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя <a href="https://semver.org/" class="external-link" target="_blank">соглашению о Семантическом Версионировании</a>.
+По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя <a href="https://semver.org/" class="external-link" target="_blank">Семантическому версионированию</a>.
-Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.
+Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.
-## Закрепите вашу версию `fastapi`
+## Закрепите вашу версию `fastapi` { #pin-your-fastapi-version }
Первым делом вам следует "закрепить" конкретную последнюю используемую версию **FastAPI**, которая корректно работает с вашим приложением.
-Например, в своём приложении вы используете версию `0.45.0`.
+Например, в своём приложении вы используете версию `0.112.0`.
Если вы используете файл `requirements.txt`, вы можете указать версию следующим способом:
```txt
-fastapi==0.45.0
+fastapi[standard]==0.112.0
```
-это означает, что вы будете использовать именно версию `0.45.0`.
+это означает, что вы будете использовать именно версию `0.112.0`.
Или вы можете закрепить версию следующим способом:
```txt
-fastapi>=0.45.0,<0.46.0
+fastapi[standard]>=0.112.0,<0.113.0
```
-это значит, что вы используете версии `0.45.0` или выше, но меньше чем `0.46.0`. Например, версия `0.45.2` все еще будет подходить.
+это значит, что вы используете версии `0.112.0` или выше, но меньше чем `0.113.0`. Например, версия `0.112.2` всё ещё будет подходить.
-Если вы используете любой другой инструмент для управления зависимостями, например Poetry, Pipenv или др., у них у всех имеется способ определения специфической версии для ваших пакетов.
+Если вы используете любой другой инструмент для управления установками/зависимостями, например `uv`, Poetry, Pipenv или др., у них у всех имеется способ определения специфической версии для ваших пакетов.
-## Доступные версии
+## Доступные версии { #available-versions }
-Ð\92Ñ\8b можеÑ\82е поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c доÑ\81Ñ\82Ñ\83пнÑ\8bе веÑ\80Ñ\81ии (напÑ\80имеÑ\80, пÑ\80овеÑ\80иÑ\82Ñ\8c поÑ\81леднÑ\8eÑ\8e на даннÑ\8bй моменÑ\82) в [примечаниях к выпуску](../release-notes.md){.internal-link target=_blank}.
+Ð\92Ñ\8b можеÑ\82е поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c доÑ\81Ñ\82Ñ\83пнÑ\8bе веÑ\80Ñ\81ии (напÑ\80имеÑ\80, пÑ\80овеÑ\80иÑ\82Ñ\8c поÑ\81леднÑ\8eÑ\8e на даннÑ\8bй моменÑ\82) в [Ð\9fримечаниях к выпуску](../release-notes.md){.internal-link target=_blank}.
-## О версиях
+## О версиях { #about-versions }
Следуя соглашению о Семантическом Версионировании, любые версии ниже `1.0.0` потенциально могут добавить обратно несовместимые изменения.
/// tip | Подсказка
-"ПАТЧ" - это последнее число. Например, в `0.2.3`, ПАТЧ-версия - это `3`.
+"ПАТЧ" — это последнее число. Например, в `0.2.3`, ПАТЧ-версия — это `3`.
///
/// tip | Подсказка
-"МИНОРНАЯ" версия - это число в середине. Например, в `0.2.3` МИНОРНАЯ версия - это `2`.
+"МИНОРНАЯ" версия — это число в середине. Например, в `0.2.3` МИНОРНАЯ версия — это `2`.
///
-## Обновление версий FastAPI
+## Обновление версий FastAPI { #upgrading-the-fastapi-versions }
Вам следует добавить тесты для вашего приложения.
После создания тестов вы можете обновить свою версию **FastAPI** до более новой. После этого следует убедиться, что ваш код работает корректно, запустив тесты.
-Если все работает корректно, или после внесения необходимых изменений все ваши тесты проходят, только тогда вы можете закрепить вашу новую версию `fastapi`.
+Если всё работает корректно, или после внесения необходимых изменений все ваши тесты проходят, только тогда вы можете закрепить вашу новую версию `fastapi`.
-## О Starlette
+## О Starlette { #about-starlette }
Не следует закреплять версию `starlette`.
Так что решение об используемой версии Starlette, вы можете оставить **FastAPI**.
-## О Pydantic
+## О Pydantic { #about-pydantic }
Pydantic включает свои собственные тесты для **FastAPI**, так что новые версии Pydantic (выше `1.0.0`) всегда совместимы с FastAPI.
-Вы можете закрепить любую версию Pydantic, которая вам подходит, выше `1.0.0` и ниже `2.0.0`.
+Вы можете закрепить любую версию Pydantic, которая вам подходит, выше `1.0.0`.
Например:
```txt
-pydantic>=1.2.0,<2.0.0
+pydantic>=2.7.0,<3.0.0
```
-# Переменные окружения
+# Переменные окружения { #environment-variables }
-/// tip
+/// tip | Совет
Если вы уже знаете, что такое «переменные окружения» и как их использовать, можете пропустить это.
Переменные окружения могут быть полезны для работы с **настройками** приложений, как часть **установки** Python и т.д.
-## Создание и использование переменных окружения
+## Создание и использование переменных окружения { #create-and-use-env-vars }
Можно **создавать** и использовать переменные окружения в **оболочке (терминале)**, не прибегая к помощи Python:
////
-## Чтение переменных окружения в python
+## Чтение переменных окружения в python { #read-env-vars-in-python }
Так же существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**.
print(f"Hello {name} from Python")
```
-/// tip
+/// tip | Совет
-Второй аргумент <a href=«https://docs.python.org/3.8/library/os.html#os.getenv» class=«external-link» target=«_blank»>`os.getenv()`</a> - это возвращаемое по умолчанию значение.
+Второй аргумент <a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> - это возвращаемое по умолчанию значение.
Если значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `«World»` в качестве значения по умолчанию.
+
///
Затем можно запустить эту программу на Python:
</div>
-/// tip
+/// tip | Совет
Подробнее об этом можно прочитать на сайте <a href="https://12factor.net/config" class="external-link" target="_blank">The Twelve-Factor App: Config</a>.
///
-## Типизация и Валидация
+## Типизация и Валидация { #types-and-validation }
Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS).
Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md){.internal-link target=_blank}.
-## Переменная окружения `PATH`
+## Переменная окружения `PATH` { #path-environment-variable }
Существует **специальная** переменная окружения **`PATH`**, которая используется операционными системами (Linux, macOS, Windows) для поиска программ для запуска.
Если она ее находит, то **использует ее**. В противном случае она продолжает искать в **других каталогах**.
-### Установка Python и обновление `PATH`
+### Установка Python и обновление `PATH` { #installing-python-and-updating-the-path }
При установке Python вас могут спросить, нужно ли обновить переменную окружения `PATH`.
Эта информация будет полезна при изучении [Виртуальных окружений](virtual-environments.md){.internal-link target=_blank}.
-## Вывод
+## Вывод { #conclusion }
Благодаря этому вы должны иметь базовое представление о том, что такое **переменные окружения** и как использовать их в Python.
-# FastAPI CLI
+# FastAPI CLI { #fastapi-cli }
**FastAPI CLI** это программа командной строки, которую вы можете использовать для запуска вашего FastAPI приложения, для управления FastAPI-проектом, а также для многих других вещей.
FastAPI CLI берет путь к вашей Python-программе (напр. `main.py`) и автоматически находит объект `FastAPI` (обычно это `app`), затем определяет правильный процесс импорта и запускает сервер приложения.
-Для работы в production окружении вместо `fastapi dev` нужно использовать `fastapi run`. 🚀
+Для работы в режиме продакшн вместо `fastapi dev` нужно использовать `fastapi run`. 🚀
-Внутри **FastAPI CLI** используется <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>, высокопроизводительный, готовый к работе в production сервер ASGI. 😎
+Внутри **FastAPI CLI** используется <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>, высокопроизводительный, готовый к работе в продакшне ASGI-сервер. 😎
-## `fastapi dev`
+## `fastapi dev` { #fastapi-dev }
Вызов `fastapi dev` запускает режим разработки.
-По умолчанию включена автоматическая перезагрузка (**auto-reload**), благодаря этому при изменении кода происходит перезагрузка сервера приложения. Эта установка требует значительных ресурсов и делает систему менее стабильной. Используйте её только при разработке. Приложение слушает входящие подключения на IP `127.0.0.1`. Это IP адрес вашей машины, предназначенный для внутренних коммуникаций (`localhost`).
+По умолчанию включена авто-перезагрузка (**auto-reload**), благодаря этому при изменении кода происходит перезагрузка сервера приложения. Эта установка требует значительных ресурсов и делает систему менее стабильной. Используйте её только при разработке. Приложение слушает входящие подключения на IP `127.0.0.1`. Это IP адрес вашей машины, предназначенный для внутренних коммуникаций (`localhost`).
-## `fastapi run`
+## `fastapi run` { #fastapi-run }
-Вызов `fastapi run` по умолчанию запускает FastAPI в режиме production.
+Вызов `fastapi run` по умолчанию запускает FastAPI в режиме продакшн.
-По умолчанию функция перезагрузки **auto-reload** отключена. Приложение слушает входящие подключения на IP `0.0.0.0`, т.е. на всех доступных адресах компьютера. Таким образом, приложение будет находиться в публичном доступе для любого, кто может подсоединиться к вашей машине. Продуктовые приложения запускаются именно так, например, с помощью контейнеров.
+По умолчанию авто-перезагрузка (**auto-reload**) отключена. Приложение слушает входящие подключения на IP `0.0.0.0`, т.е. на всех доступных адресах компьютера. Таким образом, приложение будет находиться в публичном доступе для любого, кто может подсоединиться к вашей машине. Продуктовые приложения запускаются именно так, например, с помощью контейнеров.
В большинстве случаев вы будете (и должны) использовать прокси-сервер ("termination proxy"), который будет поддерживать HTTPS поверх вашего приложения. Всё будет зависеть от того, как вы развертываете приложение: за вас это либо сделает ваш провайдер, либо вам придется сделать настройки самостоятельно.
/// tip | Подсказка
-Вы можете больше узнать об этом в документации по развертыванию приложений [deployment documentation](deployment/index.md){.internal-link target=_blank}.
+Вы можете больше узнать об этом в [документации по развертыванию](deployment/index.md){.internal-link target=_blank}.
///
-# Ð\9eÑ\81новнÑ\8bе Ñ\81войÑ\81Ñ\82ва
+# Ð\92озможноÑ\81Ñ\82и { #features }
-## Ð\9eÑ\81новнÑ\8bе Ñ\81войÑ\81Ñ\82ва FastAPI
+## Ð\92озможноÑ\81Ñ\82и FastAPI { #fastapi-features }
**FastAPI** предлагает вам следующее:
-### Ð\98Ñ\81полÑ\8cзование оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8bÑ\85 Ñ\81Ñ\82андаÑ\80Ñ\82ов
+### Ð\9eÑ\81новано на оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8bÑ\85 Ñ\81Ñ\82андаÑ\80Ñ\82аÑ\85 { #based-on-open-standards }
-* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> для создания API, включая объявления <abbr title="также известных, как HTTP-методы, такие, как: POST, GET, PUT, DELETE">операций</abbr> <abbr title="известные как: эндпоинты, маршруты, 'ручки' и т.п.">пути</abbr>, параметров, тела запроса, безопасности и т.д.
-
-
-* Автоматическое документирование моделей данных в соответствии с <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (так как спецификация OpenAPI сама основана на JSON Schema).
-* Разработан, придерживаясь этих стандартов, после тщательного их изучения. Эти стандарты изначально включены во фреймфорк, а не являются дополнительной надстройкой.
+* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> для создания API, включая объявления <abbr title="также известные как HTTP-методы, например: POST, GET, PUT, DELETE">операций</abbr> <abbr title="также известен как: эндпоинты, маршруты)">пути</abbr>, параметров, тел запросов, безопасности и т. д.
+* Автоматическая документация моделей данных с помощью <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (так как сама спецификация OpenAPI основана на JSON Schema).
+* Разработан вокруг этих стандартов, после тщательного их изучения. Это не дополнительная надстройка поверх.
* Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках.
-### Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80Ñ\83емаÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f
+### Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81каÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f { #automatic-docs }
-Интерактивная документация для API и исследования пользовательских веб-интерфейсов. Поскольку этот фреймворк основан на OpenAPI, существует несколько вариантов документирования, 2 из которых включены по умолчанию.
+Интерактивная документация для API и исследовательские веб-интерфейсы. Поскольку фреймворк основан на OpenAPI, существует несколько вариантов документирования, 2 из них включены по умолчанию.
-* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, Ñ\81 инÑ\82еÑ\80акÑ\82ивнÑ\8bм взаимодейÑ\81Ñ\82вием, вÑ\8bзÑ\8bваеÑ\82 и Ñ\82еÑ\81Ñ\82иÑ\80Ñ\83еÑ\82 ваÑ\88 API прямо из браузера.
+* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, Ñ\81 инÑ\82еÑ\80акÑ\82ивнÑ\8bм иÑ\81Ñ\81ледованием, вÑ\8bзовом и Ñ\82еÑ\81Ñ\82иÑ\80ованием ваÑ\88его API прямо из браузера.


-### Только современный Python
+### Только современный Python { #just-modern-python }
-Все эти возможности основаны на стандартных **аннотациях типов Python 3.8** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только лишь стандартный современный Python.
+Все основано на стандартных **аннотациях типов Python** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только стандартный современный Python.
-Если вам нужно освежить знания, как использовать аннотации типов в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Введение в аннотации типов Python¶
-](python-types.md){.internal-link target=_blank}.
+Если вам нужно освежить знания о типах в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Типы Python](python-types.md){.internal-link target=_blank}.
-Вы пишете на стандартном Python с аннотациями типов:
+Вы пишете стандартный Python с типами:
```Python
from datetime import date
from pydantic import BaseModel
-# Объявляем параметр user_id с типом `str`
-# и получаем поддержку редактора внутри функции
+# Объявляем параметр как `str`
+# и полÑ\83Ñ\87аем поддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а кода внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии
def main(user_id: str):
return user_id
`**second_user_data` означает:
-Передать ключи и значения словаря `second_user_data`, в качестве аргументов типа "ключ-значение", это эквивалентно: `User(id=4, name="Mary", joined="2018-11-30")` .
+Передать ключи и значения словаря `second_user_data` в качестве аргументов "ключ-значение", эквивалентно: `User(id=4, name="Mary", joined="2018-11-30")`
///
-### Поддержка редакторов (IDE)
+### Поддержка редакторов (IDE) { #editor-support }
Весь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода.
-Ð\92 опÑ\80оÑ\81е Python-Ñ\80азÑ\80абоÑ\82Ñ\87иков бÑ\8bло вÑ\8bÑ\8fÑ\81нено, <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">Ñ\87Ñ\82о наиболее Ñ\87аÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83емой Ñ\84Ñ\83нкÑ\86ией Ñ\80едакÑ\82оÑ\80ов, Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f "авÑ\82одополнение"</a>.
+Ð\92 опÑ\80оÑ\81аÑ\85 Pythonâ\80\91Ñ\80азÑ\80абоÑ\82Ñ\87иков видно, <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">Ñ\87Ñ\82о одной из Ñ\81амÑ\8bÑ\85 Ñ\87аÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83емÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f «авÑ\82озавеÑ\80Ñ\88ение»</a>.
-Ð\92Ñ\81Ñ\8f Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80а **FastAPI** оÑ\81нована на Ñ\83довлеÑ\82воÑ\80ении Ñ\8dÑ\82ой возможноÑ\81Ñ\82и. Ð\90вÑ\82одополнение работает везде.
+Ð\92Ñ\81Ñ\8f Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80а **FastAPI** оÑ\81нована на Ñ\83довлеÑ\82воÑ\80ении Ñ\8dÑ\82ой возможноÑ\81Ñ\82и. Ð\90вÑ\82озавеÑ\80Ñ\88ение работает везде.
Вам редко нужно будет возвращаться к документации.

-Вы будете получать автодополнение кода даже там, где вы считали это невозможным раньше.
-Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе.
+Вы будете получать автозавершение кода даже там, где вы считали это невозможным раньше. Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе.
+
+Больше никаких неправильных имён ключей, метания по документации или прокручивания кода вверх и вниз в попытках узнать — использовали вы ранее `username` или `user_name`.
-Больше никаких неправильных имён ключей, метания по документации или прокручивания кода вверх и вниз, в попытках узнать - использовали вы ранее `username` или `user_name`.
+### Краткость { #short }
-### Краткость
-FastAPI имеет продуманные значения **по умолчанию** для всего, с произвольными настройками везде. Все параметры могут быть тонко подстроены так, чтобы делать то, что вам нужно и определять необходимый вам API.
+FastAPI имеет продуманные значения **по умолчанию** для всего, с опциональными настройками везде. Все параметры могут быть тонко подстроены так, чтобы делать то, что вам нужно, и определять необходимый вам API.
-Но, по умолчанию, всё это **"и так работает"**.
+Но по умолчанию всё **«просто работает»**.
-### Проверка значений
+### Проверка значений { #validation }
-* Проверка значений для большинства (или всех?) **типов данных** Python, включая:
+* Проверка значений для большинства (или всех?) **типов данных** Python, включая:
* Объекты JSON (`dict`).
- * Массивы JSON (`list`) с установленными типами элементов.
+ * Массив JSON (`list`) с определёнными типами элементов.
* Строковые (`str`) поля с ограничением минимальной и максимальной длины.
- * Числа (`int`, `float`) с минимальными и максимальными значениями и т.п.
+ * Числа (`int`, `float`) с минимальными и максимальными значениями и т. п.
* Проверка для более экзотических типов, таких как:
* URL.
* UUID.
* ...и другие.
-Все проверки обрабатываются хорошо зарекомендовавшим себя и надежным **Pydantic**.
+Все проверки обрабатываются хорошо зарекомендовавшим себя и надёжным **Pydantic**.
-### Безопасность и аутентификация
+### Безопасность и аутентификация { #security-and-authentication }
-Встроеные функции безопасности и аутентификации. Без каких-либо компромиссов с базами данных или моделями данных.
+Встроенные функции безопасности и аутентификации. Без каких‑либо компромиссов с базами данных или моделями данных.
Все схемы безопасности, определённые в OpenAPI, включая:
Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т. д.
-### Внедрение зависимостей
+### Внедрение зависимостей { #dependency-injection }
FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему <abbr title='известную как: "components", "resources", "services", "providers"'><strong>Внедрения зависимостей</strong></abbr>.
-* Даже зависимости могут иметь зависимости, создавая иерархию или **"графы" зависимостей**.
+* Даже зависимости могут иметь зависимости, создавая иерархию или **«граф» зависимостей**.
* Всё **автоматически обрабатывается** фреймворком.
* Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией.
-* **Автоматическая проверка** даже для параметров *операций пути*, определенных в зависимостях.
-* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д.
-* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но легкая интеграция со всеми ними.
+* **Автоматическая проверка** даже для параметров *операций пути*, определённых в зависимостях.
+* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т. д.
+* **Никаких компромиссов** с базами данных, интерфейсами и т. д. Но при этом — лёгкая интеграция со всеми ними.
-### Нет ограничений на "Плагины"
+### Нет ограничений на "Плагины" { #unlimited-plug-ins }
-Или, другими словами, нет сложностей с ними, импортируйте и используйте нужный вам код.
+Или, другими словами, нет необходимости в них — просто импортируйте и используйте нужный вам код.
-Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать "плагин" для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*.
+Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать «плагин» для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*.
-### Проверен
+### Проверен { #tested }
-* 100% <abbr title="Количество автоматически проверямого кода">покрытие тестами</abbr>.
-* 100% <abbr title="Ð\90нноÑ\82аÑ\86ии Ñ\82ипов Python, благодаÑ\80Ñ\8f коÑ\82оÑ\80Ñ\8bм ваÑ\88 Ñ\80едакÑ\82оÑ\80 и дÑ\80Ñ\83гие инструменты могут обеспечить вам лучшую поддержку">аннотирование типов</abbr> в кодовой базе.
-* Используется в реально работающих приложениях.
+* 100% <abbr title="Ð\9aолиÑ\87еÑ\81Ñ\82во авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80овеÑ\80Ñ\8fемого кода">покÑ\80Ñ\8bÑ\82ие Ñ\82еÑ\81Ñ\82ами</abbr>.
+* 100% <abbr title="Ð\90нноÑ\82аÑ\86ии Ñ\82ипов Python, благодаÑ\80Ñ\8f коÑ\82оÑ\80Ñ\8bм ваÑ\88 Ñ\80едакÑ\82оÑ\80 и внеÑ\88ние инструменты могут обеспечить вам лучшую поддержку">аннотирование типов</abbr> в кодовой базе.
+* Используется в продакшн‑приложениях.
-## Ð\9eÑ\81новнÑ\8bе Ñ\81войÑ\81Ñ\82ва Starlette
+## Ð\92озможноÑ\81Ñ\82и Starlette { #starlette-features }
-**FastAPI** основан на <a href="https://www.starlette.io/" class="external-link" target="_blank"><strong>Starlette</strong></a> и полностью совместим с ним. Так что, любой дополнительный код Starlette, который у вас есть, будет также работать.
+**FastAPI** основан на <a href="https://www.starlette.io/" class="external-link" target="_blank"><strong>Starlette</strong></a> и полностью совместим с ним. Так что любой дополнительный код Starlette, который у вас есть, также будет работать.
-На самом деле, `FastAPI` - это класс, унаследованный от `Starlette`. Таким образом, если вы уже знаете или используете Starlette, большая часть функционала будет работать так же.
+На самом деле, `FastAPI` — это подкласс `Starlette`. Таким образом, если вы уже знаете или используете Starlette, большая часть функционала будет работать так же.
-С **FastAPI** вы получаете все возможности **Starlette** (так как FastAPI это всего лишь Starlette на стероидах):
+С **FastAPI** вы получаете все возможности **Starlette** (так как FastAPI — это всего лишь Starlette на стероидах):
-* Серьёзно впечатляющая производительность. Это <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">один из самых быстрых фреймворков на Python</a>, наравне с приложениями использующими **NodeJS** или **Go**.
+* Серьёзно впечатляющая производительность. Это <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">один из самых быстрых фреймворков на Python, наравне с **NodeJS** и **Go**</a>.
* Поддержка **WebSocket**.
-* ФоновÑ\8bе задаÑ\87и длÑ\8f пÑ\80оÑ\86еÑ\81Ñ\81ов.
+* ФоновÑ\8bе задаÑ\87и в Ñ\82ом же пÑ\80оÑ\86еÑ\81Ñ\81е.
* События запуска и выключения.
-* Тестовый клиент построен на библиотеке HTTPX.
+* Тестовый клиент построен на HTTPX.
* **CORS**, GZip, статические файлы, потоковые ответы.
* Поддержка **сессий и cookie**.
* 100% покрытие тестами.
* 100% аннотирование типов в кодовой базе.
-## Ð\9eÑ\81обенноÑ\81Ñ\82и и возможноÑ\81Ñ\82и Pydantic
+## Ð\92озможноÑ\81Ñ\82и Pydantic { #pydantic-features }
-**FastAPI** оÑ\81нован на <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a> и полноÑ\81Ñ\82Ñ\8cÑ\8e Ñ\81овмеÑ\81Ñ\82им Ñ\81 ним. Так Ñ\87Ñ\82о, лÑ\8eбой дополниÑ\82елÑ\8cнÑ\8bй код Pydantic, коÑ\82оÑ\80Ñ\8bй Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c, бÑ\83деÑ\82 Ñ\82акже работать.
+**FastAPI** полноÑ\81Ñ\82Ñ\8cÑ\8e Ñ\81овмеÑ\81Ñ\82им Ñ\81 (и оÑ\81нован на) <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>. Ð\9fоÑ\8dÑ\82омÑ\83 лÑ\8eбой дополниÑ\82елÑ\8cнÑ\8bй код Pydantic, коÑ\82оÑ\80Ñ\8bй Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c, Ñ\82акже бÑ\83деÑ\82 работать.
-Включая внешние библиотеки, также основанные на Pydantic, такие как: <abbr title="Object-Relational Mapper">ORM'ы</abbr>, <abbr title="Object-Document Mapper">ODM'ы</abbr> для баз данных.
+Включая внешние библиотеки, также основанные на Pydantic, такие как <abbr title="Object-Relational Mapper">ORM</abbr>’ы, <abbr title="Object-Document Mapper">ODM</abbr>’ы для баз данных.
Это также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически.
И наоборот, во многих случаях вы можете просто передать объект, полученный из базы данных, **непосредственно клиенту**.
-С **FastAPI** вы получаете все возможности **Pydantic** (так как, FastAPI основан на Pydantic, для обработки данных):
-
-* **Никакой нервотрёпки** :
- * Не нужно изучать новых схем в микроязыках.
- * Если вы знаете аннотации типов в Python, вы знаете, как использовать Pydantic.
-* Прекрасно сочетается с вашими **<abbr title="Интегрированное окружение для разработки, похожее на текстовый редактор">IDE</abbr>/<abbr title="программа проверяющая ошибки в коде">linter</abbr>/мозгом**:
- * Потому что структуры данных pydantic - это всего лишь экземпляры классов, определённых вами. Автодополнение, проверка кода, mypy и ваша интуиция - всё будет работать с вашими проверенными данными.
-* Ð\9fÑ\80овеÑ\80ка **сложных структур**:
- * Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python).
- * Валидаторы позволяют четко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema.
- * У вас могут быть глубоко **вложенные объекты JSON** и все они будут проверены и аннотированы.
+С **FastAPI** вы получаете все возможности **Pydantic** (так как FastAPI основан на Pydantic для обработки данных):
+
+* **Никакой нервотрёпки**:
+ * Не нужно изучать новые схемы в микроязыках.
+ * Если вы знаете типы в Python, вы знаете, как использовать Pydantic.
+* Прекрасно сочетается с вашим **<abbr title="Integrated Development Environment - Интегрированная среда разработки: попросту «редактора кода»">IDE</abbr>/<abbr title="Программа, проверяющая ошибки в коде">linter</abbr>/мозгом**:
+ * Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными.
+* Ð\92алидаÑ\86иÑ\8f **сложных структур**:
+ * Использование иерархических моделей Pydantic; `List`, `Dict` и т. п. из модуля `typing` (входит в стандартную библиотеку Python).
+ * Валидаторы позволяют чётко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema.
+ * У вас могут быть глубоко **вложенные объекты JSON**, и все они будут проверены и аннотированы.
* **Расширяемость**:
- * Pydantic позволяет определять пользовательские типы данных или расширять проверку методами модели, с помощью проверочных декораторов.
+ * Pydantic позволяет определять пользовательские типы данных или расширять проверку методами модели с помощью декораторов валидаторов.
* 100% покрытие тестами.
-# Помочь FastAPI - Получить помощь
+# Помочь FastAPI - Получить помощь { #help-fastapi-get-help }
Нравится ли Вам **FastAPI**?
-ХоÑ\82ели бÑ\8b Ð\92Ñ\8b помоÑ\87Ñ\8c FastAPI, его пользователям и автору?
+ХоÑ\82ели бÑ\8b Ð\92Ñ\8b помоÑ\87Ñ\8c FastAPI, дÑ\80Ñ\83гим пользователям и автору?
-Ð\9cожеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\83 Ð\92аÑ\81 возникли Ñ\82Ñ\80Ñ\83дноÑ\81Ñ\82и Ñ\81 **FastAPI** и Ð\92ам нÑ\83жна помоÑ\89Ñ\8c?
+Ð\98ли Ð\92Ñ\8b Ñ\85оÑ\82иÑ\82е полÑ\83Ñ\87иÑ\82Ñ\8c помоÑ\89Ñ\8c по **FastAPI**?
-Ð\95Ñ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82Ñ\8bÑ\85 Ñ\81поÑ\81обов оказаниÑ\8f помоÑ\89и (иногда доÑ\81Ñ\82аÑ\82оÑ\87но вÑ\81его лиÑ\88Ñ\8c одного или двух кликов).
+Ð\95Ñ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82Ñ\8bÑ\85 Ñ\81поÑ\81обов помоÑ\87Ñ\8c (иногда доÑ\81Ñ\82аÑ\82оÑ\87но вÑ\81его лиÑ\88Ñ\8c одного-двух кликов).
И также есть несколько способов получить помощь.
-## Подписаться на новостную рассылку
+## Подписаться на новостную рассылку { #subscribe-to-the-newsletter }
Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md){.internal-link target=_blank} и быть в курсе о:
* Новостях о FastAPI и его друзьях 🚀
* Руководствах 📝
* Возможностях ✨
-* Ð\98Ñ\81пÑ\80авлениях 🚨
+* Ð\9bомаÑ\8eÑ\89иÑ\85 изменениях 🚨
* Подсказках и хитростях ✅
-## Подписаться на FastAPI в X (Twitter)
+## Подписаться на FastAPI в X (Twitter) { #follow-fastapi-on-x-twitter }
<a href="https://x.com/fastapi" class="external-link" target="_blank">Подписаться на @fastapi в **X (Twitter)**</a> для получения наисвежайших новостей о **FastAPI**. 🐦
-## Добавить **FastAPI** звезду на GitHub
+## Добавить **FastAPI** звезду на GitHub { #star-fastapi-in-github }
-Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️
+Вы можете добавить FastAPI "звезду" на GitHub (кликнув на кнопку звезды в правом верхнем углу): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️
-Чем болÑ\8cÑ\88е звÑ\91зд, Ñ\82ем легÑ\87е дÑ\80Ñ\83гим полÑ\8cзоваÑ\82елÑ\8fм найÑ\82и наÑ\81 и Ñ\83видеÑ\82Ñ\8c, Ñ\87Ñ\82о пÑ\80оекÑ\82 Ñ\83же Ñ\81Ñ\82ал полезным для многих.
+Чем болÑ\8cÑ\88е звÑ\91зд, Ñ\82ем легÑ\87е дÑ\80Ñ\83гим полÑ\8cзоваÑ\82елÑ\8fм найÑ\82и пÑ\80оекÑ\82 и Ñ\83видеÑ\82Ñ\8c, Ñ\87Ñ\82о он Ñ\83же оказалÑ\81Ñ\8f полезным для многих.
-## Отслеживать свежие выпуски в репозитории на GitHub
+## Отслеживать свежие выпуски в репозитории на GitHub { #watch-the-github-repository-for-releases }
-Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
+Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
-Там же Вы можете указать в настройках - "Releases only".
+Там же Вы можете выбрать "Releases only".
С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.
-## Связаться с автором
+## Связаться с автором { #connect-with-the-author }
-Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себястьян Рамирез / `tiangolo`)</a>, автором FastAPI.
+Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Sebastián Ramírez / `tiangolo`)</a>, автором.
Вы можете:
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Подписаться на меня на **GitHub**</a>.
* Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
- * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
+ * Подписаться, чтобы видеть, когда я создаю новый проект с открытым кодом.
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">Подписаться на меня в **X (Twitter)**</a> или в <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>.
- * Ð\9fоделиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81о мной, как Ð\92Ñ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е FastAPI (Ñ\8f обожаÑ\8e Ñ\87иÑ\82аÑ\82Ñ\8c пÑ\80о Ñ\8dÑ\82о).
- * Ð\9fолÑ\83Ñ\87аÑ\82Ñ\8c Ñ\83ведомлениÑ\8f, когда Ñ\8f делаÑ\8e обÑ\8aÑ\8fвлениÑ\8f и пÑ\80едÑ\81Ñ\82авлÑ\8fю новые инструменты.
+ * Ð\9fоделиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81о мной, как Ð\92Ñ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е FastAPI (Ñ\8f обожаÑ\8e Ñ\8dÑ\82о Ñ\87иÑ\82аÑ\82Ñ\8c).
+ * УзнаваÑ\82Ñ\8c, когда Ñ\8f делаÑ\8e обÑ\8aÑ\8fвлениÑ\8f или вÑ\8bпÑ\83Ñ\81каю новые инструменты.
* Вы также можете <a href="https://x.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в X (Twitter)</a> (это отдельный аккаунт).
-* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **Linkedin**</a>.
- * Ð\9fолÑ\83Ñ\87аÑ\82Ñ\8c Ñ\83ведомлениÑ\8f, когда Ñ\8f делаÑ\8e обÑ\8aÑ\8fвлениÑ\8f и пÑ\80едÑ\81Ñ\82авлÑ\8fÑ\8e новÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b (пÑ\80авда Ñ\87аÑ\89е вÑ\81его я использую X (Twitter) 🤷♂).
-* ЧиÑ\82аÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\8f пиÑ\88Ñ\83 (или подпиÑ\81аÑ\82Ñ\8cÑ\81Ñ\8f на менÑ\8f) в <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или в <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
- * Читать другие идеи, статьи и читать об инструментах созданных мной.
- * Ð\9fодпиÑ\88иÑ\82еÑ\81Ñ\8c на менÑ\8f, Ñ\87Ñ\82обÑ\8b пÑ\80оÑ\87иÑ\82аÑ\82Ñ\8c, когда Ñ\8f опÑ\83бликÑ\83Ñ\8e Ñ\87Ñ\82о-нибÑ\83дÑ\8c новое.
+* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **LinkedIn**</a>.
+ * УзнаваÑ\82Ñ\8c, когда Ñ\8f делаÑ\8e обÑ\8aÑ\8fвлениÑ\8f или вÑ\8bпÑ\83Ñ\81каÑ\8e новÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b (Ñ\85оÑ\82Ñ\8f Ñ\87аÑ\89е я использую X (Twitter) 🤷♂).
+* ЧиÑ\82аÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\8f пиÑ\88Ñ\83 (или подпиÑ\81аÑ\82Ñ\8cÑ\81Ñ\8f на менÑ\8f) на <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
+ * Читать другие идеи, статьи и о созданных мной инструментах.
+ * Ð\9fодпиÑ\81аÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82обÑ\8b Ñ\87иÑ\82аÑ\82Ñ\8c, когда Ñ\8f пÑ\83бликÑ\83Ñ\8e Ñ\87Ñ\82о-Ñ\82о новое.
-## Оставить сообщение в X (Twitter) о **FastAPI**
+## Оставить сообщение в X (Twitter) о **FastAPI** { #tweet-about-fastapi }
-<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в X (Twitter) о **FastAPI**</a> и позвольте мне и другим узнать - почему он Вам нравится. 🎉
+<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в X (Twitter) о **FastAPI**</a> и позвольте мне и другим узнать, почему он Вам нравится. 🎉
-Я лÑ\8eблÑ\8e Ñ\83знаваÑ\82Ñ\8c о Ñ\82ом, как **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f, Ñ\87Ñ\82о Ð\92ам понÑ\80авилоÑ\81Ñ\8c в нÑ\91м, в какиÑ\85 пÑ\80оекÑ\82аÑ\85/компаниÑ\8fÑ\85 Ð\92Ñ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е его и Ñ\82.п.
+Я лÑ\8eблÑ\8e Ñ\83знаваÑ\82Ñ\8c о Ñ\82ом, как **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f, Ñ\87Ñ\82о Ð\92ам понÑ\80авилоÑ\81Ñ\8c в нÑ\91м, в какиÑ\85 пÑ\80оекÑ\82аÑ\85/компаниÑ\8fÑ\85 Ð\92Ñ\8b его иÑ\81полÑ\8cзÑ\83еÑ\82е и Ñ\82.д.
-## Оставить голос за FastAPI
+## Оставить голос за FastAPI { #vote-for-fastapi }
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Голосуйте за **FastAPI** в Slant</a>.
-* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>.
-* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, как Вы используете **FastAPI** на StackShare</a>.
+* <a href="https://alternativeto.net/software/fastapi/about/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>.
+* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, что Вы используете **FastAPI** на StackShare</a>.
-## Ð\9fомоÑ\87Ñ\8c дÑ\80Ñ\83гим Ñ\81 иÑ\85 пÑ\80облемами на GitHub
+## Ð\9fомоÑ\87Ñ\8c дÑ\80Ñ\83гим Ñ\81 вопÑ\80оÑ\81ами на GitHub { #help-others-with-questions-in-github }
-Вы можете посмотреть, какие <a href="https://github.com/fastapi/fastapi/issues" class="external-link" target="_blank">проблемы</a> испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓
+Вы можете попробовать помочь другим с их вопросами в:
-Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. 🎉
+* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
+* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
-ТолÑ\8cко помниÑ\82е, Ñ\81амое важное пÑ\80и Ñ\8dÑ\82ом - добÑ\80оÑ\82а. СÑ\82олкнÑ\83вÑ\88иÑ\81Ñ\8c Ñ\81 пÑ\80облемой, лÑ\8eди Ñ\80аÑ\81Ñ\81Ñ\82Ñ\80аиваÑ\8eÑ\82Ñ\81Ñ\8f и Ñ\87аÑ\81Ñ\82о задаÑ\8eÑ\82 вопÑ\80оÑ\81Ñ\8b не лÑ\83Ñ\87Ñ\88им обÑ\80азом, но поÑ\81Ñ\82аÑ\80айÑ\82еÑ\81Ñ\8c бÑ\8bÑ\82Ñ\8c макÑ\81ималÑ\8cно добÑ\80ожелаÑ\82елÑ\8cнÑ\8bм. ð\9f¤\97
+Ð\92о многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 Ð\92Ñ\8b Ñ\83же можеÑ\82е знаÑ\82Ñ\8c оÑ\82веÑ\82Ñ\8b на Ñ\8dÑ\82и вопÑ\80оÑ\81Ñ\8b. ð\9f¤\93
-Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
+Если Вы много помогаете людям с их вопросами, Вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉
+
+Только помните, самое важное — постарайтесь быть добрыми. Люди приходят со своими разочарованиями и часто задают вопросы не лучшим образом, но постарайтесь, насколько можете, быть доброжелательными. 🤗
+
+Идея сообщества **FastAPI** — быть доброжелательным и гостеприимным. В то же время не допускайте травлю или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге.
---
-Ð\9aак помоÑ\87Ñ\8c дÑ\80Ñ\83гим Ñ\81 иÑ\85 пÑ\80облемами:
+Ð\9aак помоÑ\87Ñ\8c дÑ\80Ñ\83гим Ñ\81 вопÑ\80оÑ\81ами (в обÑ\81Ñ\83ждениÑ\8fÑ\85 или Issues):
-### Понять вопрос
+### Понять вопрос { #understand-the-question }
-* УдоÑ\81Ñ\82овеÑ\80Ñ\8cÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о понÑ\8fли **Ñ\86елÑ\8c** и обÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cÑ\81Ñ\82ва Ñ\81лÑ\83Ñ\87аÑ\8f вопÑ\80оÑ\88аÑ\8eÑ\89его.
+* УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о понÑ\8fли **Ñ\86елÑ\8c** и кейÑ\81 иÑ\81полÑ\8cзованиÑ\8f задаÑ\8eÑ\89его вопÑ\80оÑ\81.
-* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
+* Затем проверьте, что вопрос (в подавляющем большинстве это вопросы) сформулирован **ясно**.
-* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
+* Во многих случаях спрашивают о воображаемом решении пользователя, но может быть решение **получше**. Если Вы лучше поймёте проблему и кейс, сможете предложить **альтернативное решение**.
-* Ежели вопрос Вам непонятен, запросите больше **деталей**.
+* Если вопрос непонятен, запросите больше **деталей**.
-### Воспроизвести проблему
+### Воспроизвести проблему { #reproduce-the-problem }
-Ð\92 болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев еÑ\81Ñ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о Ñ\81вÑ\8fзанное Ñ\81 **иÑ\81Ñ\85однÑ\8bм кодом** вопÑ\80оÑ\88аÑ\8eÑ\89его.
+Ð\92 болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев и вопÑ\80оÑ\81ов еÑ\81Ñ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о Ñ\81вÑ\8fзанное Ñ\81 **иÑ\81Ñ\85однÑ\8bм кодом** авÑ\82оÑ\80а.
-Ð\98 во многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 бÑ\83деÑ\82 пÑ\80едоÑ\81Ñ\82авлен Ñ\82олÑ\8cко Ñ\84Ñ\80агменÑ\82 Ñ\8dÑ\82ого кода, коÑ\82оÑ\80ого недоÑ\81Ñ\82аÑ\82оÑ\87но длÑ\8f **воÑ\81пÑ\80оизведениÑ\8f пÑ\80облемÑ\8b**.
+Ð\92о многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 пÑ\80едоÑ\81Ñ\82авлÑ\8fÑ\8eÑ\82 Ñ\82олÑ\8cко Ñ\84Ñ\80агменÑ\82 кода, но Ñ\8dÑ\82ого недоÑ\81Ñ\82аÑ\82оÑ\87но, Ñ\87Ñ\82обÑ\8b **воÑ\81пÑ\80оизвеÑ\81Ñ\82и пÑ\80облемÑ\83**.
-* Ð\9fопÑ\80оÑ\81иÑ\82е пÑ\80едоÑ\81Ñ\82авиÑ\82Ñ\8c <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минималÑ\8cнÑ\8bй воÑ\81пÑ\80оизводимÑ\8bй пÑ\80имеÑ\80</a>, коÑ\82оÑ\80Ñ\8bй можно **Ñ\81копиÑ\80оваÑ\82Ñ\8c** и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c локалÑ\8cно дабÑ\8b Ñ\83видеÑ\82Ñ\8c Ñ\82акÑ\83Ñ\8e же оÑ\88ибкÑ\83, или поведение, или лÑ\83Ñ\87Ñ\88е понÑ\8fÑ\82Ñ\8c обÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cÑ\81Ñ\82ва Ñ\81лÑ\83Ñ\87аÑ\8f.
+* Ð\9fопÑ\80оÑ\81иÑ\82е пÑ\80едоÑ\81Ñ\82авиÑ\82Ñ\8c <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минималÑ\8cнÑ\8bй воÑ\81пÑ\80оизводимÑ\8bй пÑ\80имеÑ\80</a>, коÑ\82оÑ\80Ñ\8bй Ð\92Ñ\8b Ñ\81можеÑ\82е **Ñ\81копиÑ\80оваÑ\82Ñ\8c-вÑ\81Ñ\82авиÑ\82Ñ\8c** и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c локалÑ\8cно, Ñ\87Ñ\82обÑ\8b Ñ\83видеÑ\82Ñ\8c Ñ\82Ñ\83 же оÑ\88ибкÑ\83 или поведение, или лÑ\83Ñ\87Ñ\88е понÑ\8fÑ\82Ñ\8c иÑ\85 кейÑ\81.
-* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
+* Если чувствуете себя особенно великодушными, можете попытаться **создать такой пример** сами, основываясь только на описании проблемы. Просто помните, что это может занять много времени, и, возможно, сначала лучше попросить уточнить проблему.
-### Предложить решение
+### Предложить решение { #suggest-solutions }
-* После того как Вы поняли вопрос, Вы можете дать **ответ**.
+* После того как Вы поняли вопрос, Вы можете дать возможный **ответ**.
-* СледÑ\83еÑ\82 понÑ\8fÑ\82Ñ\8c **оÑ\81новнÑ\83Ñ\8e пÑ\80облемÑ\83 и обÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cÑ\81Ñ\82ва Ñ\81лÑ\83Ñ\87аÑ\8f**, поÑ\82омÑ\83 Ñ\87Ñ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\80еÑ\88ение лÑ\83Ñ\87Ñ\88е, Ñ\87ем Ñ\82о, коÑ\82оÑ\80ое пÑ\8bÑ\82алиÑ\81Ñ\8c Ñ\80еализовать.
+* Ð\92о многиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 лÑ\83Ñ\87Ñ\88е понÑ\8fÑ\82Ñ\8c **иÑ\81Ñ\85однÑ\83Ñ\8e пÑ\80облемÑ\83 или кейÑ\81**, поÑ\82омÑ\83 Ñ\87Ñ\82о можеÑ\82 Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82воваÑ\82Ñ\8c Ñ\81поÑ\81об Ñ\80еÑ\88иÑ\82Ñ\8c еÑ\91 лÑ\83Ñ\87Ñ\88е, Ñ\87ем Ñ\82о, Ñ\87Ñ\82о пÑ\8bÑ\82аÑ\8eÑ\82Ñ\81Ñ\8f Ñ\81делать.
-### Попросить закрыть проблему
+### Попросить закрыть { #ask-to-close }
-Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
+Если Вам ответили, велика вероятность, что Вы решили их проблему, поздравляю, **Вы — герой**! 🦸
-* В таком случае, если вопрос решён, попросите **закрыть проблему**.
+* Теперь, если проблема решена, можно попросить их:
+ * В GitHub Discussions: пометить комментарий как **answer** (ответ).
+ * В GitHub Issues: **закрыть** Issue.
-## Отслеживать репозиторий на GitHub
+## Отслеживать репозиторий на GitHub { #watch-the-github-repository }
-Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
+Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
-Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы.
+Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления, когда кто-либо создаёт новый вопрос или Issue. Вы также можете указать, что хотите получать уведомления только о новых Issues, или обсуждениях, или пулл-реквестах и т.д.
-Тогда Вы можете попробовать решить эту проблему.
+Тогда Вы можете попробовать помочь им с решением этих вопросов.
-## Ð\97апÑ\80оÑ\81иÑ\82Ñ\8c помоÑ\89Ñ\8c Ñ\81 Ñ\80еÑ\88ением пÑ\80облемÑ\8b
+## Ð\97адаÑ\82Ñ\8c вопÑ\80оÑ\81Ñ\8b { #ask-questions }
-Вы можете <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">создать новый запрос с просьбой о помощи</a> в репозитории на GitHub, например:
+Вы можете <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">создать новый вопрос</a> в репозитории GitHub, например:
-* Задать **вопрос** или попросить помощи в решении **проблемы**.
-* Предложить новое **улучшение**.
+* Задать **вопрос** или спросить о **проблеме**.
+* Предложить новую **возможность**.
-**Ð\97амеÑ\82ка**: Ð\95Ñ\81ли Ð\92Ñ\8b Ñ\81оздаÑ\91Ñ\82е подобнÑ\8bе запÑ\80оÑ\81Ñ\8b, Ñ\82о Ñ\8f попÑ\80оÑ\88Ñ\83 Ð\92аÑ\81 Ñ\82акже оказÑ\8bваÑ\82Ñ\8c аналогиÑ\87нÑ\83Ñ\8e помоÑ\89ь другим. 😉
+**Ð\97амеÑ\82ка**: еÑ\81ли Ð\92Ñ\8b Ñ\8dÑ\82о Ñ\81делаеÑ\82е, Ñ\82о Ñ\8f попÑ\80оÑ\88Ñ\83 Ð\92аÑ\81 Ñ\82акже помогаÑ\82ь другим. 😉
-## Проверять пул-реквесты
+## Проверять пулл-реквесты { #review-pull-requests }
-Вы можете помочь мне проверять пул-реквесты других участников.
+Вы можете помочь мне проверять пулл-реквесты других участников.
-И повторюсь, постарайтесь быть доброжелательным. 🤗
+И, снова, постарайтесь быть доброжелательными. 🤗
---
-Ð\9e Ñ\82ом, Ñ\87Ñ\82о нÑ\83жно имеÑ\82Ñ\8c в видÑ\83 пÑ\80и пÑ\80овеÑ\80ке пÑ\83л-Ñ\80еквеÑ\81Ñ\82ов:
+Ð\9e Ñ\82ом, Ñ\87Ñ\82о нÑ\83жно имеÑ\82Ñ\8c в видÑ\83 и как пÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c пÑ\83лл-Ñ\80еквеÑ\81Ñ\82:
-### Понять проблему
+### Понять проблему { #understand-the-problem }
-* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение.
+* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Возможно, это обсуждалось более подробно в GitHub Discussion или Issue.
-* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт.
+* Также есть вероятность, что пулл-реквест не нужен, так как проблему можно решить **другим путём**. Тогда Вы можете предложить или спросить об этом.
-### Не переживайте о стиле
+### Не переживайте о стиле { #dont-worry-about-style }
-* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную.
+* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах — при слиянии я выполню squash и настрою коммит вручную.
-* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты.
+* Также не беспокойтесь о правилах стиля, это уже проверяют автоматизированные инструменты.
-Ð\98 еÑ\81ли вÑ\81Ñ\91 же поÑ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f какой-Ñ\82о дÑ\80Ñ\83гой Ñ\81Ñ\82илÑ\8c, Ñ\8f попÑ\80оÑ\88Ñ\83 Ð\92аÑ\81 об Ñ\8dÑ\82ом напÑ\80Ñ\8fмÑ\83Ñ\8e или добавлÑ\8e Ñ\81ам коммиÑ\82Ñ\8b Ñ\81 необÑ\85одимыми изменениями.
+Ð\95Ñ\81ли бÑ\83деÑ\82 нÑ\83жна какаÑ\8f-Ñ\82о дÑ\80Ñ\83гаÑ\8f Ñ\81Ñ\82илиÑ\81Ñ\82ика или единообÑ\80азие, Ñ\8f попÑ\80оÑ\88Ñ\83 об Ñ\8dÑ\82ом напÑ\80Ñ\8fмÑ\83Ñ\8e или добавлÑ\8e повеÑ\80Ñ\85 Ñ\81вои коммиÑ\82Ñ\8b Ñ\81 нÑ\83жными изменениями.
-### Проверить код
+### Проверить код { #check-the-code }
-* Ð\9fÑ\80овеÑ\80Ñ\8cÑ\82е и пÑ\80оÑ\87иÑ\82айÑ\82е код, поÑ\81моÑ\82Ñ\80иÑ\82е, какой он имееÑ\82 Ñ\81мÑ\8bÑ\81л, **запÑ\83Ñ\81Ñ\82иÑ\82е его локалÑ\8cно** и поÑ\81моÑ\82Ñ\80иÑ\82е, дейÑ\81Ñ\82виÑ\82елÑ\8cно ли он Ñ\80еÑ\88аеÑ\82 поÑ\81Ñ\82авленнÑ\83Ñ\8e задаÑ\87у.
+* Ð\9fÑ\80овеÑ\80Ñ\8cÑ\82е и пÑ\80оÑ\87иÑ\82айÑ\82е код, поÑ\81моÑ\82Ñ\80иÑ\82е, логиÑ\87ен ли он, **запÑ\83Ñ\81Ñ\82иÑ\82е его локалÑ\8cно** и пÑ\80овеÑ\80Ñ\8cÑ\82е, дейÑ\81Ñ\82виÑ\82елÑ\8cно ли он Ñ\80еÑ\88аеÑ\82 пÑ\80облему.
-* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код.
+* Затем оставьте **комментарий**, что Вы это сделали, так я пойму, что Вы действительно проверили код.
/// info | Информация
-К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений.
+К сожалению, я не могу просто доверять PR-ам только потому, что у них есть несколько одобрений.
-Ð\91Ñ\8bвали Ñ\81лÑ\83Ñ\87аи, Ñ\87Ñ\82о пÑ\83л-Ñ\80еквеÑ\81Ñ\82Ñ\8b имели 3, 5 или болÑ\8cÑ\88е одобÑ\80ений, веÑ\80оÑ\8fÑ\82но из-за пÑ\80ивлекаÑ\82елÑ\8cного опиÑ\81аниÑ\8f, но когда Ñ\8f пÑ\80овеÑ\80Ñ\8fл Ñ\8dÑ\82и пÑ\83л-Ñ\80еквеÑ\81Ñ\82Ñ\8b, они оказÑ\8bвалиÑ\81Ñ\8c Ñ\81ломанÑ\8b, Ñ\81одеÑ\80жали оÑ\88ибки или вовÑ\81е не Ñ\80еÑ\88али пÑ\80облемÑ\83, коÑ\82оÑ\80Ñ\83Ñ\8e, как они Ñ\83Ñ\82веÑ\80ждали, должнÑ\8b бÑ\8bли Ñ\80еÑ\88иÑ\82Ñ\8c. 😅
+Ð\9dеÑ\81колÑ\8cко Ñ\80аз бÑ\8bло Ñ\82ак, Ñ\87Ñ\82о Ñ\83 PR-ов бÑ\8bло 3, 5 или болÑ\8cÑ\88е одобÑ\80ений, веÑ\80оÑ\8fÑ\82но из-за пÑ\80ивлекаÑ\82елÑ\8cного опиÑ\81аниÑ\8f, но когда Ñ\8f иÑ\85 пÑ\80овеÑ\80Ñ\8fл, они оказÑ\8bвалиÑ\81Ñ\8c Ñ\81ломаннÑ\8bми, Ñ\81одеÑ\80жали баги или вовÑ\81е не Ñ\80еÑ\88али заÑ\8fвленнÑ\83Ñ\8e пÑ\80облемÑ\83. 😅
-Ð\9fоÑ\82омÑ\83 Ñ\8dÑ\82о дейÑ\81Ñ\82виÑ\82елÑ\8cно важно - пÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c и запÑ\83Ñ\81каÑ\82Ñ\8c код, и комменÑ\82аÑ\80ием Ñ\83ведомлÑ\8fÑ\82Ñ\8c менÑ\8f, Ñ\87Ñ\82о Ð\92Ñ\8b пÑ\80оделали Ñ\8dÑ\82и дейÑ\81Ñ\82виÑ\8f. 🤓
+Ð\9fоÑ\8dÑ\82омÑ\83 оÑ\87енÑ\8c важно дейÑ\81Ñ\82виÑ\82елÑ\8cно пÑ\80оÑ\87иÑ\82аÑ\82Ñ\8c и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c код и Ñ\81ообÑ\89иÑ\82Ñ\8c мне об Ñ\8dÑ\82ом в комменÑ\82аÑ\80ии. 🤓
///
-* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах.
+* Если PR можно упростить, Вы можете попросить об этом, но не нужно быть слишком придирчивым — может быть много субъективных мнений (и у меня тоже 🙈), поэтому лучше сосредоточиться на фундаментальных вещах.
-### Тестировать
+### Тестировать { #tests }
-* Помогите мне проверить, что у пул-реквеста есть **тесты**.
+* Помогите мне проверить, что у PR есть **тесты**.
-* Проверьте, что тесты **падали** до пул-реквеста. 🚨
+* Проверьте, что тесты **падают** до PR. 🚨
-* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅
+* Затем проверьте, что тесты **проходят** после PR. ✅
-* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим.
+* Многие PR не имеют тестов — Вы можете **напомнить** добавить тесты или даже **предложить** некоторые тесты сами. Это одна из самых трудозатратных частей, и здесь Вы можете очень помочь.
-* Ð\97аÑ\82ем добавÑ\8cÑ\82е комменÑ\82аÑ\80ий, Ñ\87Ñ\82о Ð\92Ñ\8b иÑ\81пÑ\80обовали в Ñ\85оде пÑ\80овеÑ\80ки. Таким обÑ\80азом Ñ\8f бÑ\83дÑ\83 знаÑ\82Ñ\8c, как Ð\92Ñ\8b пÑ\80оизвели пÑ\80овеÑ\80кÑ\83. 🤓
+* Ð\97аÑ\82ем добавÑ\8cÑ\82е комменÑ\82аÑ\80ий, Ñ\87Ñ\82о Ð\92Ñ\8b попÑ\80обовали, Ñ\87Ñ\82обÑ\8b Ñ\8f знал, Ñ\87Ñ\82о Ð\92Ñ\8b Ñ\8dÑ\82о пÑ\80овеÑ\80или. 🤓
-## Создать пул-реквест
+## Создать пулл-реквест { #create-a-pull-request }
-Ð\92Ñ\8b можеÑ\82е [Ñ\81делаÑ\82Ñ\8c вклад](contributing.md){.internal-link target=_blank} в код Ñ\84Ñ\80еймвоÑ\80ка иÑ\81полÑ\8cзÑ\83Ñ\8f пÑ\83л-Ñ\80еквеÑ\81Ñ\82Ñ\8b, например:
+Ð\92Ñ\8b можеÑ\82е [Ñ\81делаÑ\82Ñ\8c вклад](contributing.md){.internal-link target=_blank} в иÑ\81Ñ\85однÑ\8bй код пÑ\83лл-Ñ\80еквеÑ\81Ñ\82ами, например:
-* Ð\98Ñ\81пÑ\80авиÑ\82Ñ\8c опеÑ\87аÑ\82кÑ\83, коÑ\82оÑ\80Ñ\83Ñ\8e Ð\92Ñ\8b наÑ\88ли в документации.
-* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>.
- * УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о Ð\92Ñ\8b добавили Ñ\81воÑ\8e Ñ\81Ñ\81Ñ\8bлкÑ\83 в наÑ\87ало Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89его Ñ\80аздела.
-* Помочь с [переводом документации](contributing.md#_8){.internal-link target=_blank} на Ваш язык.
- * Вы также можете проверять переводы сделанные другими.
+* Ð\98Ñ\81пÑ\80авиÑ\82Ñ\8c опеÑ\87аÑ\82кÑ\83, найденнÑ\83Ñ\8e в документации.
+* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли, <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>.
+ * Убедитесь, что добавили свою ссылку в начало соответствующего раздела.
+* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык.
+ * Вы также можете проверять переводы, сделанные другими.
* Предложить новые разделы документации.
-* Исправить существующуе проблемы/баги.
+* Исправить существующую проблему/баг.
* Убедитесь, что добавили тесты.
* Добавить новую возможность.
* Убедитесь, что добавили тесты.
- * Убедитесь, что добавили документацию, если она необходима.
+ * Убедитесь, что добавили документацию, если это уместно.
-## Помочь поддерживать FastAPI
+## Помочь поддерживать FastAPI { #help-maintain-fastapi }
Помогите мне поддерживать **FastAPI**! 🤓
-Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать.
+Предстоит ещё много работы, и, по большей части, **ВЫ** можете её сделать.
Основные задачи, которые Вы можете выполнить прямо сейчас:
-* [Ð\9fомоÑ\87Ñ\8c дÑ\80Ñ\83гим Ñ\81 иÑ\85 пÑ\80облемами на GitHub](#github_1){.internal-link target=_blank} (Ñ\81моÑ\82Ñ\80иÑ\82е вÑ\8bÑ\88еÑ\81Ñ\82оÑ\8fÑ\89Ñ\83Ñ\8e Ñ\81екÑ\86иÑ\8e).
-* [Проверить пул-реквесты](#-){.internal-link target=_blank} (смотрите вышестоящую секцию).
+* [Ð\9fомоÑ\87Ñ\8c дÑ\80Ñ\83гим Ñ\81 вопÑ\80оÑ\81ами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (Ñ\81моÑ\82Ñ\80иÑ\82е Ñ\81екÑ\86иÑ\8e вÑ\8bÑ\88е).
+* [Проверять пулл-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите секцию выше).
-ÐÑ\82и две задаÑ\87и **оÑ\82нимают больше всего времени**. Это основная работа по поддержке FastAPI.
+Ð\98менно Ñ\8dÑ\82и две задаÑ\87и **забиÑ\80ают больше всего времени**. Это основная работа по поддержке FastAPI.
-Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
+Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и делаете так, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
-## Подключиться к чату
+## Подключиться к чату { #join-the-chat }
-Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank"> чату в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI.
+Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">серверу чата в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI.
/// tip | Подсказка
-Ð\92опÑ\80оÑ\81Ñ\8b по пÑ\80облемам Ñ\81 Ñ\84Ñ\80еймвоÑ\80ком лÑ\83Ñ\87Ñ\88е задаваÑ\82Ñ\8c в <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, Ñ\82ак болÑ\8cÑ\88е Ñ\88анÑ\81ов, Ñ\87Ñ\82о Ð\92Ñ\8b полÑ\83Ñ\87иÑ\82е помоÑ\89Ñ\8c оÑ\82 [ÐкÑ\81пеÑ\80Ñ\82ов FastAPI](fastapi-people.md#_3){.internal-link target=_blank}.
+Ð\9fо вопÑ\80оÑ\81ам â\80\94 задавайÑ\82е иÑ\85 в <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>, Ñ\82ак гоÑ\80аздо вÑ\8bÑ\88е Ñ\88анÑ\81, Ñ\87Ñ\82о Ð\92Ñ\8b полÑ\83Ñ\87иÑ\82е помоÑ\89Ñ\8c оÑ\82 [ÐкÑ\81пеÑ\80Ñ\82ов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}.
-Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е Ñ\8dÑ\82оÑ\82 Ñ\87аÑ\82 Ñ\82олÑ\8cко длÑ\8f беÑ\81ед на оÑ\82влеÑ\87Ñ\91ннÑ\8bе Ñ\82емÑ\8b.
+Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е Ñ\87аÑ\82 Ñ\82олÑ\8cко длÑ\8f пÑ\80оÑ\87иÑ\85 обÑ\89иÑ\85 беÑ\81ед.
///
-### Не использовать чаты для вопросов
-
-Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
-
-В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅
-
-Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#_3){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
-
-С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄
-
-## Спонсировать автора
-
-Вы также можете оказать мне финансовую поддержку посредством <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">спонсорства через GitHub</a>.
+### Не используйте чат для вопросов { #dont-use-the-chat-for-questions }
-Там можно пÑ\80оÑ\81Ñ\82о кÑ\83пиÑ\82Ñ\8c мне коÑ\84е â\98\95ï¸\8f в знак благодаÑ\80ноÑ\81Ñ\82и. ð\9f\98\84
+Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о в Ñ\87аÑ\82аÑ\85, благодаÑ\80Ñ\8f "Ñ\81вободномÑ\83 обÑ\89ениÑ\8e", легко задаÑ\82Ñ\8c вопÑ\80оÑ\81Ñ\8b, коÑ\82оÑ\80Ñ\8bе Ñ\81лиÑ\88ком обÑ\89ие и на коÑ\82оÑ\80Ñ\8bе Ñ\81ложнее оÑ\82веÑ\82иÑ\82Ñ\8c, поÑ\8dÑ\82омÑ\83 Ð\92Ñ\8b можеÑ\82е не полÑ\83Ñ\87иÑ\82Ñ\8c оÑ\82веÑ\82Ñ\8b.
-Ð\90 еÑ\89Ñ\91 Ð\92Ñ\8b можеÑ\82е Ñ\81Ñ\82аÑ\82Ñ\8c СеÑ\80ебÑ\80Ñ\8fнÑ\8bм или Ð\97олоÑ\82Ñ\8bм Ñ\81понÑ\81оÑ\80ом длÑ\8f FastAPI. ð\9f\8f\85ð\9f\8e\89
+Ð\9dа GitHub Ñ\88аблон поможеÑ\82 Ð\92ам пÑ\80авилÑ\8cно Ñ\81Ñ\84оÑ\80мÑ\83лиÑ\80оваÑ\82Ñ\8c вопÑ\80оÑ\81, Ñ\87Ñ\82обÑ\8b Ð\92ам бÑ\8bло легÑ\87е полÑ\83Ñ\87иÑ\82Ñ\8c Ñ\85оÑ\80оÑ\88ий оÑ\82веÑ\82 или даже Ñ\80еÑ\88иÑ\82Ñ\8c пÑ\80облемÑ\83 Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно еÑ\89Ñ\91 до Ñ\82ого, как Ñ\81пÑ\80оÑ\81иÑ\82е. Ð\98 на GitHub Ñ\8f могÑ\83 Ñ\81ледиÑ\82Ñ\8c за Ñ\82ем, Ñ\87Ñ\82обÑ\8b вÑ\81егда оÑ\82веÑ\87аÑ\82Ñ\8c на вÑ\81Ñ\91, даже еÑ\81ли Ñ\8dÑ\82о занимаеÑ\82 вÑ\80емÑ\8f. Ð\90 Ñ\81 Ñ\87аÑ\82ами Ñ\8f не могÑ\83 Ñ\81делаÑ\82Ñ\8c Ñ\8dÑ\82ого лиÑ\87но. ð\9f\98\85
-## Спонсировать инструменты, на которых зиждется мощь FastAPI
+Кроме того, переписка в чатах хуже ищется, чем на GitHub, поэтому вопросы и ответы могут теряться среди остальных сообщений. И только те, что на GitHub, учитываются для получения лычки [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что вероятнее всего Вы получите больше внимания именно на GitHub.
-Ð\9aак Ð\92Ñ\8b могли замеÑ\82иÑ\82Ñ\8c в докÑ\83менÑ\82аÑ\86ии, FastAPI опиÑ\80аеÑ\82Ñ\81Ñ\8f на плеÑ\87и Ñ\82иÑ\82анов: Starlette и Pydantic.
+С дÑ\80Ñ\83гой Ñ\81Ñ\82оÑ\80онÑ\8b, в Ñ\87аÑ\82аÑ\85 Ñ\82Ñ\8bÑ\81Ñ\8fÑ\87и полÑ\8cзоваÑ\82елей, Ñ\82ак Ñ\87Ñ\82о поÑ\87Ñ\82и вÑ\81егда еÑ\81Ñ\82Ñ\8c Ñ\88анÑ\81 найÑ\82и Ñ\82ам кого-Ñ\82о длÑ\8f Ñ\80азговоÑ\80а. ð\9f\98\84
-Им тоже можно оказать спонсорскую поддержку:
+## Спонсировать автора { #sponsor-the-author }
-* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
-* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
+Если Ваш **продукт/компания** зависят от **FastAPI** или связаны с ним и Вы хотите донести до пользователей информацию о себе, Вы можете спонсировать автора (меня) через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>. В зависимости от уровня поддержки Вы можете получить дополнительные бонусы, например, бейдж в документации. 🎁
---
-Ð\91лагодаÑ\80Ñ\81Ñ\82вÑ\83Ñ\8e! 🚀
+СпаÑ\81ибо! 🚀
-# История создания и дальнейшее развитие
+# История, проектирование и будущее { #history-design-and-future }
Однажды, <a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">один из пользователей **FastAPI** задал вопрос</a>:
Что ж, вот небольшая часть истории проекта.
-## Альтернативы
+## Альтернативы { #alternatives }
В течение нескольких лет я, возглавляя различные команды разработчиков, создавал довольно сложные API для машинного обучения, распределённых систем, асинхронных задач, баз данных NoSQL и т.д.
Я всячески избегал создания нового фреймворка в течение нескольких лет. Сначала я пытался собрать все нужные возможности, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов.
-Ð\9dо в какой-Ñ\82о моменÑ\82 не оÑ\81Ñ\82алоÑ\81Ñ\8c дÑ\80Ñ\83гого вÑ\8bбоÑ\80а, кÑ\80оме как Ñ\81оздаÑ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о, Ñ\87Ñ\82о пÑ\80едоÑ\81Ñ\82авлÑ\8fло бÑ\8b вÑ\81е Ñ\8dÑ\82и возможноÑ\81Ñ\82и Ñ\81Ñ\80азÑ\83. Ð\92зÑ\8fÑ\82Ñ\8c Ñ\81амÑ\8bе лÑ\83Ñ\87Ñ\88ие идеи из пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов и, иÑ\81полÑ\8cзÑ\83Ñ\8f введÑ\91ннÑ\8bе в Python подÑ\81казки типов (которых не было до версии 3.6), объединить их.
+Ð\9dо в какой-Ñ\82о моменÑ\82 не оÑ\81Ñ\82алоÑ\81Ñ\8c дÑ\80Ñ\83гого вÑ\8bбоÑ\80а, кÑ\80оме как Ñ\81оздаÑ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о, Ñ\87Ñ\82о пÑ\80едоÑ\81Ñ\82авлÑ\8fло бÑ\8b вÑ\81е Ñ\8dÑ\82и возможноÑ\81Ñ\82и Ñ\81Ñ\80азÑ\83. Ð\92зÑ\8fÑ\82Ñ\8c Ñ\81амÑ\8bе лÑ\83Ñ\87Ñ\88ие идеи из пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов и, иÑ\81полÑ\8cзÑ\83Ñ\8f введÑ\91ннÑ\8bе в Python анноÑ\82аÑ\86ии типов (которых не было до версии 3.6), объединить их.
</blockquote>
-## Исследования
+## Исследования { #investigation }
Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом.
-Например, стало ясно, что необходимо брать за основу стандартные подсказки типов Python, а самым лучшим подходом является использование уже существующих стандартов.
+Например, стало ясно, что необходимо брать за основу стандартные аннотации типов Python.
+
+Также наилучшим подходом является использование уже существующих стандартов.
Итак, прежде чем приступить к написанию **FastAPI**, я потратил несколько месяцев на изучение OpenAPI, JSON Schema, OAuth2, и т.п. для понимания их взаимосвязей, совпадений и различий.
-## Ð\94изайн
+## Ð\9fÑ\80оекÑ\82иÑ\80ование { #design }
Затем я потратил некоторое время на придумывание "API" разработчика, который я хотел иметь как пользователь (как разработчик, использующий FastAPI).
-Я проверил несколько идей на самых популярных редакторах кода среди Python-разработчиков: PyCharm, VS Code, Jedi.
+Я проверил несколько идей на самых популярных редакторах кода: PyCharm, VS Code, редакторы на базе Jedi.
-Ð\94аннÑ\8bе по Ñ\80едакÑ\82оÑ\80ам Ñ\8f взÑ\8fл из <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">опÑ\80оÑ\81а Python-Ñ\80азÑ\80абоÑ\82Ñ\87иков</a>, коÑ\82оÑ\80Ñ\8bй оÑ\85ваÑ\82Ñ\8bвааеÑ\82 около 80% полÑ\8cзоваÑ\82елей.
+Данные по редакторам я взял из <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">опроса Python-разработчиков</a>, который охватывает около 80% пользователей.
Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.
-Таким обÑ\80азом, Ñ\8f Ñ\81мог найÑ\82и наилÑ\83Ñ\87Ñ\88ие Ñ\81поÑ\81обÑ\8b Ñ\81окÑ\80аÑ\82иÑ\82Ñ\8c дÑ\83блиÑ\80ование кода, обеÑ\81пеÑ\87иÑ\82Ñ\8c повÑ\81емеÑ\81Ñ\82ное авÑ\82одополнение, проверку типов и ошибок и т.д.
+Таким обÑ\80азом, Ñ\8f Ñ\81мог найÑ\82и наилÑ\83Ñ\87Ñ\88ие Ñ\81поÑ\81обÑ\8b Ñ\81окÑ\80аÑ\82иÑ\82Ñ\8c дÑ\83блиÑ\80ование кода, обеÑ\81пеÑ\87иÑ\82Ñ\8c повÑ\81емеÑ\81Ñ\82ное авÑ\82озавеÑ\80Ñ\88ение, проверку типов и ошибок и т.д.
И все это, чтобы все пользователи могли получать наилучший опыт разработки.
-## Зависимости
+## Зависимости { #requirements }
Протестировав несколько вариантов, я решил, что в качестве основы буду использовать <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">**Pydantic**</a> и его преимущества.
-Ð\9fо моим пÑ\80едложениÑ\8fм бÑ\8bл изменÑ\91н код Ñ\8dÑ\82ого Ñ\84Ñ\80еймвоÑ\80ка, Ñ\87Ñ\82обÑ\8b Ñ\81делаÑ\82Ñ\8c его полноÑ\81Ñ\82Ñ\8cÑ\8e Ñ\81овмеÑ\81Ñ\82имÑ\8bм Ñ\81 JSON Schema, поддеÑ\80жаÑ\82Ñ\8c Ñ\80азлиÑ\87нÑ\8bе Ñ\81поÑ\81обÑ\8b опÑ\80еделениÑ\8f огÑ\80аниÑ\87ений и Ñ\83лÑ\83Ñ\87Ñ\88иÑ\82Ñ\8c помоÑ\89Ñ\8c Ñ\80едакÑ\82оÑ\80ов (пÑ\80овеÑ\80ки Ñ\82ипов, авÑ\82озаполнение).
+Ð\9fо моим пÑ\80едложениÑ\8fм бÑ\8bл изменÑ\91н код Ñ\8dÑ\82ого Ñ\84Ñ\80еймвоÑ\80ка, Ñ\87Ñ\82обÑ\8b Ñ\81делаÑ\82Ñ\8c его полноÑ\81Ñ\82Ñ\8cÑ\8e Ñ\81овмеÑ\81Ñ\82имÑ\8bм Ñ\81 JSON Schema, поддеÑ\80жаÑ\82Ñ\8c Ñ\80азлиÑ\87нÑ\8bе Ñ\81поÑ\81обÑ\8b опÑ\80еделениÑ\8f огÑ\80аниÑ\87ений и Ñ\83лÑ\83Ñ\87Ñ\88иÑ\82Ñ\8c поддеÑ\80жкÑ\83 в Ñ\80едакÑ\82оÑ\80аÑ\85 кода (пÑ\80овеÑ\80ки Ñ\82ипов, авÑ\82озавеÑ\80Ñ\88ение) на оÑ\81нове Ñ\82еÑ\81Ñ\82ов в неÑ\81колÑ\8cкиÑ\85 Ñ\80едакÑ\82оÑ\80аÑ\85.
В то же время, я принимал участие в разработке <a href="https://www.starlette.io/" class="external-link" target="_blank">**Starlette**</a>, ещё один из основных компонентов FastAPI.
-## Разработка
+## Разработка { #development }
К тому времени, когда я начал создавать **FastAPI**, большинство необходимых деталей уже существовало, дизайн был определён, зависимости и прочие инструменты были готовы, а знания о стандартах и спецификациях были четкими и свежими.
-## Будущее
+## Будущее { #future }
Сейчас уже ясно, что **FastAPI** со своими идеями стал полезен многим людям.
-# FastAPI
+# FastAPI { #fastapi }
<style>
.md-content .md-typeset h1 { display: none; }
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
- <em>Ð\93оÑ\82овÑ\8bй к внедÑ\80ениÑ\8e вÑ\8bÑ\81окопÑ\80оизводиÑ\82елÑ\8cнÑ\8bй Ñ\84Ñ\80еймвоÑ\80к, пÑ\80оÑ\81Ñ\82ой в изÑ\83Ñ\87ении и Ñ\80азÑ\80абоÑ\82ке.</em>
+ <em>ФÑ\80еймвоÑ\80к FastAPI: вÑ\8bÑ\81окаÑ\8f пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c, пÑ\80оÑ\81Ñ\82 в изÑ\83Ñ\87ении, бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bй в Ñ\80азÑ\80абоÑ\82ке, гоÑ\82ов к пÑ\80одакÑ\88н</em>
</p>
<p align="center">
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
- <img src="https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master" alt="Test">
+ <img src="https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master" alt="Тест">
</a>
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi" target="_blank">
- <img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg" alt="Coverage">
+ <img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg" alt="Покрытие">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
- <img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
+ <img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Версия пакета">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
- <img src="https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058" alt="Supported Python versions">
+ <img src="https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058" alt="Поддерживаемые версии Python">
</a>
</p>
---
-**Документация**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
+**Документация**: <a href="https://fastapi.tiangolo.com/ru" target="_blank">https://fastapi.tiangolo.com</a>
**Исходный код**: <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
---
-FastAPI â\80\94 Ñ\8dÑ\82о Ñ\81овÑ\80еменнÑ\8bй, бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bй (вÑ\8bÑ\81окопÑ\80оизводиÑ\82елÑ\8cнÑ\8bй) веб-Ñ\84Ñ\80еймвоÑ\80к длÑ\8f Ñ\81озданиÑ\8f API иÑ\81полÑ\8cзÑ\83Ñ\8f Python, в оÑ\81нове коÑ\82оÑ\80ого лежиÑ\82 Ñ\81Ñ\82андаÑ\80Ñ\82наÑ\8f анноÑ\82аÑ\86иÑ\8f типов Python.
+FastAPI â\80\94 Ñ\8dÑ\82о Ñ\81овÑ\80еменнÑ\8bй, бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bй (вÑ\8bÑ\81окопÑ\80оизводиÑ\82елÑ\8cнÑ\8bй) веб-Ñ\84Ñ\80еймвоÑ\80к длÑ\8f Ñ\81озданиÑ\8f API на Python, оÑ\81нованнÑ\8bй на Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bÑ\85 анноÑ\82аÑ\86иÑ\8fÑ\85 типов Python.
Ключевые особенности:
-* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков Python](#_10).
-* **Быстрота разработки**: Увеличьте скорость разработки примерно на 200–300%. *
+* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).
+* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200–300%. *
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
-* **Интуитивно понятный**: Отличная поддержка редактора. <abbr title="также известное как автозаполнение, автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
-* **Ð\9bÑ\91гкоÑ\81Ñ\82Ñ\8c**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
-* **Ð\9aÑ\80аÑ\82коÑ\81Ñ\82Ñ\8c**: СведиÑ\82е к минимÑ\83мÑ\83 дÑ\83блиÑ\80ование кода. Ð\9aаждÑ\8bй обÑ\8aÑ\8fвленнÑ\8bй паÑ\80амеÑ\82Ñ\80 - опÑ\80еделÑ\8fеÑ\82 неÑ\81колÑ\8cко Ñ\84Ñ\83нкÑ\86ий. Меньше ошибок.
-* **Ð\9dадежноÑ\81Ñ\82Ñ\8c**: Ð\9fолÑ\83Ñ\87иÑ\82е гоÑ\82овÑ\8bй к Ñ\80абоÑ\82е код. С автоматической интерактивной документацией.
-* **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (ранее известном как Swagger) и <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
+* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
+* **Ð\9fÑ\80оÑ\81Ñ\82оÑ\82а**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
+* **Ð\9aÑ\80аÑ\82коÑ\81Ñ\82Ñ\8c**: Ð\9cинимизиÑ\80Ñ\83йÑ\82е дÑ\83блиÑ\80ование кода. Ð\9dеÑ\81колÑ\8cко возможноÑ\81Ñ\82ей из каждого обÑ\8aÑ\8fвлениÑ\8f паÑ\80амеÑ\82Ñ\80ов. Меньше ошибок.
+* **Ð\9dадежноÑ\81Ñ\82Ñ\8c**: Ð\9fолÑ\83Ñ\87иÑ\82е код, гоÑ\82овÑ\8bй к пÑ\80одакÑ\88н. С автоматической интерактивной документацией.
+* **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (ранее известный как Swagger) и <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
-<small>* оÑ\86енка на оÑ\81нове Ñ\82еÑ\81Ñ\82ов внÑ\83Ñ\82Ñ\80енней командÑ\8b Ñ\80азÑ\80абоÑ\82Ñ\87иков, Ñ\81оздаÑ\8eÑ\89иÑ\85 пÑ\80оизводÑ\81Ñ\82веннÑ\8bе приложения.</small>
+<small>* оÑ\86енка на оÑ\81нове Ñ\82еÑ\81Ñ\82ов внÑ\83Ñ\82Ñ\80енней командÑ\8b Ñ\80азÑ\80абоÑ\82Ñ\87иков, Ñ\81оздаÑ\8eÑ\89иÑ\85 пÑ\80одакÑ\88н-приложения.</small>
-## Спонсоры
+## Спонсоры { #sponsors }
<!-- sponsors -->
<!-- /sponsors -->
-<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Другие спонсоры</a>
+<a href="https://fastapi.tiangolo.com/ru/fastapi-people/#sponsors" class="external-link" target="_blank">Другие спонсоры</a>
-## Ð\9eÑ\82зÑ\8bвÑ\8b
+## Ð\9cнениÑ\8f { #opinions }
-"_В последнее время я много где использую **FastAPI**. [...] На самом деле я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._"
+"_[...] В последнее время я много где использую **FastAPI**. [...] На самом деле я планирую использовать его для всех **ML-сервисов моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._"
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
---
-"_Ð\9cÑ\8b иÑ\81полÑ\8cзовали библиоÑ\82екÑ\83 **FastAPI** длÑ\8f Ñ\81озданиÑ\8f Ñ\81еÑ\80веÑ\80а **REST**, к коÑ\82оÑ\80омÑ\83 можно делаÑ\82Ñ\8c запÑ\80оÑ\81Ñ\8b длÑ\8f полÑ\83Ñ\87ениÑ\8f **пÑ\80огнозов**. [для Ludwig]_"
+"_Ð\9cÑ\8b наÑ\87али иÑ\81полÑ\8cзоваÑ\82Ñ\8c библиоÑ\82екÑ\83 **FastAPI**, Ñ\87Ñ\82обÑ\8b поднÑ\8fÑ\82Ñ\8c **REST**-Ñ\81еÑ\80веÑ\80, к коÑ\82оÑ\80омÑ\83 можно обÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f за **пÑ\80едÑ\81казаниÑ\8fми**. [для Ludwig]_"
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
---
-"_**Netflix** рада объявить о выпуске опенсорсного фреймворка для оркестровки **антикризисного управления**: **Dispatch**! [создана с помощью **FastAPI**]_"
+"_**Netflix** рада объявить об открытом релизе нашего фреймворка оркестрации **антикризисного управления**: **Dispatch**! [создан с помощью **FastAPI**]_"
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
"_Я в полном восторге от **FastAPI**. Это так весело!_"
-<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
+<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong>Ведущий подкаста <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a></strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
-"_ЧеÑ\81Ñ\82но говоÑ\80Ñ\8f, Ñ\82о, Ñ\87Ñ\82о вÑ\8b Ñ\81оздали, вÑ\8bглÑ\8fдиÑ\82 оÑ\87енÑ\8c Ñ\81олидно и оÑ\82полиÑ\80овано. Ð\92о многиÑ\85 Ñ\81мÑ\8bÑ\81лаÑ\85 Ñ\8f Ñ\85оÑ\82ел, Ñ\87Ñ\82обÑ\8b **Hug** бÑ\8bл именно Ñ\82аким â\80\94 Ñ\8dÑ\82о дейÑ\81Ñ\82виÑ\82елÑ\8cно вдоÑ\85новлÑ\8fеÑ\82, когда кÑ\82о-Ñ\82о Ñ\81оздаÑ\91Ñ\82 Ñ\82акое._"
+"_ЧеÑ\81Ñ\82но говоÑ\80Ñ\8f, Ñ\82о, Ñ\87Ñ\82о вÑ\8b Ñ\81оздали, вÑ\8bглÑ\8fдиÑ\82 оÑ\87енÑ\8c Ñ\81олидно и оÑ\82полиÑ\80овано. Ð\92о многиÑ\85 Ñ\81мÑ\8bÑ\81лаÑ\85 Ñ\8dÑ\82о Ñ\82о, Ñ\87ем Ñ\8f Ñ\85оÑ\82ел видеÑ\82Ñ\8c **Hug** â\80\94 оÑ\87енÑ\8c вдоÑ\85новлÑ\8fеÑ\82 видеÑ\82Ñ\8c, как кÑ\82о-Ñ\82о Ñ\8dÑ\82о Ñ\81оздал._"
-<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
+<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong>Создатель <a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
-"_Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е изÑ\83Ñ\87иÑ\82Ñ\8c какой-нибÑ\83дÑ\8c **Ñ\81овÑ\80еменнÑ\8bй Ñ\84Ñ\80еймвоÑ\80к** длÑ\8f Ñ\81озданиÑ\8f REST API, ознакомÑ\8cÑ\82еÑ\81Ñ\8c Ñ\81 **FastAPI** [...] Ð\9eн бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bй, лÑ\91гкий и пÑ\80оÑ\81Ñ\82ой в изучении [...]_"
+"_Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е изÑ\83Ñ\87иÑ\82Ñ\8c один **Ñ\81овÑ\80еменнÑ\8bй Ñ\84Ñ\80еймвоÑ\80к** длÑ\8f Ñ\81озданиÑ\8f REST API, поÑ\81моÑ\82Ñ\80иÑ\82е **FastAPI** [...] Ð\9eн бÑ\8bÑ\81Ñ\82Ñ\80Ñ\8bй, пÑ\80оÑ\81Ñ\82ой в иÑ\81полÑ\8cзовании и лÑ\91гкий в изучении [...]_"
-"_Мы перешли на **FastAPI** для наших **API** [...] Я думаю, вам тоже понравится [...]_"
+"_Мы переключились на **FastAPI** для наших **API** [...] Думаю, вам тоже понравится [...]_"
-<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
+<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>Основатели <a href="https://explosion.ai" target="_blank">Explosion AI</a> — создатели <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
---
-## **Typer**, интерфейс командной строки для FastAPI
+"_Если кто-то собирается делать продакшн-API на Python, я настоятельно рекомендую **FastAPI**. Он **прекрасно спроектирован**, **прост в использовании** и **отлично масштабируется**, стал **ключевым компонентом** нашей стратегии API-first и приводит в действие множество автоматизаций и сервисов, таких как наш Virtual TAC Engineer._"
-<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
-
-Если вы создаете приложение <abbr title="Интерфейс командной строки">CLI</abbr> для использования в терминале вместо веб-API, ознакомьтесь с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
+<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
-**Typer** — младший брат FastAPI. И он предназначен для использования в качестве **интерфейса командной строки для FastAPI**. ⌨️ 🚀
+---
-## Зависимости
+## **Typer**, FastAPI для CLI { #typer-the-fastapi-of-clis }
-FastAPI стоит на плечах гигантов:
+<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
-* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> для части связанной с вебом.
-* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> для части связанной с данными.
+Если вы создаёте приложение <abbr title="Command Line Interface – Интерфейс командной строки">CLI</abbr> для использования в терминале вместо веб-API, посмотрите <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
-## Установка
+**Typer** — младший брат FastAPI. И он задуман как **FastAPI для CLI**. ⌨️ 🚀
-<div class="termy">
+## Зависимости { #requirements }
-```console
-$ pip install fastapi
+FastAPI стоит на плечах гигантов:
----> 100%
-```
+* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> для части, связанной с вебом.
+* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> для части, связанной с данными.
-</div>
+## Установка { #installation }
-Ð\92ам Ñ\82акже понадобиÑ\82Ñ\81Ñ\8f Ñ\81еÑ\80веÑ\80 ASGI длÑ\8f пÑ\80оизводÑ\81Ñ\82ва, Ñ\82акой как <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> или <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
+СоздайÑ\82е и акÑ\82ивиÑ\80Ñ\83йÑ\82е <a href="https://fastapi.tiangolo.com/ru/virtual-environments/" class="external-link" target="_blank">виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение</a>, заÑ\82ем Ñ\83Ñ\81Ñ\82ановиÑ\82е FastAPI:
<div class="termy">
```console
-$ pip install "uvicorn[standard]"
+$ pip install "fastapi[standard]"
---> 100%
```
</div>
-## Пример
+**Примечание**: Обязательно заключите `"fastapi[standard]"` в кавычки, чтобы это работало во всех терминалах.
+
+## Пример { #example }
-### Создание
+### Создание { #create-it }
-* Создайте файл `main.py` со следующим содержимым:
+Создайте файл `main.py` со следующим содержимым:
```Python
from typing import Union
**Примечание**:
-Ð\95Ñ\81ли вÑ\8b не знаеÑ\82е, пÑ\80овеÑ\80Ñ\8cÑ\82е Ñ\80аздел _"ТоÑ\80опиÑ\82еÑ\81Ñ\8c?"_ <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">в докÑ\83менÑ\82аÑ\86ии об `async` и `await`</a>.
+Ð\95Ñ\81ли не Ñ\83веÑ\80енÑ\8b, поÑ\81моÑ\82Ñ\80иÑ\82е Ñ\80аздел _«Ð\9dеÑ\82 вÑ\80емени?»_ о <a href="https://fastapi.tiangolo.com/ru/async/#in-a-hurry" target="_blank">`async` и `await` в докÑ\83менÑ\82аÑ\86ии</a>.
</details>
-### Запуск
+### Запуск { #run-it }
-Запустите сервер с помощью:
+Запустите сервер командой:
<div class="termy">
```console
-$ uvicorn main:app --reload
-
+$ fastapi dev main.py
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [28720]
-INFO: Started server process [28722]
+INFO: Started reloader process [2248755] using WatchFiles
+INFO: Started server process [2248757]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>
<details markdown="1">
-<summary>О команде <code>uvicorn main:app --reload</code>...</summary>
+<summary>О команде <code>fastapi dev main.py</code>...</summary>
-Команда `uvicorn main:app` относится к:
+Команда `fastapi dev` читает ваш файл `main.py`, находит в нём приложение **FastAPI** и запускает сервер с помощью <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>.
-* `main`: файл `main.py` (модуль Python).
-* `app`: объект, созданный внутри `main.py` с помощью строки `app = FastAPI()`.
-* `--reload`: перезапуск сервера после изменения кода. Делайте это только во время разработки.
+По умолчанию `fastapi dev` запускается с включённой авто-перезагрузкой для локальной разработки.
+
+Подробнее в <a href="https://fastapi.tiangolo.com/ru/fastapi-cli/" target="_blank">документации по FastAPI CLI</a>.
</details>
-### Проверка
+### Проверка { #check-it }
Откройте браузер на <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
-Вы увидите следующий JSON ответ:
+Вы увидите JSON-ответ:
```JSON
{"item_id": 5, "q": "somequery"}
Вы уже создали API, который:
* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.
-* Ð\98 пеÑ\80вÑ\8bй и вÑ\82оÑ\80ой _пÑ\83Ñ\82Ñ\8c_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
-* _путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
-* _путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
+* Ð\9eба _пÑ\83Ñ\82и_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
+* _Ð\9fуть_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
+* _Ð\9fуть_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
-### Интерактивная документация по API
+### Интерактивная документация API { #interactive-api-docs }
Перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
-Ð\92Ñ\8b Ñ\83видиÑ\82е авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e инÑ\82еÑ\80акÑ\82ивнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e API (пÑ\80едоÑ\81Ñ\82авленнÑ\83Ñ\8e <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
+Ð\92Ñ\8b Ñ\83видиÑ\82е авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e инÑ\82еÑ\80акÑ\82ивнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e API (пÑ\80едоÑ\81Ñ\82авлена <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):

-### Альтернативная документация по API
+### Альтернативная документация API { #alternative-api-docs }
-Ð\90 Ñ\82епеÑ\80Ñ\8c пеÑ\80ейдиÑ\82е на <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
+ТепеÑ\80Ñ\8c оÑ\82кÑ\80ойÑ\82е <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
-Ð\92Ñ\8b Ñ\83видиÑ\82е алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\83Ñ\8e авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e (пÑ\80едоÑ\81Ñ\82авленнÑ\83Ñ\8e <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
+Ð\92Ñ\8b Ñ\83видиÑ\82е алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\83Ñ\8e авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e (пÑ\80едоÑ\81Ñ\82авлена <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):

-## Пример обновления
+## Пример обновления { #example-upgrade }
-Теперь измените файл `main.py`, чтобы получить тело ответа из `PUT` запроса.
+Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` запроса.
-Ð\9eбÑ\8aÑ\8fвиÑ\82е Ñ\82ело, иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\83Ñ\8e Ñ\82ипизаÑ\86иÑ\8e Python, спасибо Pydantic.
+Ð\9eбÑ\8aÑ\8fвиÑ\82е Ñ\82ело, иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе Ñ\82ипÑ\8b Python, спасибо Pydantic.
```Python hl_lines="4 9-12 25-27"
from typing import Union
return {"item_name": item.name, "item_id": item_id}
```
-Сервер должен перезагрузиться автоматически (потому что вы добавили `--reload` к команде `uvicorn` выше).
+Сервер `fastapi dev` должен перезагрузиться автоматически.
-### Ð\98нÑ\82еÑ\80акÑ\82ивное обновление докÑ\83менÑ\82аÑ\86ии API
+### Ð\9eбновление инÑ\82еÑ\80акÑ\82ивной докÑ\83менÑ\82аÑ\86ии API { #interactive-api-docs-upgrade }
Перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
-* Интерактивная документация API будет автоматически обновляться, включая новое тело:
+* Интерактивная документация API будет автоматически обновлена, включая новое тело:

-* Ð\9dажмиÑ\82е на кнопкÑ\83 "Try it out", это позволит вам заполнить параметры и напрямую взаимодействовать с API:
+* Ð\9dажмиÑ\82е кнопкÑ\83 «Try it out», это позволит вам заполнить параметры и напрямую взаимодействовать с API:

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

-### Ð\90лÑ\8cÑ\82еÑ\80наÑ\82ивное обновление докÑ\83менÑ\82аÑ\86ии API
+### Ð\9eбновление алÑ\8cÑ\82еÑ\80наÑ\82ивной докÑ\83менÑ\82аÑ\86ии API { #alternative-api-docs-upgrade }
-Ð\90 Ñ\82епеÑ\80Ñ\8c пеÑ\80ейдиÑ\82е на <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
+ТепеÑ\80Ñ\8c оÑ\82кÑ\80ойÑ\82е <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
-* Ð\90лÑ\8cÑ\82еÑ\80наÑ\82ивнаÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f Ñ\82акже бÑ\83деÑ\82 оÑ\82Ñ\80ажаÑ\82Ñ\8c новÑ\8bй паÑ\80амеÑ\82Ñ\80 и Ñ\82ело запÑ\80оÑ\81а:
+* Ð\90лÑ\8cÑ\82еÑ\80наÑ\82ивнаÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f Ñ\82акже оÑ\82Ñ\80азиÑ\82 новÑ\8bй паÑ\80амеÑ\82Ñ\80 запÑ\80оÑ\81а и Ñ\82ело:

-### Подведём итоги
+### Подведём итоги { #recap }
-Таким обÑ\80азом, вÑ\8b обÑ\8aÑ\8fвлÑ\8fеÑ\82е **один Ñ\80аз** Ñ\82ипÑ\8b паÑ\80амеÑ\82Ñ\80ов, Ñ\82ело и Ñ\82. д. в каÑ\87еÑ\81Ñ\82ве паÑ\80амеÑ\82Ñ\80ов функции.
+Ð\98Ñ\82ак, вÑ\8b обÑ\8aÑ\8fвлÑ\8fеÑ\82е **один Ñ\80аз** Ñ\82ипÑ\8b паÑ\80амеÑ\82Ñ\80ов, Ñ\82ела запÑ\80оÑ\81а и Ñ\82.д. как паÑ\80амеÑ\82Ñ\80Ñ\8b функции.
-Вы делаете это используя стандартную современную типизацию Python.
+Вы делаете это с помощью стандартных современных типов Python.
-Вам не нужно изучать новый синтаксис, методы или классы конкретной библиотеки и т. д.
+Вам не нужно изучать новый синтаксис, методы или классы конкретной библиотеки и т.п.
Только стандартный **Python**.
item: Item
```
-... и с этим единственным объявлением вы получаете:
+...и с этим единственным объявлением вы получаете:
-* Поддержка редактора, в том числе:
+* Поддержку редактора кода, включая:
* Автозавершение.
- * Проверка типов.
-* Ð\92алидаÑ\86иÑ\8f данных:
- * Автоматические и четкие ошибки, когда данные недействительны.
- * Ð\9fÑ\80овеÑ\80ка даже для глубоко вложенных объектов JSON.
-* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> входных данных: поступающие из сети в объекты Python с соблюдением типов. Чтение из:
+ * Проверку типов.
+* Ð\92алидаÑ\86иÑ\8e данных:
+ * Автоматические и понятные ошибки, когда данные некорректны.
+ * Ð\92алидаÑ\86иÑ\8e даже для глубоко вложенных объектов JSON.
+* <abbr title="также известное как: сериализация, парсинг, маршалинг">Преобразование</abbr> входных данных: из сети в данные и типы Python. Чтение из:
* JSON.
* Параметров пути.
* Параметров запроса.
* Cookies.
- * Заголовков.
+ * HTTP-заголовков.
* Форм.
* Файлов.
-* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> выходных данных: преобразование объектов Python в данные передаваемые по сети интернет (такие как JSON):
- * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т.д.).
+* <abbr title="также известное как: сериализация, парсинг, маршалинг">Преобразование</abbr> выходных данных: из данных и типов Python в данные сети (например, JSON):
+ * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list` и т.д.).
* Объекты `datetime`.
* Объекты `UUID`.
* Модели баз данных.
* ...и многое другое.
-* Автоматическая интерактивная документация по API, включая 2 альтернативных пользовательских интерфейса:
+* Автоматическую интерактивную документацию API, включая 2 альтернативных интерфейса:
* Swagger UI.
* ReDoc.
Возвращаясь к предыдущему примеру кода, **FastAPI** будет:
-* Ð\9fÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c налиÑ\87ие `item_id` в пÑ\83Ñ\82и длÑ\8f запÑ\80оÑ\81ов `GET` и `PUT`.
-* Ð\9fÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c, Ñ\87Ñ\82о `item_id` имееÑ\82 Ñ\82ип `int` длÑ\8f запÑ\80оÑ\81ов `GET` и `PUT`.
- * Если это не так, клиент увидит полезную чёткую ошибку.
+* Ð\92алидиÑ\80оваÑ\82Ñ\8c налиÑ\87ие `item_id` в пÑ\83Ñ\82и длÑ\8f `GET` и `PUT` запÑ\80оÑ\81ов.
+* Ð\92алидиÑ\80оваÑ\82Ñ\8c, Ñ\87Ñ\82о `item_id` имееÑ\82 Ñ\82ип `int` длÑ\8f `GET` и `PUT` запÑ\80оÑ\81ов.
+ * Если это не так, клиент увидит полезную понятную ошибку.
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` запросов.
- * Поскольку параметр `q` объявлен с `= None`, он является необязательным.
- * Ð\91ез `None` он бÑ\8bл бÑ\8b необÑ\85одим (как Ñ\82ело в случае с `PUT`).
-* Для `PUT` запросов к `/items/{item_id}` читать тело как JSON:
- * Проверять, что у него есть обязательный атрибут `name`, который должен быть `str`.
- * Проверять, что у него есть обязательный атрибут `price`, который должен быть `float`.
- * Проверять, что у него есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.
- * Все это также будет работать для глубоко вложенных объектов JSON.
-* Ð\9fÑ\80еобÑ\80азовÑ\8bваÑ\82Ñ\8c из и в JSON авÑ\82омаÑ\82иÑ\87еÑ\81ки.
-* Документировать с помощью OpenAPI все, что может быть использовано:
- * Системы интерактивной документации.
- * Системы автоматической генерации клиентского кода для многих языков.
-* Ð\9eбеÑ\81пеÑ\87иÑ\82 2 инÑ\82еÑ\80акÑ\82ивнÑ\8bÑ\85 веб-инÑ\82еÑ\80Ñ\84ейÑ\81а документации напрямую.
+ * Поскольку параметр `q` объявлен с `= None`, он необязателен.
+ * Ð\91ез `None` он бÑ\8bл бÑ\8b обÑ\8fзаÑ\82елÑ\8cнÑ\8bм (как Ñ\82ело запÑ\80оÑ\81а в случае с `PUT`).
+* Ð\94лÑ\8f `PUT` запÑ\80оÑ\81ов к `/items/{item_id}` Ñ\87иÑ\82аÑ\82Ñ\8c Ñ\82ело запÑ\80оÑ\81а как JSON:
+ * Проверять, что есть обязательный атрибут `name`, который должен быть `str`.
+ * Проверять, что есть обязательный атрибут `price`, который должен быть `float`.
+ * Проверять, что есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.
+ * Всё это также будет работать для глубоко вложенных объектов JSON.
+* Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80еобÑ\80азовÑ\8bваÑ\82Ñ\8c из и в JSON.
+* Документировать всё с помощью OpenAPI, что может быть использовано:
+ * Системами интерактивной документации.
+ * Системами автоматической генерации клиентского кода для многих языков.
+* Ð\9fÑ\80едоÑ\81Ñ\82авлÑ\8fÑ\82Ñ\8c 2 веб-инÑ\82еÑ\80Ñ\84ейÑ\81а инÑ\82еÑ\80акÑ\82ивной документации напрямую.
---
-Ð\9cÑ\8b Ñ\82олÑ\8cко немного копнÑ\83ли повеÑ\80Ñ\85ноÑ\81Ñ\82Ñ\8c, но вÑ\8b Ñ\83же понÑ\8fли, как вÑ\81е это работает.
+Ð\9cÑ\8b Ñ\82олÑ\8cко повеÑ\80Ñ\85ноÑ\81Ñ\82но ознакомилиÑ\81Ñ\8c, но вÑ\8b Ñ\83же понимаеÑ\82е, как вÑ\81Ñ\91 это работает.
-Попробуйте изменить строку с помощью:
+Попробуйте изменить строку:
```Python
return {"item_name": item.name, "item_id": item_id}
... "item_name": item.name ...
```
-...в:
+...на:
```Python
... "item_price": item.price ...
```
-... и посмотрите, как ваш редактор будет автоматически заполнять атрибуты и узнавать их типы:
+...и посмотрите, как ваш редактор кода будет автоматически дополнять атрибуты и знать их типы:

-Более полный пример с дополнительными функциями см. в <a href="https://fastapi.tiangolo.com/tutorial/">Учебное руководство - Руководство пользователя</a>.
+Более полный пример с дополнительными возможностями см. в <a href="https://fastapi.tiangolo.com/ru/tutorial/">Учебник - Руководство пользователя</a>.
-**Ð\9eÑ\81Ñ\82оÑ\80ожно, Ñ\81пойлеÑ\80**: Ñ\80Ñ\83ководÑ\81Ñ\82во полÑ\8cзоваÑ\82елÑ\8f вклÑ\8eÑ\87аеÑ\82 в Ñ\81ебÑ\8f:
+**Ð\9eÑ\81Ñ\82оÑ\80ожно, Ñ\81пойлеÑ\80**: Ñ\83Ñ\87ебник - Ñ\80Ñ\83ководÑ\81Ñ\82во вклÑ\8eÑ\87аеÑ\82:
-* Ð\9eбÑ\8aÑ\8fвление **паÑ\80амеÑ\82Ñ\80ов** из дÑ\80Ñ\83гиÑ\85 меÑ\81Ñ\82, Ñ\82акиÑ\85 как: **заголовки**, **cookies**, **поля формы** и **файлы**.
-* Как установить **ограничительные проверки** такие как `maximum_length` или `regex`.
-* Очень мощная и простая в использовании система **<abbr title="также известная как компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
-* Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c и аÑ\83Ñ\82енÑ\82иÑ\84икаÑ\86иÑ\8f, вклÑ\8eÑ\87аÑ\8f поддеÑ\80жкÑ\83 **OAuth2** Ñ\81 **Ñ\82окенами JWT** и **HTTP Basic** аутентификацию.
-* Ð\91олее пÑ\80одвинÑ\83Ñ\82Ñ\8bе (но Ñ\81Ñ\82олÑ\8c же пÑ\80оÑ\81Ñ\82Ñ\8bе) меÑ\82одÑ\8b обÑ\8aÑ\8fвлениÑ\8f **глÑ\83боко вложеннÑ\8bÑ\85 моделей JSON** (спасибо Pydantic).
-* **GraphQL** интеграция с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
+* Ð\9eбÑ\8aÑ\8fвление **паÑ\80амеÑ\82Ñ\80ов** из дÑ\80Ñ\83гиÑ\85 иÑ\81Ñ\82оÑ\87ников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.
+* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.
+* Очень мощную и простую в использовании систему **<abbr title="также известная как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
+* Ð\91езопаÑ\81ноÑ\81Ñ\82Ñ\8c и аÑ\83Ñ\82енÑ\82иÑ\84икаÑ\86иÑ\8e, вклÑ\8eÑ\87аÑ\8f поддеÑ\80жкÑ\83 **OAuth2** Ñ\81 **JWT Ñ\82окенами** и **HTTP Basic** аутентификацию.
+* Ð\91олее пÑ\80одвинÑ\83Ñ\82Ñ\8bе (но Ñ\81Ñ\82олÑ\8c же пÑ\80оÑ\81Ñ\82Ñ\8bе) пÑ\80иÑ\91мÑ\8b обÑ\8aÑ\8fвлениÑ\8f **глÑ\83боко вложеннÑ\8bÑ\85 JSON-моделей** (спасибо Pydantic).
+* Интеграцию **GraphQL** с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
* Множество дополнительных функций (благодаря Starlette), таких как:
- * **Веб-сокеты**
- * очень простые тесты на основе HTTPX и `pytest`
+ * **WebSockets**
+ * чрезвычайно простые тесты на основе HTTPX и `pytest`
* **CORS**
- * **Cookie сеансы(сессии)**
+ * **сессии с использованием cookie**
* ...и многое другое.
-## Производительность
+## Производительность { #performance }
+
+Независимые бенчмарки TechEmpower показывают приложения **FastAPI**, работающие под управлением Uvicorn, как <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">один из самых быстрых доступных фреймворков Python</a>, уступающий только самим Starlette и Uvicorn (используются внутри FastAPI). (*)
+
+Чтобы узнать больше, см. раздел <a href="https://fastapi.tiangolo.com/ru/benchmarks/" class="internal-link" target="_blank">Бенчмарки</a>.
+
+## Зависимости { #dependencies }
-Независимые тесты TechEmpower показывают приложения **FastAPI**, работающие под управлением Uvicorn, как <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">один из самых быстрых доступных фреймворков Python</a>, уступающий только самим Starlette и Uvicorn (используемых внутри FastAPI). (*)
+FastAPI зависит от Pydantic и Starlette.
-Чтобы узнать больше об этом, см. раздел <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Тесты производительности</a>.
+### Зависимости `standard` { #standard-dependencies }
-## Необязательные зависимости
+Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он идёт с группой опциональных зависимостей `standard`:
Используется Pydantic:
-* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - для проверки электронной почты.
+* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> — для проверки адресов электронной почты.
Используется Starlette:
-* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - Обязательно, если вы хотите использовать `TestClient`.
-* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Обязательно, если вы хотите использовать конфигурацию шаблона по умолчанию.
-* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Обязательно, если вы хотите поддерживать форму <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">"парсинга"</abbr> с помощью `request.form()`.
-* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Обязательно, для поддержки `SessionMiddleware`.
-* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Обязательно, для поддержки `SchemaGenerator` Starlette (возможно, вам это не нужно с FastAPI).
+* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> — обязателен, если вы хотите использовать `TestClient`.
+* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию.
+* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> — обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
+
+Используется FastAPI:
+
+* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> — сервер, который загружает и обслуживает ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.
+* `fastapi-cli[standard]` — чтобы предоставить команду `fastapi`.
+ * Включает `fastapi-cloud-cli`, который позволяет развернуть ваше приложение FastAPI в <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
+
+### Без зависимостей `standard` { #without-standard-dependencies }
+
+Если вы не хотите включать опциональные зависимости `standard`, можно установить `pip install fastapi` вместо `pip install "fastapi[standard]"`.
+
+### Без `fastapi-cloud-cli` { #without-fastapi-cloud-cli }
+
+Если вы хотите установить FastAPI со стандартными зависимостями, но без `fastapi-cloud-cli`, установите `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
+
+### Дополнительные опциональные зависимости { #additional-optional-dependencies }
+
+Есть дополнительные зависимости, которые вы можете установить.
+
+Дополнительные опциональные зависимости Pydantic:
-Используется FastAPI / Starlette:
+* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> — для управления настройками.
+* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> — дополнительные типы для использования с Pydantic.
-* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - сервер, который загружает и обслуживает ваше приложение.
-* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Обязательно, если вы хотите использовать `ORJSONResponse`.
-* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Обязательно, если вы хотите использовать `UJSONResponse`.
+Дополнительные опциональные зависимости FastAPI:
-Вы можете установить все это с помощью `pip install "fastapi[all]"`.
+* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> — обязателен, если вы хотите использовать `ORJSONResponse`.
+* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> — обязателен, если вы хотите использовать `UJSONResponse`.
-## Лицензия
+## Лицензия { #license }
Этот проект распространяется на условиях лицензии MIT.
-# Обучение
+# Обучение { #learn }
Здесь представлены вводные разделы и учебные пособия для изучения **FastAPI**.
-# Генераторы проектов - Шаблоны
-
-Чтобы начать работу быстрее, Вы можете использовать "генераторы проектов", в которые включены множество начальных настроек для функций безопасности, баз данных и некоторые <dfn title="также известные как маршруты, URLы, ручки, ">эндпоинты</dfn> API.
-
-В генераторе проектов всегда будут предустановлены какие-то настройки, которые Вам следует обновить и подогнать под свои нужды, но это может быть хорошей отправной точкой для Вашего проекта.
-
-## Full Stack FastAPI PostgreSQL
-
-GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
-
-### Full Stack FastAPI PostgreSQL - Особенности
-
-* Полностью интегрирован с **Docker** (основан на Docker).
-* Развёртывается в режиме Docker Swarm.
-* Интегрирован с **Docker Compose** и оптимизирован для локальной разработки.
-* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
-* Бэкенд построен на фреймворке <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a>:
- * **Быстрый**: Высокопроизводительный, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic).
- * **Интуитивно понятный**: Отличная поддержка редактора. <dfn title="также известное как автозаполнение, интеллектуальность, автозавершение">Автодополнение кода</dfn> везде. Меньше времени на отладку.
- * **Простой**: Разработан так, чтоб быть простым в использовании и изучении. Меньше времени на чтение документации.
- * **Лаконичный**: Минимизировано повторение кода. Каждый объявленный параметр определяет несколько функций.
- * **Надёжный**: Получите готовый к работе код. С автоматической интерактивной документацией.
- * **Стандартизированный**: Основан на открытых стандартах API (<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> и <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>) и полностью совместим с ними.
- * <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Множество других возможностей**</a> включая автоматическую проверку и сериализацию данных, интерактивную документацию, аутентификацию с помощью OAuth2 JWT-токенов и т.д.
-* **Безопасное хранение паролей**, которые хэшируются по умолчанию.
-* Аутентификация посредством **JWT-токенов**.
-* <dfn title="Python-объекты связанные с базами данных">Модели</dfn> **SQLAlchemy** (независящие от расширений Flask, а значит могут быть непосредственно использованы процессами Celery).
-* Базовая модель пользователя (измените или удалите её по необходимости).
-* **Alembic** для организации миграций.
-* **CORS** (Совместное использование ресурсов из разных источников).
-* **Celery**, процессы которого могут выборочно импортировать и использовать модели и код из остальной части бэкенда.
-* Тесты, на основе **Pytest**, интегрированные в Docker, чтобы Вы могли полностью проверить Ваше API, независимо от базы данных. Так как тесты запускаются в Docker, для них может создаваться новое хранилище данных каждый раз (Вы можете, по своему желанию, использовать ElasticSearch, MongoDB, CouchDB или другую СУБД, только лишь для проверки - будет ли Ваше API работать с этим хранилищем).
-* Простая интеграция Python с **Jupyter Kernels** для разработки удалённо или в Docker с расширениями похожими на Atom Hydrogen или Visual Studio Code Jupyter.
-* Фронтенд построен на фреймворке **Vue**:
- * Сгенерирован с помощью Vue CLI.
- * Поддерживает **аутентификацию с помощью JWT-токенов**.
- * Страница логина.
- * Перенаправление на страницу главной панели мониторинга после логина.
- * Главная страница мониторинга с возможностью создания и изменения пользователей.
- * Пользователь может изменять свои данные.
- * **Vuex**.
- * **Vue-router**.
- * **Vuetify** для конструирования красивых компонентов страниц.
- * **TypeScript**.
- * Сервер Docker основан на **Nginx** (настроен для удобной работы с Vue-router).
- * Многоступенчатая сборка Docker, то есть Вам не нужно сохранять или коммитить скомпилированный код.
- * Тесты фронтенда запускаются во время сборки (можно отключить).
- * Сделан настолько модульно, насколько возможно, поэтому работает "из коробки", но Вы можете повторно сгенерировать фронтенд с помощью Vue CLI или создать то, что Вам нужно и повторно использовать то, что захотите.
-* **PGAdmin** для СУБД PostgreSQL, которые легко можно заменить на PHPMyAdmin и MySQL.
-* **Flower** для отслеживания работы Celery.
-* Балансировка нагрузки между фронтендом и бэкендом с помощью **Traefik**, а значит, Вы можете расположить их на одном домене, разделив url-пути, так как они обслуживаются разными контейнерами.
-* Интеграция с Traefik включает автоматическую генерацию сертификатов Let's Encrypt для поддержки протокола **HTTPS**.
-* GitLab **CI** (непрерывная интеграция), которая включает тестирование фронтенда и бэкенда.
-
-## Full Stack FastAPI Couchbase
-
-GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
-
-⚠️ **ПРЕДУПРЕЖДЕНИЕ** ⚠️
-
-Если Вы начинаете новый проект, ознакомьтесь с представленными здесь альтернативами.
-
-Например, генератор проектов <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> может быть более подходящей альтернативой, так как он активно поддерживается и используется. И он включает в себя все новые возможности и улучшения.
-
-Но никто не запрещает Вам использовать генератор с СУБД Couchbase, возможно, он всё ещё работает нормально. Или у Вас уже есть проект, созданный с помощью этого генератора ранее, и Вы, вероятно, уже обновили его в соответствии со своими потребностями.
-
-Вы можете прочитать о нём больше в документации соответствующего репозитория.
-
-## Full Stack FastAPI MongoDB
-
-...может быть когда-нибудь появится, в зависимости от наличия у меня свободного времени и прочих факторов. 😅 🎉
-
-## Модели машинного обучения на основе spaCy и FastAPI
-
-GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
-
-### Модели машинного обучения на основе spaCy и FastAPI - Особенности
-
-* Интеграция с моделями **spaCy** NER.
-* Встроенный формат запросов к **когнитивному поиску Azure**.
-* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
-* Встроенное развёртывание на основе **Azure DevOps** Kubernetes (AKS) CI/CD.
-* **Многоязычность**. Лёгкий выбор одного из встроенных в spaCy языков во время настройки проекта.
-* **Легко подключить** модели из других фреймворков (Pytorch, Tensorflow) не ограничиваясь spaCy.
+# Шаблон Full Stack FastAPI { #full-stack-fastapi-template }
+
+Шаблоны, хотя обычно поставляются с определённой конфигурацией, спроектированы так, чтобы быть гибкими и настраиваемыми. Это позволяет вам изменять их и адаптировать под требования вашего проекта, что делает их отличной отправной точкой. 🏁
+
+Вы можете использовать этот шаблон для старта: в нём уже сделана значительная часть начальной настройки, безопасность, база данных и несколько эндпоинтов API.
+
+Репозиторий GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
+
+## Шаблон Full Stack FastAPI — Технологический стек и возможности { #full-stack-fastapi-template-technology-stack-and-features }
+
+- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/ru) для бэкенд‑API на Python.
+ - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия с SQL‑базой данных на Python (ORM).
+ - 🔍 [Pydantic](https://docs.pydantic.dev), используется FastAPI, для валидации данных и управления настройками.
+ - 💾 [PostgreSQL](https://www.postgresql.org) в качестве SQL‑базы данных.
+- 🚀 [React](https://react.dev) для фронтенда.
+ - 💃 Используются TypeScript, хуки, [Vite](https://vitejs.dev) и другие части современного фронтенд‑стека.
+ - 🎨 [Chakra UI](https://chakra-ui.com) для компонентов фронтенда.
+ - 🤖 Автоматически сгенерированный фронтенд‑клиент.
+ - 🧪 [Playwright](https://playwright.dev) для End‑to‑End тестирования.
+ - 🦇 Поддержка тёмной темы.
+- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна.
+- 🔒 Безопасное хэширование паролей по умолчанию.
+- 🔑 Аутентификация по JWT‑токенам.
+- 📫 Восстановление пароля по электронной почте.
+- ✅ Тесты с [Pytest](https://pytest.org).
+- 📞 [Traefik](https://traefik.io) в роли обратного прокси / балансировщика нагрузки.
+- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд‑прокси Traefik для автоматического получения сертификатов HTTPS.
+- 🏭 CI (continuous integration) и CD (continuous deployment) на основе GitHub Actions.
-# Введение в аннотации типов Python
+# Введение в типы Python { #python-types-intro }
-Python имееÑ\82 поддеÑ\80жкÑ\83 необÑ\8fзаÑ\82елÑ\8cнÑ\8bÑ\85 анноÑ\82аÑ\86ий Ñ\82ипов.
+Python поддеÑ\80живаеÑ\82 необÑ\8fзаÑ\82елÑ\8cнÑ\8bе «подÑ\81казки Ñ\82ипов» (иÑ\85 Ñ\82акже назÑ\8bваÑ\8eÑ\82 «анноÑ\82аÑ\86иÑ\8fми Ñ\82ипов»).
-**Аннотации типов** являются специальным синтаксисом, который позволяет определять <abbr title="например: str, int, float, bool">тип</abbr> переменной.
+Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять <abbr title="например: str, int, float, bool">тип</abbr> переменной.
-Объявление типов для переменных позволяет улучшить поддержку вашего кода редакторами и различными инструментами.
+Объявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать.
-ÐÑ\82о пÑ\80оÑ\81Ñ\82о **кÑ\80аÑ\82кое Ñ\80Ñ\83ководÑ\81Ñ\82во / напоминание** об анноÑ\82аÑ\86иÑ\8fх типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.
+ÐÑ\82о вÑ\81его лиÑ\88Ñ\8c **кÑ\80аÑ\82кое Ñ\80Ñ\83ководÑ\81Ñ\82во / напоминание** о подÑ\81казках типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.
-**FastAPI** целиком основан на аннотациях типов, у них много выгод и преимуществ.
+**FastAPI** целиком основан на этих подсказках типов — они дают ему множество преимуществ и выгод.
Но даже если вы никогда не используете **FastAPI**, вам будет полезно немного узнать о них.
-/// note
+/// note | Примечание
-Если вы являетесь экспертом в Python и уже знаете всё об аннотациях типов, переходите к следующему разделу.
+Если вы являетесь экспертом в Python и уже знаете всё о подсказках типов, переходите к следующей главе.
///
-## Мотивация
+## Мотивация { #motivation }
Давайте начнем с простого примера:
{* ../../docs_src/python_types/tutorial001.py *}
-
Вызов этой программы выводит:
```
Функция делает следующее:
* Принимает `first_name` и `last_name`.
-* Преобразует первую букву содержимого каждой переменной в верхний регистр с `title()`.
-* <abbr title="Объединяет в одно целое, последовательно, друг за другом.">Соединяет</abbr> их через пробел.
+* Преобразует первую букву каждого значения в верхний регистр с помощью `title()`.
+* <abbr title="Объединяет в одно целое. Содержимое одного — сразу после другого.">Соединяет</abbr> их пробелом посередине.
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
-
-### Отредактируем пример
+### Отредактируем пример { #edit-it }
Это очень простая программа.
В какой-то момент вы бы начали определение функции, у вас были бы готовы параметры...
-Ð\9dо заÑ\82ем вÑ\8b должнÑ\8b вÑ\8bзваÑ\82Ñ\8c «Ñ\82оÑ\82 меÑ\82од, коÑ\82оÑ\80Ñ\8bй пÑ\80еобÑ\80азÑ\83еÑ\82 пеÑ\80вÑ\83Ñ\8e бÑ\83квÑ\83 в веÑ\80Ñ\85ний Ñ\80егиÑ\81Ñ\82Ñ\80».
+Ð\9dо заÑ\82ем нÑ\83жно вÑ\8bзваÑ\82Ñ\8c «Ñ\82оÑ\82 меÑ\82од, коÑ\82оÑ\80Ñ\8bй делаеÑ\82 пеÑ\80вÑ\83Ñ\8e бÑ\83квÑ\83 заглавной».
-Ð\91Ñ\8bло Ñ\8dÑ\82о `upper`? Или `uppercase`? `first_uppercase`? `capitalize`?
+ÐÑ\82о бÑ\8bл `upper`? Или `uppercase`? `first_uppercase`? `capitalize`?
-Тогда вы попробуете с давним другом программиста: автодополнением редактора.
+Тогда вы пробуете старого друга программиста — автозавершение редактора кода.
-Вы вводите первый параметр функции, `first_name`, затем точку (`.`), а затем нажимаете `Ctrl+Space`, чтобы запустить дополнение.
+Вы вводите первый параметр функции, `first_name`, затем точку (`.`) и нажимаете `Ctrl+Space`, чтобы вызвать автозавершение.
-Ð\9dо, к Ñ\81ожалениÑ\8e, ниÑ\87его полезного не вÑ\8bÑ\85одиÑ\82:
+Ð\9dо, к Ñ\81ожалениÑ\8e, ниÑ\87его полезного не наÑ\85одиÑ\82Ñ\81Ñ\8f:
<img src="/img/python-types/image01.png">
-### Добавим типы
+### Добавим типы { #add-types }
-Давайте изменим одну строчку в предыдущей версии.
+Давайте изменим одну строку из предыдущей версии.
-Ð\9cÑ\8b изменим именно Ñ\8dÑ\82оÑ\82 Ñ\84Ñ\80агменÑ\82, паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\84Ñ\83нкÑ\86ии, с:
+Ð\9cÑ\8b поменÑ\8fем Ñ\80овно Ñ\8dÑ\82оÑ\82 Ñ\84Ñ\80агменÑ\82 â\80\94 паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\84Ñ\83нкÑ\86ии â\80\94 с:
```Python
first_name, last_name
first_name: str, last_name: str
```
-Вот и все.
+Вот и всё.
-ÐÑ\82о анноÑ\82аÑ\86ии Ñ\82ипов:
+ÐÑ\82о и еÑ\81Ñ\82Ñ\8c «подÑ\81казки Ñ\82ипов»:
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
-
-Это не то же самое, что объявление значений по умолчанию, например:
+Это не то же самое, что объявление значений по умолчанию, как, например:
```Python
first_name="john", last_name="doe"
Это другая вещь.
-Ð\9cÑ\8b иÑ\81полÑ\8cзÑ\83ем двоеÑ\82оÑ\87иÑ\8f (`:`), а не Ñ\80авно (`=`).
+Ð\97деÑ\81Ñ\8c мÑ\8b иÑ\81полÑ\8cзÑ\83ем двоеÑ\82оÑ\87иÑ\8f (`:`), а не знак Ñ\80авенÑ\81Ñ\82ва (`=`).
-Ð\98 добавление анноÑ\82аÑ\86ий Ñ\82ипов обÑ\8bÑ\87но не менÑ\8fеÑ\82 пÑ\80оиÑ\81Ñ\85одÑ\8fÑ\89его по Ñ\81Ñ\80авнениÑ\8e Ñ\81 Ñ\82ем, Ñ\87Ñ\82о пÑ\80оизоÑ\88ло бÑ\8b без неÑ\91.
+Ð\98 добавление подÑ\81казок Ñ\82ипов обÑ\8bÑ\87но не менÑ\8fеÑ\82 поведение пÑ\80огÑ\80аммÑ\8b по Ñ\81Ñ\80авнениÑ\8e Ñ\81 ваÑ\80ианÑ\82ом без ниÑ\85.
-Ð\9dо Ñ\82епеÑ\80Ñ\8c пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о вÑ\8b Ñ\81нова наÑ\85одиÑ\82еÑ\81Ñ\8c в пÑ\80оÑ\86еÑ\81Ñ\81е Ñ\81озданиÑ\8f Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии, но Ñ\83же Ñ\81 анноÑ\82аÑ\86иÑ\8fми типов.
+Ð\9dо Ñ\82епеÑ\80Ñ\8c пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о вÑ\8b Ñ\81нова поÑ\81еÑ\80едине напиÑ\81аниÑ\8f Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии, Ñ\82олÑ\8cко Ñ\83же Ñ\81 подÑ\81казками типов.
-Ð\92 Ñ\82оÑ\82 же моменÑ\82 вÑ\8b пÑ\8bÑ\82аеÑ\82еÑ\81Ñ\8c запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c авÑ\82одополнение Ñ\81 помоÑ\89Ñ\8cÑ\8e `Ctrl+Space` и вÑ\8b видите:
+Ð\92 Ñ\82оÑ\82 же моменÑ\82 вÑ\8b пÑ\80обÑ\83еÑ\82е вÑ\8bзваÑ\82Ñ\8c авÑ\82озавеÑ\80Ñ\88ение Ñ\81 помоÑ\89Ñ\8cÑ\8e `Ctrl+Space` â\80\94 и видите:
<img src="/img/python-types/image02.png">
-Ð\9fÑ\80и Ñ\8dÑ\82ом вÑ\8b можеÑ\82е пÑ\80оÑ\81маÑ\82Ñ\80иваÑ\82Ñ\8c ваÑ\80ианÑ\82Ñ\8b, пока не найдÑ\91Ñ\82е подÑ\85одÑ\8fÑ\89ий:
+С Ñ\8dÑ\82им вÑ\8b можеÑ\82е пÑ\80окÑ\80Ñ\83Ñ\87иваÑ\82Ñ\8c ваÑ\80ианÑ\82Ñ\8b, пока не найдÑ\91Ñ\82е Ñ\82оÑ\82 Ñ\81амÑ\8bй:
<img src="/img/python-types/image03.png">
-## Больше мотивации
+## Больше мотивации { #more-motivation }
-Проверьте эту функцию, она уже имеет аннотации типов:
+Посмотрите на эту функцию — у неё уже есть подсказки типов:
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
-
-Поскольку редактор знает типы переменных, вы получаете не только дополнение, но и проверки ошибок:
+Так как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок:
<img src="/img/python-types/image04.png">
-ТепеÑ\80Ñ\8c вÑ\8b знаеÑ\82е, Ñ\87Ñ\82о вам нÑ\83жно иÑ\81пÑ\80авиÑ\82Ñ\8c, пÑ\80еобÑ\80азовав `age` в Ñ\81Ñ\82Ñ\80окÑ\83 Ñ\81 `str(age)`:
+ТепеÑ\80Ñ\8c вÑ\8b знаеÑ\82е, Ñ\87Ñ\82о нÑ\83жно иÑ\81пÑ\80авиÑ\82Ñ\8c â\80\94 пÑ\80еобÑ\80азоваÑ\82Ñ\8c `age` в Ñ\81Ñ\82Ñ\80окÑ\83 Ñ\81 помоÑ\89Ñ\8cÑ\8e `str(age)`:
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
+## Объявление типов { #declaring-types }
-## Объявление типов
-
-Вы только что видели основное место для объявления подсказок типов. В качестве параметров функции.
+Вы только что увидели основное место, где объявляют подсказки типов — параметры функции.
-ÐÑ\82о Ñ\82акже оÑ\81новное меÑ\81Ñ\82о, где вÑ\8b можете использовать их с **FastAPI**.
+ÐÑ\82о Ñ\82акже оÑ\81новное меÑ\81Ñ\82о, где вÑ\8b бÑ\83дете использовать их с **FastAPI**.
-### Простые типы
+### Простые типы { #simple-types }
-Ð\92Ñ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c вÑ\81е Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе Ñ\82ипÑ\8b Python, а не только `str`.
+Ð\92Ñ\8b можеÑ\82е обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c вÑ\81е Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе Ñ\82ипÑ\8b Python, не только `str`.
-Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c, к пÑ\80имеÑ\80Ñ\83:
+Ð\9cожно иÑ\81полÑ\8cзоваÑ\82Ñ\8c, напÑ\80имеÑ\80:
* `int`
* `float`
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
+### Generic-типы с параметрами типов { #generic-types-with-type-parameters }
+
+Есть структуры данных, которые могут содержать другие значения, например, `dict`, `list`, `set` и `tuple`. И внутренние значения тоже могут иметь свой тип.
+
+Такие типы, которые содержат внутренние типы, называют «**generic**»-типами. И их можно объявлять, в том числе с указанием внутренних типов.
+
+Чтобы объявлять эти типы и их внутренние типы, вы можете использовать стандартный модуль Python `typing`. Он существует специально для поддержки подсказок типов.
+
+#### Новые версии Python { #newer-versions-of-python }
+
+Синтаксис с использованием `typing` **совместим** со всеми версиями, от Python 3.6 до самых новых, включая Python 3.9, Python 3.10 и т.д.
-### Generic-типы с параметрами типов
+По мере развития Python **новые версии** получают улучшенную поддержку этих аннотаций типов, и во многих случаях вам даже не нужно импортировать и использовать модуль `typing`, чтобы объявлять аннотации типов.
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83Ñ\8eÑ\82 некоÑ\82оÑ\80Ñ\8bе Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80Ñ\8b даннÑ\8bÑ\85, коÑ\82оÑ\80Ñ\8bе могÑ\83Ñ\82 Ñ\81одеÑ\80жаÑ\82Ñ\8c дÑ\80Ñ\83гие знаÑ\87ениÑ\8f, напÑ\80имеÑ\80, `dict`, `list`, `set` и `tuple`. Ð\98 внÑ\83Ñ\82Ñ\80енние знаÑ\87ениÑ\8f Ñ\82оже могÑ\83Ñ\82 имеÑ\82Ñ\8c Ñ\81вой Ñ\82ип.
+Ð\95Ñ\81ли вÑ\8b можеÑ\82е вÑ\8bбÑ\80аÑ\82Ñ\8c более Ñ\81вежÑ\83Ñ\8e веÑ\80Ñ\81иÑ\8e Python длÑ\8f пÑ\80оекÑ\82а, вÑ\8b полÑ\83Ñ\87иÑ\82е дополниÑ\82елÑ\8cнÑ\83Ñ\8e пÑ\80оÑ\81Ñ\82оÑ\82Ñ\83.
-ЧÑ\82обÑ\8b обÑ\8aÑ\8fвиÑ\82Ñ\8c Ñ\8dÑ\82и Ñ\82ипÑ\8b и внÑ\83Ñ\82Ñ\80енние Ñ\82ипÑ\8b, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bй Python-модÑ\83лÑ\8c `typing`.
+Ð\92о вÑ\81ей докÑ\83менÑ\82аÑ\86ии еÑ\81Ñ\82Ñ\8c пÑ\80имеÑ\80Ñ\8b, Ñ\81овмеÑ\81Ñ\82имÑ\8bе Ñ\81 каждой веÑ\80Ñ\81ией Python (когда еÑ\81Ñ\82Ñ\8c Ñ\80азлиÑ\87иÑ\8f).
-Ð\9eн Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 Ñ\81пеÑ\86иалÑ\8cно длÑ\8f поддеÑ\80жки подÑ\81казок Ñ\8dÑ\82иÑ\85 Ñ\82ипов.
+Ð\9dапÑ\80имеÑ\80, «**Python 3.6+**» ознаÑ\87аеÑ\82 Ñ\81овмеÑ\81Ñ\82имоÑ\81Ñ\82Ñ\8c Ñ\81 Python 3.6 и вÑ\8bÑ\88е (вклÑ\8eÑ\87аÑ\8f 3.7, 3.8, 3.9, 3.10 и Ñ\82.д.). Ð\90 «**Python 3.9+**» â\80\94 Ñ\81овмеÑ\81Ñ\82имоÑ\81Ñ\82Ñ\8c Ñ\81 Python 3.9 и вÑ\8bÑ\88е (вклÑ\8eÑ\87аÑ\8f 3.10 и Ñ\82.п.).
-#### `List`
+Если вы можете использовать **последние версии Python**, используйте примеры для самой новой версии — у них будет **самый лучший и простой синтаксис**, например, «**Python 3.10+**».
+
+#### List { #list }
+
+Например, давайте определим переменную как `list` из `str`.
+
+//// tab | Python 3.9+
+
+Объявите переменную с тем же синтаксисом двоеточия (`:`).
+
+В качестве типа укажите `list`.
+
+Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках:
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial006_py39.py!}
+```
-Например, давайте определим переменную как `list`, состоящий из `str`.
+////
-Импортируйте `List` из `typing` (с заглавной `L`):
+//// tab | Python 3.8+
-{* ../../docs_src/python_types/tutorial006.py hl[1] *}
+Из `typing` импортируйте `List` (с заглавной `L`):
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial006.py!}
+```
Объявите переменную с тем же синтаксисом двоеточия (`:`).
-В качестве типа укажите `List`.
+В качестве типа используйте `List`, который вы импортировали из `typing`.
-Ð\9fоÑ\81колÑ\8cкÑ\83 Ñ\81пиÑ\81ок Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\82ипом, Ñ\81одеÑ\80жаÑ\89им некоÑ\82оÑ\80Ñ\8bе внÑ\83Ñ\82Ñ\80енние Ñ\82ипÑ\8b, вÑ\8b помеÑ\89аеÑ\82е иÑ\85 в квадÑ\80аÑ\82нÑ\8bе Ñ\81кобки:
+Так как Ñ\81пиÑ\81ок â\80\94 Ñ\8dÑ\82о Ñ\82ип, Ñ\81одеÑ\80жаÑ\89ий внÑ\83Ñ\82Ñ\80енние Ñ\82ипÑ\8b, Ñ\83кажиÑ\82е иÑ\85 в квадÑ\80аÑ\82нÑ\8bÑ\85 Ñ\81кобкаÑ\85:
-{* ../../docs_src/python_types/tutorial006.py hl[4] *}
+```Python hl_lines="4"
+{!> ../../docs_src/python_types/tutorial006.py!}
+```
+////
-/// tip
+/// info | Информация
Эти внутренние типы в квадратных скобках называются «параметрами типов».
-В этом случае `str` является параметром типа, передаваемым в `List`.
+В данном случае `str` — это параметр типа, передаваемый в `List` (или `list` в Python 3.9 и выше).
///
-Это означает: "переменная `items` является `list`, и каждый из элементов этого списка является `str`".
+Это означает: «переменная `items` — это `list`, и каждый элемент этого списка — `str`».
+
+/// tip | Совет
+
+Если вы используете Python 3.9 или выше, вам не нужно импортировать `List` из `typing`, можно использовать обычный встроенный тип `list`.
+
+///
-Ð\95Ñ\81ли вÑ\8b бÑ\83деÑ\82е Ñ\82ак поÑ\81Ñ\82Ñ\83паÑ\82Ñ\8c, Ñ\80едакÑ\82оÑ\80 можеÑ\82 оказÑ\8bваÑ\82Ñ\8c поддеÑ\80жкÑ\83 даже при обработке элементов списка:
+Таким обÑ\80азом, ваÑ\88 Ñ\80едакÑ\82оÑ\80 кода Ñ\81можеÑ\82 помогаÑ\82Ñ\8c даже при обработке элементов списка:
<img src="/img/python-types/image05.png">
-Без типов добиться этого практически невозможно.
+Без типов добиться этого почти невозможно.
+
+Обратите внимание, что переменная `item` — один из элементов списка `items`.
-Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о пеÑ\80еменнаÑ\8f `item` Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f одним из Ñ\8dлеменÑ\82ов Ñ\81пиÑ\81ка `items`.
+Ð\98 вÑ\81Ñ\91 же Ñ\80едакÑ\82оÑ\80 кода знаеÑ\82, Ñ\87Ñ\82о Ñ\8dÑ\82о `str`, и даÑ\91Ñ\82 Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89Ñ\83Ñ\8e поддеÑ\80жкÑ\83.
-И все же редактор знает, что это `str`, и поддерживает это.
+#### Tuple и Set { #tuple-and-set }
-#### `Tuple` и `Set`
+Аналогично вы бы объявили `tuple` и `set`:
-Вы бы сделали то же самое, чтобы объявить `tuple` и `set`:
+//// tab | Python 3.9+
-{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial007_py39.py!}
+```
+////
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial007.py!}
+```
+
+////
Это означает:
-* Переменная `items_t` является `tuple` с 3 элементами: `int`, другим `int` и `str`.
-* Переменная `items_s` является `set` и каждый элемент имеет тип `bytes`.
+* Переменная `items_t` — это `tuple` из 3 элементов: `int`, ещё один `int` и `str`.
+* Переменная `items_s` — это `set`, и каждый элемент имеет тип `bytes`.
-#### `Dict`
+#### Dict { #dict }
-Чтобы определить `dict`, вы передаёте 2 параметра типов, разделённых запятыми.
+Чтобы определить `dict`, вы передаёте 2 параметра типов, разделённые запятой.
-Первый параметр типа предназначен для ключей `dict`.
+Первый параметр типа — для ключей `dict`.
-Второй параметр типа предназначен для значений `dict`:
+Второй параметр типа — для значений `dict`:
-{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
+//// tab | Python 3.9+
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial008_py39.py!}
+```
+////
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial008.py!}
+```
+
+////
Это означает:
-* Переменная `prices` является `dict`:
- * Ð\9aлÑ\8eÑ\87и Ñ\8dÑ\82ого `dict` имеÑ\8eÑ\82 Ñ\82ип `str` (Ñ\81кажем, название каждого Ñ\8dлеменÑ\82а).
+* Переменная `prices` — это `dict`:
+ * Ð\9aлÑ\8eÑ\87и Ñ\8dÑ\82ого `dict` имеÑ\8eÑ\82 Ñ\82ип `str` (Ñ\81кажем, название каждой позиÑ\86ии).
* Значения этого `dict` имеют тип `float` (скажем, цена каждой позиции).
-#### `Optional`
+#### Union { #union }
+
+Вы можете объявить, что переменная может быть **одним из нескольких типов**, например, `int` или `str`.
+
+В Python 3.6 и выше (включая Python 3.10) вы можете использовать тип `Union` из `typing` и перечислить в квадратных скобках все допустимые типы.
+
+В Python 3.10 также появился **новый синтаксис**, где допустимые типы можно указать через <abbr title='также называется «побитовый оператор OR», но это значение здесь нерелевантно'>вертикальную черту (`|`)</abbr>.
+
+//// tab | Python 3.10+
-Вы также можете использовать `Optional`, чтобы объявить, что переменная имеет тип, например, `str`, но это является «необязательным», что означает, что она также может быть `None`:
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial008b_py310.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial008b.py!}
+```
+
+////
+
+В обоих случаях это означает, что `item` может быть `int` или `str`.
+
+#### Возможно `None` { #possibly-none }
+
+Вы можете объявить, что значение может иметь определённый тип, например `str`, но также может быть и `None`.
+
+В Python 3.6 и выше (включая Python 3.10) это можно объявить, импортировав и используя `Optional` из модуля `typing`.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009.py!}
```
-Использование `Optional[str]` вместо просто `str` позволит редактору помочь вам в обнаружении ошибок, в которых вы могли бы предположить, что значение всегда является `str`, хотя на самом деле это может быть и `None`.
+Использование `Optional[str]` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`.
+
+`Optional[Something]` — это на самом деле сокращение для `Union[Something, None]`, они эквивалентны.
+
+Это также означает, что в Python 3.10 вы можете использовать `Something | None`:
+
+//// tab | Python 3.10+
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial009_py310.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial009.py!}
+```
+
+////
+
+//// tab | Python 3.8+ альтернативный вариант
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial009b.py!}
+```
+
+////
+
+#### Использовать `Union` или `Optional` { #using-union-or-optional }
+
+Если вы используете версию Python ниже 3.10, вот совет с моей весьма **субъективной** точки зрения:
+
+* 🚨 Избегайте использования `Optional[SomeType]`
+* Вместо этого ✨ **используйте `Union[SomeType, None]`** ✨.
+
+Оба варианта эквивалентны и внутри одинаковы, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «**optional**» («необязательный») может навести на мысль, что значение необязательное, хотя на самом деле оно означает «может быть `None`», даже если параметр не является необязательным и всё ещё обязателен.
+
+Мне кажется, `Union[SomeType, None]` более явно выражает смысл.
+
+Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваши коллеги думаете о коде.
+
+В качестве примера возьмём эту функцию:
+
+{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *}
+
+Параметр `name` определён как `Optional[str]`, но он **не необязательный** — вы не можете вызвать функцию без этого параметра:
+
+```Python
+say_hi() # О нет, это вызывает ошибку! 😱
+```
+
+Параметр `name` всё ещё **обязателен** (не *optional*), потому что у него нет значения по умолчанию. При этом `name` принимает `None` как значение:
+
+```Python
+say_hi(name=None) # Это работает, None допустим 🎉
+```
+
+Хорошая новость: как только вы перейдёте на Python 3.10, об этом можно не переживать — вы сможете просто использовать `|` для объединения типов:
+
+{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
+
+И тогда вам не придётся задумываться о названиях вроде `Optional` и `Union`. 😎
+
+#### Generic-типы { #generic-types }
+
+Типы, которые принимают параметры типов в квадратных скобках, называются **Generic-типами** или **Generics**, например:
+
+//// tab | Python 3.10+
+
+Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
+
+* `list`
+* `tuple`
+* `set`
+* `dict`
-#### Generic-типы
+И, как и в Python 3.8, из модуля `typing`:
-Эти типы принимают параметры в квадратных скобках:
+* `Union`
+* `Optional` (так же, как в Python 3.8)
+* ...и другие.
+
+В Python 3.10, как альтернативу generics `Union` и `Optional`, можно использовать <abbr title='также называется «побитовый оператор OR», но это значение здесь нерелевантно'>вертикальную черту (`|`)</abbr> для объявления объединений типов — это гораздо лучше и проще.
+
+////
+
+//// tab | Python 3.9+
+
+Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
+
+* `list`
+* `tuple`
+* `set`
+* `dict`
+
+И, как и в Python 3.8, из модуля `typing`:
+
+* `Union`
+* `Optional`
+* ...и другие.
+
+////
+
+//// tab | Python 3.8+
* `List`
* `Tuple`
* `Set`
* `Dict`
+* `Union`
* `Optional`
-* ...и др.
+* ...и другие.
-называются **Generic-типами** или **Generics**.
+////
-### Классы как типы
+### Классы как типы { #classes-as-types }
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е обÑ\8aÑ\8fвить класс как тип переменной.
+Ð\92Ñ\8b Ñ\82акже можеÑ\82е обÑ\8aÑ\8fвлÑ\8fть класс как тип переменной.
-Ð\94опÑ\83Ñ\81Ñ\82им, Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c клаÑ\81Ñ\81 `Person` Ñ\81 полем `name`:
+Ð\94опÑ\83Ñ\81Ñ\82им, Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c клаÑ\81Ñ\81 `Person` Ñ\81 именем:
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
-
Тогда вы можете объявить переменную типа `Person`:
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
-
-И снова вы получаете полную поддержку редактора:
+И снова вы получите полную поддержку редактора кода:
<img src="/img/python-types/image06.png">
-## Pydantic-модели
+Обратите внимание, что это означает: «`one_person` — это **экземпляр** класса `Person`».
+
+Это не означает: «`one_person` — это **класс** с именем `Person`».
-<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> является Python-библиотекой для выполнения валидации данных.
+## Pydantic-модели { #pydantic-models }
+
+<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> — это библиотека Python для валидации данных.
Вы объявляете «форму» данных как классы с атрибутами.
-И каждый атрибут имеет тип.
+И у каждого атрибута есть тип.
-Затем вы создаете экземпляр этого класса с некоторыми значениями, и он проверяет значения, преобразует их в соответствующий тип (если все верно) и предоставляет вам объект со всеми данными.
+Затем вы создаёте экземпляр этого класса с некоторыми значениями — он провалидирует значения, преобразует их к соответствующему типу (если это применимо) и вернёт вам объект со всеми данными.
-Ð\98 вÑ\8b полÑ\83Ñ\87аеÑ\82е полнÑ\83Ñ\8e поддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а длÑ\8f Ñ\8dÑ\82ого иÑ\82огового объекта.
+Ð\98 вÑ\8b полÑ\83Ñ\87иÑ\82е полнÑ\83Ñ\8e поддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а кода длÑ\8f Ñ\8dÑ\82ого Ñ\80езÑ\83лÑ\8cÑ\82иÑ\80Ñ\83Ñ\8eÑ\89его объекта.
-Ð\92зÑ\8fÑ\82о из официальной документации Pydantic:
+Ð\9fÑ\80имеÑ\80 из официальной документации Pydantic:
-{* ../../docs_src/python_types/tutorial011.py *}
+//// tab | Python 3.10+
+```Python
+{!> ../../docs_src/python_types/tutorial011_py310.py!}
+```
+
+////
-/// info
+//// tab | Python 3.9+
-Чтобы узнать больше о <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, читайте его документацию</a>.
+```Python
+{!> ../../docs_src/python_types/tutorial011_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+{!> ../../docs_src/python_types/tutorial011.py!}
+```
+
+////
+
+/// info | Информация
+
+Чтобы узнать больше о <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, ознакомьтесь с его документацией</a>.
///
Вы увидите намного больше всего этого на практике в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
-## Аннотации типов в **FastAPI**
+/// tip | Совет
+
+У Pydantic есть особое поведение, когда вы используете `Optional` или `Union[Something, None]` без значения по умолчанию. Подробнее читайте в документации Pydantic: <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>.
+
+///
+
+## Подсказки типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
+
+В Python также есть возможность добавлять **дополнительные <abbr title="Данные о данных, в данном случае — информация о типе, например описание.">метаданные</abbr>** к подсказкам типов с помощью `Annotated`.
+
+//// tab | Python 3.9+
+
+В Python 3.9 `Annotated` входит в стандартную библиотеку, поэтому вы можете импортировать его из `typing`.
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial013_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+В версиях ниже Python 3.9 импортируйте `Annotated` из `typing_extensions`.
+
+Он уже будет установлен вместе с **FastAPI**.
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial013.py!}
+```
+
+////
+
+Сам Python ничего не делает с `Annotated`. А для редакторов кода и других инструментов тип по-прежнему `str`.
+
+Но вы можете использовать это место в `Annotated`, чтобы передать **FastAPI** дополнительные метаданные о том, как вы хотите, чтобы ваше приложение себя вело.
+
+Важно помнить, что **первый параметр типа**, который вы передаёте в `Annotated`, — это **фактический тип**. Всё остальное — просто метаданные для других инструментов.
+
+Пока вам достаточно знать, что `Annotated` существует и это — стандартный Python. 😎
+
+Позже вы увидите, насколько это **мощно**.
+
+/// tip | Совет
+
+Тот факт, что это **стандартный Python**, означает, что вы по-прежнему получите **лучший возможный разработческий опыт** в вашем редакторе кода, с инструментами для анализа и рефакторинга кода и т.д. ✨
+
+А ещё ваш код будет очень совместим со множеством других инструментов и библиотек Python. 🚀
+
+///
+
+## Аннотации типов в **FastAPI** { #type-hints-in-fastapi }
-**FastAPI** полÑ\83Ñ\87аеÑ\82 пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82ва анноÑ\82аÑ\86ий Ñ\82ипов длÑ\8f вÑ\8bполнениÑ\8f опÑ\80еделÑ\91ннÑ\8bх задач.
+**FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Ñ\8dÑ\82и подÑ\81казки Ñ\82ипов длÑ\8f вÑ\8bполнениÑ\8f неÑ\81колÑ\8cких задач.
-С **FastAPI** вÑ\8b обÑ\8aÑ\8fвлÑ\8fеÑ\82е паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\81 анноÑ\82аÑ\86иÑ\8fми типов и получаете:
+С **FastAPI** вÑ\8b обÑ\8aÑ\8fвлÑ\8fеÑ\82е паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\81 подÑ\81казками типов и получаете:
-* **Поддержку редактора**.
+* **Поддержку редактора кода**.
* **Проверки типов**.
-...и **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Ñ\82оÑ\82 же меÑ\85анизм для:
+...и **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Ñ\8dÑ\82и же обÑ\8aÑ\8fвлениÑ\8f для:
-* **Определения требований**: из параметров пути запроса, параметров запроса, заголовков, зависимостей и т.д.
-* **Ð\9fÑ\80еобÑ\80азованиÑ\8f даннÑ\8bÑ\85**: оÑ\82 запÑ\80оÑ\81а к нÑ\83жному типу.
-* **Ð\92алидаÑ\86ии даннÑ\8bÑ\85**: иÑ\81Ñ\85одÑ\8f из каждого запроса:
- * Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные не являются корректными.
+* **Определения требований**: из path-параметров, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.
+* **Ð\9fÑ\80еобÑ\80азованиÑ\8f даннÑ\8bÑ\85**: из HTTP-запÑ\80оÑ\81а к Ñ\82Ñ\80ебÑ\83емому типу.
+* **Ð\92алидаÑ\86ии даннÑ\8bÑ\85**: пÑ\80иÑ\85одÑ\8fÑ\89иÑ\85 Ñ\81 каждого HTTP-запроса:
+ * Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные некорректны.
* **Документирования** API с использованием OpenAPI:
- * который затем используется пользовательскими интерфейсами автоматической интерактивной документации.
+ * что затем используется пользовательскими интерфейсами автоматической интерактивной документации.
-Ð\92Ñ\81Ñ\91 Ñ\8dÑ\82о можеÑ\82 показаÑ\82Ñ\8cÑ\81Ñ\8f абÑ\81Ñ\82Ñ\80акÑ\82нÑ\8bм. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
+Ð\92Ñ\81Ñ\91 Ñ\8dÑ\82о можеÑ\82 звÑ\83Ñ\87аÑ\82Ñ\8c абÑ\81Ñ\82Ñ\80акÑ\82но. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
-Важно то, что при использовании стандартных типов Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.) **FastAPI** сделает за вас большую часть работы.
+Важно то, что, используя стандартные типы Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.), **FastAPI** сделает за вас большую часть работы.
-/// info
+/// info | Информация
-Если вы уже прошли всё руководство и вернулись, чтобы узнать больше о типах, хорошим ресурсом является <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">«шпаргалка» от `mypy`</a>.
+Если вы уже прошли всё руководство и вернулись, чтобы узнать больше о типах, хорошим ресурсом будет <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">«шпаргалка» от `mypy`</a>.
///
-# Фоновые задачи
+# Фоновые задачи { #background-tasks }
-Ð\92Ñ\8b можеÑ\82е Ñ\81оздаваÑ\82Ñ\8c Ñ\84оновÑ\8bе задаÑ\87и, коÑ\82оÑ\80Ñ\8bе бÑ\83дÑ\83Ñ\82 вÑ\8bполнÑ\8fÑ\82Ñ\81Ñ\8f *поÑ\81ле* возвÑ\80аÑ\89ениÑ\8f оÑ\82веÑ\82а Ñ\81еÑ\80веÑ\80ом.
+Ð\92Ñ\8b можеÑ\82е Ñ\81оздаваÑ\82Ñ\8c Ñ\84оновÑ\8bе задаÑ\87и, коÑ\82оÑ\80Ñ\8bе бÑ\83дÑ\83Ñ\82 вÑ\8bполнÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f поÑ\81ле возвÑ\80аÑ\82а оÑ\82веÑ\82а.
-ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c полезно длÑ\8f Ñ\84Ñ\83нкÑ\86ий, коÑ\82оÑ\80Ñ\8bе должнÑ\8b вÑ\8bполниÑ\82Ñ\8cÑ\81Ñ\8f поÑ\81ле полÑ\83Ñ\87ениÑ\8f запÑ\80оÑ\81а, но ожидание иÑ\85 вÑ\8bполнениÑ\8f необÑ\8fзаÑ\82елÑ\8cно длÑ\8f полÑ\8cзоваÑ\82елÑ\8f.
+ÐÑ\82о полезно длÑ\8f опеÑ\80аÑ\86ий, коÑ\82оÑ\80Ñ\8bе должнÑ\8b пÑ\80оизойÑ\82и поÑ\81ле HTTP-запÑ\80оÑ\81а, но клиенÑ\82Ñ\83 не обÑ\8fзаÑ\82елÑ\8cно ждаÑ\82Ñ\8c иÑ\85 завеÑ\80Ñ\88ениÑ\8f, Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87иÑ\82Ñ\8c оÑ\82веÑ\82.
-Ð\9a пÑ\80имеÑ\80Ñ\83:
+Ð\9dапÑ\80имеÑ\80:
-* Ð\9eÑ\82пÑ\80авка пиÑ\81ем на поÑ\87Ñ\82Ñ\83 поÑ\81ле вÑ\8bполнениÑ\8f какиÑ\85-либо дейÑ\81Ñ\82вий:
- * Т.к. соединение с почтовым сервером и отправка письма идут достаточно "долго" (несколько секунд), вы можете отправить ответ пользователю, а отправку письма выполнить в фоне.
+* УведомлениÑ\8f по Ñ\8dлекÑ\82Ñ\80онной поÑ\87Ñ\82е, оÑ\82пÑ\80авлÑ\8fемÑ\8bе поÑ\81ле вÑ\8bполнениÑ\8f дейÑ\81Ñ\82виÑ\8f:
+ * Так как подключение к почтовому серверу и отправка письма обычно «медленные» (несколько секунд), вы можете сразу вернуть ответ, а отправку уведомления выполнить в фоне.
* Обработка данных:
- * Ð\9a пÑ\80имеÑ\80Ñ\83, еÑ\81ли вÑ\8b полÑ\83Ñ\87аеÑ\82е Ñ\84айл, коÑ\82оÑ\80Ñ\8bй должен пÑ\80ойÑ\82и Ñ\87еÑ\80ез медленнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81, вÑ\8b можеÑ\82е оÑ\82пÑ\80авиÑ\82Ñ\8c оÑ\82веÑ\82 "Accepted" (HTTP 202) и оÑ\82пÑ\80авиÑ\82Ñ\8c Ñ\80абоÑ\82Ñ\83 Ñ\81 Ñ\84айлом в Ñ\84он.
+ * Ð\9dапÑ\80имеÑ\80, еÑ\81ли вÑ\8b полÑ\83Ñ\87аеÑ\82е Ñ\84айл, коÑ\82оÑ\80Ñ\8bй должен пÑ\80ойÑ\82и Ñ\87еÑ\80ез медленнÑ\8bй пÑ\80оÑ\86еÑ\81Ñ\81, вÑ\8b можеÑ\82е веÑ\80нÑ\83Ñ\82Ñ\8c оÑ\82веÑ\82 «Accepted» (HTTP 202) и обÑ\80абоÑ\82аÑ\82Ñ\8c Ñ\84айл в Ñ\84оне.
-## Использование класса `BackgroundTasks`
+## Использование `BackgroundTasks` { #using-backgroundtasks }
-Сначала импортируйте `BackgroundTasks`, потом добавьте в функцию параметр с типом `BackgroundTasks`:
+Сначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`:
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
-**FastAPI** создаст объект класса `BackgroundTasks` для вас и запишет его в параметр.
+**FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр.
-## Создание функции для фоновой задачи
+## Создание функции для фоновой задачи { #create-a-task-function }
-Создайте функцию, которую хотите запустить в фоне.
+Создайте функцию, которую нужно запустить как фоновую задачу.
-Это совершенно обычная функция, которая может принимать параметры.
+Это обычная функция, которая может принимать параметры.
-Ð\9eна можеÑ\82 бÑ\8bÑ\82Ñ\8c как аÑ\81инÑ\85Ñ\80онной `async def`, Ñ\82ак и обÑ\8bÑ\87ной `def` Ñ\84Ñ\83нкÑ\86ией, **FastAPI** знаеÑ\82, как пÑ\80авилÑ\8cно ее выполнить.
+ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c как `async def`, Ñ\82ак и обÑ\8bÑ\87наÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f `def`, **FastAPI** знаеÑ\82, как коÑ\80Ñ\80екÑ\82но еÑ\91 выполнить.
-В нашем примере фоновая задача будет вести запись в файл (симулируя отправку письма).
+В этом случае функция задачи будет записывать данные в файл (имитируя отправку письма).
-Так как операция записи не использует `async` и `await`, мы определим ее как обычную `def`:
+Так как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`:
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
-## Добавление фоновой задачи
+## Добавление фоновой задачи { #add-the-background-task }
-Внутри функции вызовите метод `.add_task()` у объекта *background tasks* и передайте ему функцию, которую хотите выполнить в фоне:
+Внутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`:
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
`.add_task()` принимает следующие аргументы:
-* Функцию, которая будет выполнена в фоне (`write_notification`). Обратите внимание, что передается объект функции, без скобок.
-* Ð\9bÑ\8eбое Ñ\83поÑ\80Ñ\8fдоÑ\87енное колиÑ\87еÑ\81Ñ\82во аÑ\80гÑ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе пÑ\80инимаеÑ\82 Ñ\84Ñ\83нкÑ\86иÑ\8f (`email`).
-* Любое количество именованных аргументов, которые принимает функция (`message="some notification"`).
+* Функцию задачи, которую нужно выполнить в фоне (`write_notification`).
+* Ð\9fоÑ\81ледоваÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c позиÑ\86ионнÑ\8bÑ\85 аÑ\80гÑ\83менÑ\82ов, коÑ\82оÑ\80Ñ\8bе должнÑ\8b бÑ\8bÑ\82Ñ\8c пеÑ\80еданÑ\8b Ñ\84Ñ\83нкÑ\86ии задаÑ\87и, в поÑ\80Ñ\8fдке (`email`).
+* Любые именованные аргументы, которые должны быть переданы функции задачи (`message="some notification"`).
-## Встраивание зависимостей
+## Встраивание зависимостей { #dependency-injection }
-Ð\9aлаÑ\81Ñ\81 `BackgroundTasks` Ñ\82акже Ñ\80абоÑ\82аеÑ\82 Ñ\81 Ñ\81иÑ\81Ñ\82емой вÑ\81Ñ\82Ñ\80аиваниÑ\8f завиÑ\81имоÑ\81Ñ\82ей, вÑ\8b можеÑ\82е опÑ\80еделиÑ\82Ñ\8c `BackgroundTasks` на Ñ\80азнÑ\8bÑ\85 Ñ\83Ñ\80овнÑ\8fÑ\85: как паÑ\80амеÑ\82Ñ\80 Ñ\84Ñ\83нкÑ\86ии, как завимоÑ\81Ñ\82Ñ\8c, как подзавиÑ\81имоÑ\81Ñ\82Ñ\8c и Ñ\82ак далее.
+Ð\98Ñ\81полÑ\8cзование `BackgroundTasks` Ñ\82акже Ñ\80абоÑ\82аеÑ\82 Ñ\81 Ñ\81иÑ\81Ñ\82емой вÑ\81Ñ\82Ñ\80аиваниÑ\8f завиÑ\81имоÑ\81Ñ\82ей, вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 Ñ\82ипа `BackgroundTasks` на неÑ\81колÑ\8cкиÑ\85 Ñ\83Ñ\80овнÑ\8fÑ\85: в Ñ\84Ñ\83нкÑ\86ииâ\80\91обÑ\80абоÑ\82Ñ\87ике пÑ\83Ñ\82и, в завиÑ\81имоÑ\81Ñ\82и (dependable), в подзавиÑ\81имоÑ\81Ñ\82и и Ñ\82. д.
-**FastAPI** знаеÑ\82, Ñ\87Ñ\82о нÑ\83жно Ñ\81делаÑ\82Ñ\8c в каждом Ñ\81лÑ\83Ñ\87ае и как пеÑ\80еиÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82оÑ\82 же обÑ\8aекÑ\82 `BackgroundTasks`, Ñ\82ак Ñ\87Ñ\82обÑ\8b вÑ\81е Ñ\84оновÑ\8bе задаÑ\87и Ñ\81обÑ\80алиÑ\81Ñ\8c и запÑ\83Ñ\81Ñ\82илиÑ\81Ñ\8c вмеÑ\81Ñ\82е в фоне:
+**FastAPI** знаеÑ\82, Ñ\87Ñ\82о делаÑ\82Ñ\8c в каждом Ñ\81лÑ\83Ñ\87ае и как пеÑ\80еиÑ\81полÑ\8cзоваÑ\82Ñ\8c один и Ñ\82оÑ\82 же обÑ\8aекÑ\82, Ñ\82ак Ñ\87Ñ\82обÑ\8b вÑ\81е Ñ\84оновÑ\8bе задаÑ\87и бÑ\8bли обÑ\8aединенÑ\8b и заÑ\82ем вÑ\8bполненÑ\8b в фоне:
-{* ../../docs_src/background_tasks/tutorial002_py310.py hl[11,13,20,23] *}
+{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
-В этом примере сообщения будут записаны в `log.txt` *после* того, как ответ сервера был отправлен.
+В этом примере сообщения будут записаны в файл `log.txt` после отправки ответа.
-Ð\95Ñ\81ли бÑ\8b в запÑ\80оÑ\81 бÑ\8bл пеÑ\80едан query-паÑ\80амеÑ\82Ñ\80 `q`, он бÑ\8b пеÑ\80вÑ\8bми запиÑ\81алÑ\81Ñ\8f в `log.txt` Ñ\84оновой задаÑ\87ей (поÑ\82омÑ\83 Ñ\87Ñ\82о вÑ\8bзÑ\8bваеÑ\82Ñ\81Ñ\8f в завиÑ\81имоÑ\81Ñ\82и `get_query`).
+Ð\95Ñ\81ли в запÑ\80оÑ\81е бÑ\8bла Ñ\81Ñ\82Ñ\80ока запÑ\80оÑ\81а (query), она бÑ\83деÑ\82 запиÑ\81ана в лог Ñ\84оновой задаÑ\87ей.
-Ð\9fоÑ\81ле дÑ\80Ñ\83гаÑ\8f Ñ\84оноваÑ\8f задаÑ\87а, коÑ\82оÑ\80аÑ\8f бÑ\8bла Ñ\81генеÑ\80иÑ\80ована в Ñ\84Ñ\83нкÑ\86ии, запиÑ\88еÑ\82 Ñ\81ообÑ\89ение из паÑ\80амеÑ\82Ñ\80а `email`.
+Ð\97аÑ\82ем дÑ\80Ñ\83гаÑ\8f Ñ\84оноваÑ\8f задаÑ\87а, Ñ\81озданнаÑ\8f в Ñ\84Ñ\83нкÑ\86ииâ\80\91обÑ\80абоÑ\82Ñ\87ике пÑ\83Ñ\82и, запиÑ\88еÑ\82 Ñ\81ообÑ\89ение, иÑ\81полÑ\8cзÑ\83Ñ\8f pathâ\80\91паÑ\80амеÑ\82Ñ\80 `email`.
-## Технические детали
+## Технические детали { #technical-details }
-Ð\9aлаÑ\81Ñ\81 `BackgroundTasks` оÑ\81нован на <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>.
+Ð\9aлаÑ\81Ñ\81 `BackgroundTasks` пÑ\80иÑ\85одиÑ\82 напÑ\80Ñ\8fмÑ\83Ñ\8e из <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>.
-Ð\9eн инÑ\82егÑ\80иÑ\80ован в FastAPI, Ñ\82ак Ñ\87Ñ\82о вÑ\8b можеÑ\82е импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c его пÑ\80Ñ\8fмо из `fastapi` и избежаÑ\82Ñ\8c Ñ\81лÑ\83Ñ\87айного импоÑ\80Ñ\82а `BackgroundTask` (без `s` на конце) из `starlette.background`.
+Ð\9eн импоÑ\80Ñ\82иÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f/вклÑ\8eÑ\87аеÑ\82Ñ\81Ñ\8f пÑ\80Ñ\8fмо в FastAPI, Ñ\87Ñ\82обÑ\8b вÑ\8b могли импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c его из `fastapi` и избежаÑ\82Ñ\8c Ñ\81лÑ\83Ñ\87айного импоÑ\80Ñ\82а алÑ\8cÑ\82еÑ\80наÑ\82ивного `BackgroundTask` (без `s` на конце) из `starlette.background`.
-Ð\9fÑ\80и иÑ\81полÑ\8cзовании `BackgroundTasks` (а не `BackgroundTask`), вам доÑ\81Ñ\82аÑ\82оÑ\87но Ñ\82олÑ\8cко опÑ\80еделиÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 Ñ\84Ñ\83нкÑ\86ии Ñ\81 Ñ\82ипом `BackgroundTasks` и **FastAPI** Ñ\81делаеÑ\82 вÑ\81е за ваÑ\81, Ñ\82акже как пÑ\80и иÑ\81полÑ\8cзовании обÑ\8aекÑ\82а `Request`.
+Ð\98Ñ\81полÑ\8cзÑ\83Ñ\8f Ñ\82олÑ\8cко `BackgroundTasks` (а не `BackgroundTask`), его можно пÑ\80именÑ\8fÑ\82Ñ\8c как паÑ\80амеÑ\82Ñ\80 Ñ\84Ñ\83нкÑ\86ииâ\80\91обÑ\80абоÑ\82Ñ\87ика пÑ\83Ñ\82и, и **FastAPI** Ñ\81делаеÑ\82 оÑ\81Ñ\82алÑ\8cное за ваÑ\81, как пÑ\80и иÑ\81полÑ\8cзовании обÑ\8aекÑ\82а `Request` напÑ\80Ñ\8fмÑ\83Ñ\8e.
-Ð\92Ñ\8b вÑ\81е Ñ\80авно можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c `BackgroundTask` из `starlette` в FastAPI, но вам пÑ\80идеÑ\82Ñ\81Ñ\8f Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно Ñ\81оздаваÑ\82Ñ\8c обÑ\8aекÑ\82 Ñ\84оновой задаÑ\87и и вÑ\80Ñ\83Ñ\87нÑ\83Ñ\8e обÑ\80абоÑ\82аÑ\82Ñ\8c `Response` внÑ\83Ñ\82Ñ\80и него.
+Ð\9fоâ\80\91пÑ\80ежнемÑ\83 можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c один `BackgroundTask` в FastAPI, но Ñ\82огда вам нÑ\83жно Ñ\81оздаÑ\82Ñ\8c обÑ\8aекÑ\82 в Ñ\81воÑ\91м коде и веÑ\80нÑ\83Ñ\82Ñ\8c Starlette `Response`, вклÑ\8eÑ\87аÑ\8eÑ\89ий его.
-Ð\92Ñ\8b можеÑ\82е подÑ\80обнее изÑ\83Ñ\87иÑ\82Ñ\8c его в <a href="https://www.starlette.io/background/" class="external-link" target="_blank">Ð\9eÑ\84иÑ\86иалÑ\8cной докÑ\83менÑ\82аÑ\86ии Starlette длÑ\8f BackgroundTasks</a>.
+Ð\9fодÑ\80обнее Ñ\81м. в <a href="https://www.starlette.io/background/" class="external-link" target="_blank">оÑ\84иÑ\86иалÑ\8cной докÑ\83менÑ\82аÑ\86ии Starlette по Ñ\84оновÑ\8bм задаÑ\87ам</a>.
-## Предостережение
+## Предостережение { #caveat }
-Если вам нужно выполнить тяжелые вычисления в фоне, которым необязательно быть запущенными в одном процессе с приложением **FastAPI** (к примеру, вам не нужны обрабатываемые переменные или вы не хотите делиться памятью процесса и т.д.), вы можете использовать более серьезные инструменты, такие как <a href="https://docs.celeryproject.org" class="external-link" target="_blank">Celery</a>.
+Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т. п.), вам могут подойти более мощные инструменты, такие как <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
-Ð\98Ñ\85 Ñ\82Ñ\8fжелее наÑ\81Ñ\82Ñ\80аиваÑ\82Ñ\8c, Ñ\82акже им нÑ\83жен бÑ\80океÑ\80 Ñ\81ообÑ\89ений наподобие RabbitMQ или Redis, но заÑ\82о они позволÑ\8fÑ\8eÑ\82 вам запÑ\83Ñ\81каÑ\82Ñ\8c Ñ\84оновÑ\8bе задаÑ\87и в неÑ\81колÑ\8cкиÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81аÑ\85 и даже на нескольких серверах.
+Ð\9eни обÑ\8bÑ\87но Ñ\82Ñ\80ебÑ\83Ñ\8eÑ\82 более Ñ\81ложной конÑ\84игÑ\83Ñ\80аÑ\86ии, менеджеÑ\80а оÑ\87еÑ\80еди Ñ\81ообÑ\89ений/заданий (напÑ\80имеÑ\80, RabbitMQ или Redis), но позволÑ\8fÑ\8eÑ\82 запÑ\83Ñ\81каÑ\82Ñ\8c Ñ\84оновÑ\8bе задаÑ\87и в неÑ\81колÑ\8cкиÑ\85 пÑ\80оÑ\86еÑ\81Ñ\81аÑ\85 и, Ñ\87Ñ\82о оÑ\81обенно важно, на нескольких серверах.
-Ð\9dо еÑ\81ли вам нÑ\83жен доÑ\81Ñ\82Ñ\83п к обÑ\89им пеÑ\80еменнÑ\8bм и обÑ\8aекÑ\82ам ваÑ\88его **FastAPI** пÑ\80иложениÑ\8f или вам нÑ\83жно вÑ\8bполнÑ\8fÑ\82Ñ\8c пÑ\80оÑ\81Ñ\82Ñ\8bе Ñ\84оновÑ\8bе задаÑ\87и (наподобие оÑ\82пÑ\80авки пиÑ\81Ñ\8cма из пÑ\80имеÑ\80а) вы можете просто использовать `BackgroundTasks`.
+Ð\9dо еÑ\81ли вам нÑ\83жен доÑ\81Ñ\82Ñ\83п к пеÑ\80еменнÑ\8bм и обÑ\8aекÑ\82ам из Ñ\82ого же пÑ\80иложениÑ\8f **FastAPI**, или нÑ\83жно вÑ\8bполнÑ\8fÑ\82Ñ\8c неболÑ\8cÑ\88ие Ñ\84оновÑ\8bе задаÑ\87и (напÑ\80имеÑ\80, оÑ\82пÑ\80авкÑ\83 emailâ\80\91Ñ\83ведомлениÑ\8f), вы можете просто использовать `BackgroundTasks`.
-## Резюме
+## Резюме { #recap }
-Ð\94лÑ\8f Ñ\81озданиÑ\8f Ñ\84оновÑ\8bÑ\85 задаÑ\87 вам необÑ\85одимо импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c `BackgroundTasks` и добавиÑ\82Ñ\8c его в Ñ\84Ñ\83нкÑ\86иÑ\8e, как паÑ\80амеÑ\82Ñ\80 Ñ\81 Ñ\82ипом `BackgroundTasks`.
+Ð\98мпоÑ\80Ñ\82иÑ\80Ñ\83йÑ\82е и иÑ\81полÑ\8cзÑ\83йÑ\82е `BackgroundTasks` Ñ\81 паÑ\80амеÑ\82Ñ\80ами в Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85â\80\91обÑ\80абоÑ\82Ñ\87икаÑ\85 пÑ\83Ñ\82и и завиÑ\81имоÑ\81Ñ\82Ñ\8fÑ\85, Ñ\87Ñ\82обÑ\8b добавлÑ\8fÑ\82Ñ\8c Ñ\84оновÑ\8bе задаÑ\87и.
-# Большие приложения, в которых много файлов
+# Большие приложения, в которых много файлов { #bigger-applications-multiple-files }
При построении приложения или веб-API нам редко удается поместить всё в один файл.
///
-## Пример структуры приложения
+## Пример структуры приложения { #an-example-file-structure }
Давайте предположим, что наше приложение имеет следующую структуру:
│ └── admin.py # суб-модуль "admin", напр.: import app.internal.admin
```
-## `APIRouter`
+## `APIRouter` { #apirouter }
Давайте предположим, что для работы с пользователями используется отдельный файл (суб-модуль) `/app/routers/users.py`.
С помощью `APIRouter` вы можете создать *операции пути* (*эндпоинты*) для данного модуля.
-
-### Импорт `APIRouter`
+### Импорт `APIRouter` { #import-apirouter }
Точно также, как и в случае с классом `FastAPI`, вам нужно импортировать и создать объект класса `APIRouter`.
{!../../docs_src/bigger_applications/app/routers/users.py!}
```
-### Создание *эндпоинтов* с помощью `APIRouter`
+### Создание *эндпоинтов* с помощью `APIRouter` { #path-operations-with-apirouter }
В дальнейшем используйте `APIRouter` для объявления *эндпоинтов*, точно также, как вы используете класс `FastAPI`:
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и создадим ещё один модуль с `APIRouter`.
-## Зависимости
+## Зависимости { #dependencies }
Нам понадобятся некоторые зависимости, которые мы будем использовать в разных местах нашего приложения.
Для простоты мы воспользовались неким воображаемым заголовоком.
-В реальных случаях для получения наилучших результатов используйте интегрированные утилиты обеспечения безопасности [Security utilities](security/index.md){.internal-link target=_blank}.
+В реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md){.internal-link target=_blank}.
///
-## Ещё один модуль с `APIRouter`
+## Ещё один модуль с `APIRouter` { #another-module-with-apirouter }
Давайте также предположим, что у вас есть *эндпоинты*, отвечающие за обработку "items", и они находятся в модуле `app/routers/items.py`.
/// tip | Подсказка
-Обратите внимание, что также, как и в случае с зависимостями в декораторах *эндпоинтов* ([dependencies in *path operation decorators*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), никакого значения в *функцию эндпоинта* передано не будет.
+Обратите внимание, что также, как и в случае с зависимостями в декораторах *эндпоинтов* ([зависимости в декораторах операций пути](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), никакого значения в *функцию эндпоинта* передано не будет.
///
* Каждый из них будет включать предопределенные ответы `responses`.
* Каждый *эндпоинт* будет иметь список зависимостей (`dependencies`), исполняемых перед вызовом *эндпоинта*.
* Если вы определили зависимости в самой операции пути, **то она также будет выполнена**.
- * Сначала выполняются зависимости маршрутизатора, затем вызываются зависимости, определенные в декораторе *эндпоинта* ([`dependencies` in the decorator](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), и, наконец, обычные параметрические зависимости.
- * Вы также можете добавить зависимости безопасности с областями видимости (`scopes`) [`Security` dependencies with `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
+ * Сначала выполняются зависимости маршрутизатора, затем вызываются [зависимости в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и, наконец, обычные параметрические зависимости.
+ * Вы также можете добавить [зависимости `Security` с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
/// tip | Подсказка
///
-### Импорт зависимостей
+### Импорт зависимостей { #import-the-dependencies }
Наш код находится в модуле `app.routers.items` (файл `app/routers/items.py`).
{!../../docs_src/bigger_applications/app/routers/items.py!}
```
-#### Как работает относительный импорт?
+#### Как работает относительный импорт? { #how-relative-imports-work }
/// tip | Подсказка
Теперь вы знаете, как работает импорт в Python, и сможете использовать относительное импортирование в своих собственных приложениях любого уровня сложности. 🤓
-### Добавление пользовательских тегов (`tags`), ответов (`responses`) и зависимостей (`dependencies`)
+### Добавление пользовательских тегов (`tags`), ответов (`responses`) и зависимостей (`dependencies`) { #add-some-custom-tags-responses-and-dependencies }
Мы не будем добавлять префикс `/items` и список тегов `tags=["items"]` для каждого *эндпоинта*, т.к. мы уже их добавили с помощью `APIRouter`.
///
-## Модуль main в `FastAPI`
+## Модуль main в `FastAPI` { #the-main-fastapi }
Теперь давайте посмотрим на модуль `app/main.py`.
И теперь, когда большая часть логики приложения разделена на отдельные модули, основной файл `app/main.py` будет достаточно простым.
-### Импорт `FastAPI`
+### Импорт `FastAPI` { #import-fastapi }
Вы импортируете и создаете класс `FastAPI` как обычно.
-Мы даже можем объявить глобальные зависимости [global dependencies](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого отдельного маршрутизатора:
+Мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого отдельного маршрутизатора:
```Python hl_lines="1 3 7" title="app/main.py"
{!../../docs_src/bigger_applications/app/main.py!}
```
-### Импорт `APIRouter`
+### Импорт `APIRouter` { #import-the-apirouter }
Теперь мы импортируем другие суб-модули, содержащие `APIRouter`:
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются суб-модулями одного и того же Python-пакета `app`, то мы сможем их импортировать, воспользовавшись операцией относительного импорта `.`.
-### Как работает импорт?
+### Как работает импорт? { #how-the-importing-works }
Данная строка кода:
///
-### Избегайте конфликтов имен
+### Избегайте конфликтов имен { #avoid-name-collisions }
Вместо того чтобы импортировать только переменную `router`, мы импортируем непосредственно суб-модуль `items`.
{!../../docs_src/bigger_applications/app/main.py!}
```
-### Подключение маршрутизаторов (`APIRouter`) для `users` и для `items`
+### Подключение маршрутизаторов (`APIRouter`) для `users` и для `items` { #include-the-apirouters-for-users-and-items }
Давайте подключим маршрутизаторы (`router`) из суб-модулей `users` и `items`:
///
-### Подключение `APIRouter` с пользовательскими префиксом (`prefix`), тегами (`tags`), ответами (`responses`), и зависимостями (`dependencies`)
+### Подключение `APIRouter` с пользовательскими префиксом (`prefix`), тегами (`tags`), ответами (`responses`), и зависимостями (`dependencies`) { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
Теперь давайте представим, что ваша организация передала вам файл `app/internal/admin.py`.
Например, другие проекты, могут использовать тот же самый `APIRouter` с другими методами аутентификации.
-### Подключение отдельного *эндпоинта*
+### Подключение отдельного *эндпоинта* { #include-a-path-operation }
Мы также можем добавить *эндпоинт* непосредственно в основное приложение `FastAPI`.
///
-## Проверка автоматической документации API
+## Проверка автоматической документации API { #check-the-automatic-api-docs }
Теперь запустите приложение:
<img src="/img/tutorial/bigger-applications/image01.png">
-## Подключение существующего маршрута через новый префикс (`prefix`)
+## Подключение существующего маршрута через новый префикс (`prefix`) { #include-the-same-router-multiple-times-with-different-prefix }
Вы можете использовать `.include_router()` несколько раз с одним и тем же маршрутом, применив различные префиксы.
Это продвинутый способ, который вам может и не пригодится. Мы приводим его на случай, если вдруг вам это понадобится.
-## Включение одного маршрутизатора (`APIRouter`) в другой
+## Включение одного маршрутизатора (`APIRouter`) в другой { #include-an-apirouter-in-another }
Точно так же, как вы включаете `APIRouter` в приложение `FastAPI`, вы можете включить `APIRouter` в другой `APIRouter`:
-# Body - Поля
+# Body - Поля { #body-fields }
Таким же способом, как вы объявляете дополнительную валидацию и метаданные в параметрах *функции обработки пути* с помощью функций `Query`, `Path` и `Body`, вы можете объявлять валидацию и метаданные внутри Pydantic моделей, используя функцию `Field` из Pydantic.
-## Импорт `Field`
+## Импорт `Field` { #import-field }
Сначала вы должны импортировать его:
-{* ../../docs_src/body_fields/tutorial001_py310.py hl[2] *}
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
/// warning | Внимание
///
-## Объявление атрибутов модели
+## Объявление атрибутов модели { #declare-model-attributes }
Вы можете использовать функцию `Field` с атрибутами модели:
-{* ../../docs_src/body_fields/tutorial001_py310.py hl[9:12] *}
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
Функция `Field` работает так же, как `Query`, `Path` и `Body`, у неё такие же параметры и т.д.
На самом деле, `Query`, `Path` и другие функции, которые вы увидите в дальнейшем, создают объекты подклассов общего класса `Param`, который сам по себе является подклассом `FieldInfo` из Pydantic.
-И `Field` (из Pydantic), и `Body`, оба возвращают объекты подкласса `FieldInfo`.
+И `Field` (из Pydantic) также возвращает экземпляр `FieldInfo`.
-У класса `Body` есть и другие подклассы, с которыми вы ознакомитесь позже.
+`Body` также напрямую возвращает объекты подкласса `FieldInfo`. И есть и другие, с которыми вы познакомитесь позже, которые являются подклассами класса `Body`.
Помните, что когда вы импортируете `Query`, `Path` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.
///
-## Добавление дополнительной информации
+## Добавление дополнительной информации { #add-extra-information }
Вы можете объявлять дополнительную информацию в `Field`, `Query`, `Body` и т.п. Она будет включена в сгенерированную JSON схему.
-Вы узнаете больше о добавлении дополнительной информации позже в документации, когда будете изучать, как задавать примеры принимаемых данных.
-
+Вы узнаете больше о добавлении дополнительной информации позже в документации, когда будете изучать, как задавать примеры.
/// warning | Внимание
///
-## Резюме
+## Резюме { #recap }
Вы можете использовать функцию `Field` из Pydantic, чтобы задавать дополнительную валидацию и метаданные для атрибутов модели.
-# Body - Множество параметров
+# Body - Множество параметров { #body-multiple-parameters }
-ТепеÑ\80Ñ\8c, когда мÑ\8b Ñ\83видели, как иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Path` и `Query` паÑ\80амеÑ\82Ñ\80Ñ\8b, давайÑ\82е Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им более пÑ\80одвинÑ\83Ñ\82Ñ\8bе пÑ\80имеÑ\80Ñ\8b обÑ\8cявления тела запроса.
+ТепеÑ\80Ñ\8c, когда мÑ\8b Ñ\83видели, как иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Path` и `Query` паÑ\80амеÑ\82Ñ\80Ñ\8b, давайÑ\82е Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им более пÑ\80одвинÑ\83Ñ\82Ñ\8bе пÑ\80имеÑ\80Ñ\8b обÑ\8aявления тела запроса.
-## Ð\9eбÑ\8cединение `Path`, `Query` и паÑ\80амеÑ\82Ñ\80ов Ñ\82ела запÑ\80оÑ\81а
+## Ð\9eбÑ\8aединение `Path`, `Query` и паÑ\80амеÑ\82Ñ\80ов Ñ\82ела запÑ\80оÑ\81а { #mix-path-query-and-body-parameters }
Во-первых, конечно, вы можете объединять параметры `Path`, `Query` и объявления тела запроса в своих функциях обработки, **FastAPI** автоматически определит, что с ними нужно делать.
///
-## Несколько параметров тела запроса
+## Несколько параметров тела запроса { #multiple-body-parameters }
-В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON-тело с параметрами, соответствующими атрибутам `Item`, например:
+В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON, с параметрами, соответствующими атрибутам `Item`, например:
```JSON
{
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
-В этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются моделями Pydantic).
+В этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются Pydantic-моделями).
Таким образом, имена параметров будут использоваться в качестве ключей (имён полей) в теле запроса, и будет ожидаться запрос следующего формата:
/// note | Внимание
-Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о Ñ\85оÑ\82Ñ\8f паÑ\80амеÑ\82Ñ\80 `item` бÑ\8bл обÑ\8aÑ\8fвлен Ñ\82аким же Ñ\81поÑ\81обом, как и Ñ\80анÑ\8cÑ\88е, Ñ\82епеÑ\80Ñ\8c пÑ\80едпологается, что он находится внутри тела с ключом `item`.
+Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о Ñ\85оÑ\82Ñ\8f паÑ\80амеÑ\82Ñ\80 `item` бÑ\8bл обÑ\8aÑ\8fвлен Ñ\82аким же Ñ\81поÑ\81обом, как и Ñ\80анÑ\8cÑ\88е, Ñ\82епеÑ\80Ñ\8c пÑ\80едполагается, что он находится внутри тела с ключом `item`.
///
-**FastAPI** Ñ\81делаеÑ\82 авÑ\82омаÑ\82иÑ\87еÑ\81кие преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое происходит с пользователем `user`.
+**FastAPI** Ñ\81делаеÑ\82 авÑ\82омаÑ\82иÑ\87еÑ\81кое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое происходит с пользователем `user`.
Произойдёт проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах.
-## Отдельные значения в теле запроса
+## Отдельные значения в теле запроса { #singular-values-in-body }
Точно так же, как `Query` и `Path` используются для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет аналогичный инструмент - `Body`.
Например, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`.
-Если вы объявите его без указания, какой именно объект (Path, Query, Body и .т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать, что это query-параметр.
+Если вы объявите его без указания, какой именно объект (Path, Query, Body и т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать, что это query-параметр.
Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`:
И всё будет работать так же - преобразование типов данных, валидация, документирование и т.д.
-## Множество body и query параметров
+## Множество body и query параметров { #multiple-body-params-and-query }
Конечно, вы также можете объявлять query-параметры в любое время, дополнительно к любым body-параметрам.
Например:
-{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[27] *}
+{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
/// info | Информация
///
-## Ð\94обавление одного body-паÑ\80амеÑ\82Ñ\80а
+## Ð\92ложиÑ\82Ñ\8c один body-паÑ\80амеÑ\82Ñ\80 { #embed-a-single-body-parameter }
-Предположим, у вас есть только один body-параметр `item` из Pydantic модели `Item`.
+Предположим, у вас есть только один body-параметр `item` из Pydantic-модели `Item`.
По умолчанию, **FastAPI** ожидает получить тело запроса напрямую.
}
```
-## Резюме
+## Резюме { #recap }
-Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря даже на то, что запрос может содержать только одно тело.
+Вы можете добавлять несколько body-параметров вашей *функции-обработчика пути*, несмотря даже на то, что запрос может содержать только одно тело.
Но **FastAPI** справится с этим, предоставит правильные данные в вашей функции, а также сделает валидацию и документацию правильной схемы *операции пути*.
-# Body - Вложенные модели
+# Body - Вложенные модели { #body-nested-models }
-С помощью **FastAPI**, вы можете определять, валидировать, документировать и использовать модели произвольной вложенности (благодаря библиотеке Pydantic).
+С помощью **FastAPI** вы можете определять, валидировать, документировать и использовать модели произвольной глубины вложенности (благодаря Pydantic).
-## Ð\9eпÑ\80еделение полей Ñ\81одеÑ\80жаÑ\89иÑ\85 Ñ\81пиÑ\81ки
+## Ð\9fолÑ\8f-Ñ\81пиÑ\81ки { #list-fields }
-Вы можете определять атрибут как подтип. Например, тип `list` в Python:
+Вы можете определить атрибут как подтип. Например, Python-тип `list`:
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
-Это приведёт к тому, что обьект `tags` преобразуется в список, несмотря на то что тип его элементов не объявлен.
+Это приведёт к тому, что `tags` будет списком, несмотря на то, что тип его элементов не объявлен.
-## Ð\9eпÑ\80еделение полей Ñ\81одеÑ\80жаÑ\89иÑ\85 Ñ\81пиÑ\81ок Ñ\81 опÑ\80еделением Ñ\82ипов его Ñ\8dлеменÑ\82ов
+## Ð\9fолÑ\8f-Ñ\81пиÑ\81ки Ñ\81 паÑ\80амеÑ\82Ñ\80ом Ñ\82ипа { #list-fields-with-type-parameter }
-Ð\9eднако в Python еÑ\81Ñ\82Ñ\8c Ñ\81поÑ\81об обÑ\8aÑ\8fвлениÑ\8f Ñ\81пиÑ\81ков Ñ\81 Ñ\83казанием Ñ\82ипов длÑ\8f вложеннÑ\8bÑ\85 Ñ\8dлеменÑ\82ов:
+Ð\92 Python еÑ\81Ñ\82Ñ\8c Ñ\81пеÑ\86иалÑ\8cнÑ\8bй Ñ\81поÑ\81об обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c Ñ\81пиÑ\81ки Ñ\81 внÑ\83Ñ\82Ñ\80енними Ñ\82ипами, или «паÑ\80амеÑ\82Ñ\80ами Ñ\82ипа»:
-### Импортируйте `List` из модуля typing
+### Импортируйте `List` из модуля typing { #import-typings-list }
В Python 3.9 и выше вы можете использовать стандартный тип `list` для объявления аннотаций типов, как мы увидим ниже. 💡
-Но в версиях Python до 3.9 (начиная с 3.6) сначала вам необходимо импортировать `List` из стандартного модуля `typing` в Python:
+Но в версиях Python до 3.9 (начиная с 3.6) сначала вам необходимо импортировать `List` из стандартного модуля `typing`:
{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
-### Ð\9eбÑ\8aÑ\8fвление `list` Ñ\81 Ñ\83казанием Ñ\82ипов длÑ\8f вложеннÑ\8bÑ\85 Ñ\8dлеменÑ\82ов
+### Ð\9eбÑ\8aÑ\8fвиÑ\82е `list` Ñ\81 паÑ\80амеÑ\82Ñ\80ом Ñ\82ипа { #declare-a-list-with-a-type-parameter }
-Ð\9eбÑ\8aÑ\8fвление Ñ\82ипов длÑ\8f Ñ\8dлеменÑ\82ов (внÑ\83Ñ\82Ñ\80енниÑ\85 Ñ\82ипов) вложеннÑ\8bÑ\85 в Ñ\82акие Ñ\82ипÑ\8b как `list`, `dict`, `tuple`:
+Ð\94лÑ\8f обÑ\8aÑ\8fвлениÑ\8f Ñ\82ипов, Ñ\83 коÑ\82оÑ\80Ñ\8bÑ\85 еÑ\81Ñ\82Ñ\8c паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\82ипа (внÑ\83Ñ\82Ñ\80енние Ñ\82ипÑ\8b), Ñ\82акиÑ\85 как `list`, `dict`, `tuple`:
-* Если у вас Python версии ниже чем 3.9, импортируйте их аналог из модуля `typing`
-* Передайте внутренний(ие) тип(ы) как "параметры типа", используя квадратные скобки: `[` и `]`
+* Если у вас Python версии ниже 3.9, импортируйте их аналоги из модуля `typing`
+* Передайте внутренний(ие) тип(ы) как «параметры типа», используя квадратные скобки: `[` и `]`
-В Python версии 3.9 это будет выглядеть так:
+В Python 3.9 это будет:
```Python
my_list: list[str]
```
-В версиях Python до 3.9 это будет выглядеть так:
+В версиях Python до 3.9 это будет:
```Python
from typing import List
Используйте этот же стандартный синтаксис для атрибутов модели с внутренними типами.
-Таким образом, в нашем примере мы можем явно указать тип данных для поля `tags` как "список строк":
+Таким образом, в нашем примере мы можем явно указать тип данных для поля `tags` как «список строк»:
{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
-## Типы множеств
+## Типы множеств { #set-types }
-Но затем мы подумали и поняли, что теги не должны повторяться и, вероятно, они должны быть уникальными строками.
+Но затем мы подумали и поняли, что теги не должны повторяться, вероятно, это должны быть уникальные строки.
-И в Python есть специальный тип данных для множеств уникальных элементов - `set`.
+И в Python есть специальный тип данных для множеств уникальных элементов — `set`.
-Тогда мÑ\8b можем обÑ\8cявить поле `tags` как множество строк:
+Тогда мÑ\8b можем обÑ\8aявить поле `tags` как множество строк:
{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
И они также будут соответствующим образом аннотированы / задокументированы.
-## Ð\92ложеннÑ\8bе Ð\9cодели
+## Ð\92ложеннÑ\8bе модели { #nested-models }
У каждого атрибута Pydantic-модели есть тип.
-Но этот тип может сам быть другой моделью Pydantic.
+Но этот тип сам может быть другой моделью Pydantic.
-Таким образом вы можете объявлять глубоко вложенные JSON "объекты" с определёнными именами атрибутов, типами и валидацией.
+Таким образом, вы можете объявлять глубоко вложенные JSON «объекты» с определёнными именами атрибутов, типами и валидацией.
Всё это может быть произвольно вложенным.
-### Определение подмодели
+### Определение подмодели { #define-a-submodel }
Например, мы можем определить модель `Image`:
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
-### Ð\98Ñ\81полÑ\8cзование вложенной модели в каÑ\87еÑ\81Ñ\82ве Ñ\82ипа
+### Ð\98Ñ\81полÑ\8cзование подмодели как Ñ\82ипа { #use-the-submodel-as-a-type }
Также мы можем использовать эту модель как тип атрибута:
Ещё раз: сделав такое объявление, с помощью **FastAPI** вы получите:
-* Ð\9fоддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80ов IDE (авÑ\82одополнение и Ñ\82.д), даже для вложенных моделей
+* Ð\9fоддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а кода (авÑ\82озавеÑ\80Ñ\88ение и Ñ\82. д.), даже для вложенных моделей
* Преобразование данных
* Валидацию данных
* Автоматическую документацию
-## Особые типы и валидация
+## Особые типы и валидация { #special-types-and-validation }
-Помимо обычных простых типов, таких как `str`, `int`, `float`, и т.д. Вы можете использовать более сложные базовые типы, которые наследуются от типа `str`.
+Помимо обычных простых типов, таких как `str`, `int`, `float` и т.д., вы можете использовать более сложные простые типы, которые наследуются от `str`.
-Чтобы увидеть все варианты, которые у вас есть, ознакомьтесь с документацией <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">по необычным типам Pydantic</a>. Вы увидите некоторые примеры в следующей главе.
+Чтобы увидеть все варианты, которые у вас есть, ознакомьтесь с <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">обзором типов Pydantic</a>. Вы увидите некоторые примеры в следующей главе.
-Например, так как в модели `Image` у нас есть поле `url`, то мы можем объявить его как тип `HttpUrl` из модуля Pydantic вместо типа `str`:
+Например, так как в модели `Image` у нас есть поле `url`, то мы можем объявить его как тип `HttpUrl` из Pydantic вместо типа `str`:
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
-Строка будет проверена на соответствие допустимому URL-адресу и задокументирована в JSON схему / OpenAPI.
+Строка будет проверена на соответствие допустимому URL-адресу и задокументирована в JSON Schema / OpenAPI как таковая.
-## Атрибуты, содержащие списки подмоделей
+## Атрибуты, содержащие списки подмоделей { #attributes-with-lists-of-submodels }
-Вы также можете использовать модели Pydantic в качестве типов вложенных в `list`, `set` и т.д:
+Вы также можете использовать модели Pydantic в качестве подтипов для `list`, `set` и т.д.:
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
-Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д) JSON-содержимое в следующем формате:
+Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д.) JSON-содержимое в следующем формате:
```JSON hl_lines="11"
{
///
-## Глубоко вложенные модели
+## Глубоко вложенные модели { #deeply-nested-models }
Вы можете определять модели с произвольным уровнем вложенности:
///
-## Тела с чистыми списками элементов
+## Тела с чистыми списками элементов { #bodies-of-pure-lists }
-Если верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python - `list`), вы можете объявить тип в параметре функции, так же, как в моделях Pydantic:
+Если верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic:
```Python
images: List[Image]
```
-в Python 3.9 и выше:
+или в Python 3.9 и вÑ\8bÑ\88е:
```Python
images: list[Image]
{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
-## УнивеÑ\80Ñ\81алÑ\8cнаÑ\8f поддеÑ\80жка Ñ\80едакÑ\82оÑ\80а
+## Ð\9fоддеÑ\80жка Ñ\80едакÑ\82оÑ\80а кода везде { #editor-support-everywhere }
-И вы получаете поддержку редактора везде.
+Ð\98 вÑ\8b полÑ\83Ñ\87аеÑ\82е поддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а кода везде.
Даже для элементов внутри списков:
<img src="/img/tutorial/body-nested-models/image01.png">
-Вы не могли бы получить такую поддержку редактора, если бы работали напрямую с `dict`, а не с моделями Pydantic.
+Вы не могли бы получить такую поддержку редактора кода, если бы работали напрямую с `dict`, а не с моделями Pydantic.
Но вы также не должны беспокоиться об этом, входящие словари автоматически конвертируются, а ваш вывод также автоматически преобразуется в формат JSON.
-## Тела запросов с произвольными словарями (`dict` )
+## Тела запросов с произвольными словарями (`dict`) { #bodies-of-arbitrary-dicts }
-Вы также можете объявить тело запроса как `dict` с ключами определенного типа и значениями другого типа данных.
+Вы также можете объявить тело запроса как `dict` с ключами определённого типа и значениями другого типа.
Без необходимости знать заранее, какие значения являются допустимыми для имён полей/атрибутов (как это было бы в случае с моделями Pydantic).
-Это было бы полезно, если вы хотите получить ключи, которые вы еще не знаете.
+Это было бы полезно, если вы хотите получить ключи, которые вы ещё не знаете.
---
-Другой полезный случай - когда вы хотите чтобы ключи были другого типа данных, например, `int`.
+Другой полезный случай — когда вы хотите, чтобы ключи были другого типа данных, например, `int`.
Именно это мы сейчас и увидим здесь.
-В этом случае вы принимаете `dict`, пока у него есть ключи типа `int` со значениями типа `float`:
+В этом случае вы принимаете любой `dict`, пока у него есть ключи типа `int` со значениями типа `float`:
{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
Но Pydantic обеспечивает автоматическое преобразование данных.
-ÐÑ\82о знаÑ\87иÑ\82, Ñ\87Ñ\82о даже еÑ\81ли полÑ\8cзоваÑ\82ели ваÑ\88его API могÑ\83Ñ\82 оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c Ñ\82олÑ\8cко Ñ\81Ñ\82Ñ\80оки в каÑ\87еÑ\81Ñ\82ве клÑ\8eÑ\87ей, пÑ\80и Ñ\83Ñ\81ловии, Ñ\87Ñ\82о Ñ\8dÑ\82и Ñ\81Ñ\82Ñ\80оки Ñ\81одеÑ\80жаÑ\82 Ñ\86елÑ\8bе Ñ\87иÑ\81ла, Pydantic авÑ\82омаÑ\82иÑ\87еÑ\81кий преобразует и валидирует эти данные.
+ÐÑ\82о знаÑ\87иÑ\82, Ñ\87Ñ\82о даже еÑ\81ли клиенÑ\82Ñ\8b ваÑ\88его API могÑ\83Ñ\82 оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c Ñ\82олÑ\8cко Ñ\81Ñ\82Ñ\80оки в каÑ\87еÑ\81Ñ\82ве клÑ\8eÑ\87ей, пÑ\80и Ñ\83Ñ\81ловии, Ñ\87Ñ\82о Ñ\8dÑ\82и Ñ\81Ñ\82Ñ\80оки Ñ\81одеÑ\80жаÑ\82 Ñ\86елÑ\8bе Ñ\87иÑ\81ла, Pydantic авÑ\82омаÑ\82иÑ\87еÑ\81ки преобразует и валидирует эти данные.
-А `dict`, с именем `weights`, который вы получите в качестве ответа Pydantic, действительно будет иметь ключи типа `int` и значения типа `float`.
+А `dict`, который вы получите как `weights`, действительно будет иметь ключи типа `int` и значения типа `float`.
///
-## Резюме
+## Резюме { #recap }
С помощью **FastAPI** вы получаете максимальную гибкость, предоставляемую моделями Pydantic, сохраняя при этом простоту, краткость и элегантность вашего кода.
И дополнительно вы получаете:
-* Поддержку редактора (автодополнение доступно везде!)
+* Поддержку редактора кода (автозавершение доступно везде!)
* Преобразование данных (также известно как парсинг / сериализация)
* Валидацию данных
* Документацию схемы данных
-# Body - Обновления
+# Body - Обновления { #body-updates }
-## Ð\9fолное обновление Ñ\81 помоÑ\89Ñ\8cÑ\8e `PUT`
+## Ð\9eбновление Ñ\81 заменой пÑ\80и помоÑ\89и `PUT` { #update-replacing-with-put }
Для полного обновления элемента можно воспользоваться операцией <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
-Вы можете использовать функцию `jsonable_encoder` для преобразования входных данных в JSON, так как нередки случаи, когда работать можно только с простыми типами данных (например, для хранения в NoSQL-базе данных).
+Вы можете использовать `jsonable_encoder`, чтобы преобразовать входные данные в данные, которые можно сохранить как JSON (например, в NoSQL-базе данных). Например, преобразование `datetime` в `str`.
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
`PUT` используется для получения данных, которые должны полностью заменить существующие данные.
-### Предупреждение о замене
+### Предупреждение о замене { #warning-about-replacing }
Это означает, что если вы хотите обновить элемент `bar`, используя `PUT` с телом, содержащим:
И данные будут сохранены с этим "новым" `tax`, равным `10,5`.
-## Частичное обновление с помощью `PATCH`
+## Частичное обновление с помощью `PATCH` { #partial-updates-with-patch }
Также можно использовать <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> операцию для *частичного* обновления данных.
///
-### Использование параметра `exclude_unset` в Pydantic
+### Использование параметра `exclude_unset` в Pydantic { #using-pydantics-exclude-unset-parameter }
-Если необходимо выполнить частичное обновление, то очень полезно использовать параметр `exclude_unset` в методе `.dict()` модели Pydantic.
+Если необходимо выполнить частичное обновление, то очень полезно использовать параметр `exclude_unset` в методе `.model_dump()` модели Pydantic.
-Например, `item.dict(exclude_unset=True)`.
+Например, `item.model_dump(exclude_unset=True)`.
+
+/// info | Информация
+
+В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_dump()`.
+
+Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_dump()`.
+
+///
В результате будет сгенерирован словарь, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию. Затем вы можете использовать это для создания словаря только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
-### Использование параметра `update` в Pydantic
+### Использование параметра `update` в Pydantic { #using-pydantics-update-parameter }
-Теперь можно создать копию существующей модели, используя `.copy()`, и передать параметр `update` с `dict`, содержащим данные для обновления.
+Теперь можно создать копию существующей модели, используя `.model_copy()`, и передать параметр `update` с `dict`, содержащим данные для обновления.
+
+/// info | Информация
+
+В Pydantic v1 метод назывался `.copy()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_copy()`.
+
+Примеры здесь используют `.copy()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_copy()`.
+
+///
-Например, `stored_item_model.copy(update=update_data)`:
+Например, `stored_item_model.model_copy(update=update_data)`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
-### Кратко о частичном обновлении
+### Кратко о частичном обновлении { #partial-updates-recap }
В целом, для применения частичных обновлений необходимо:
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять значения, уже сохраненные в модели по умолчанию.
* Создать копию хранимой модели, обновив ее атрибуты полученными частичными обновлениями (с помощью параметра `update`).
* Преобразовать скопированную модель в то, что может быть сохранено в вашей БД (например, с помощью `jsonable_encoder`).
- * Это сравнимо с повторным использованием метода модели `.dict()`, но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например, `datetime` в `str`.
+ * Это сравнимо с повторным использованием метода модели `.model_dump()`, но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например, `datetime` в `str`.
* Сохранить данные в своей БД.
* Вернуть обновленную модель.
-# Тело запроса
+# Тело запроса { #request-body }
-Ð\9aогда вам необÑ\85одимо оÑ\82пÑ\80авиÑ\82Ñ\8c даннÑ\8bе из клиенÑ\82а (допÑ\83Ñ\81Ñ\82им, браузера) в ваш API, вы отправляете их как **тело запроса**.
+Ð\9aогда вам необÑ\85одимо оÑ\82пÑ\80авиÑ\82Ñ\8c даннÑ\8bе из клиенÑ\82а (напÑ\80имеÑ\80, браузера) в ваш API, вы отправляете их как **тело запроса**.
-Тело **запроса** --- это данные, отправляемые клиентом в ваш API. Тело **ответа** --- это данные, которые ваш API отправляет клиенту.
+Тело **запроса** — это данные, отправляемые клиентом в ваш API. Тело **ответа** — это данные, которые ваш API отправляет клиенту.
-Ð\92аÑ\88 API поÑ\87Ñ\82и вÑ\81егда оÑ\82пÑ\80авлÑ\8fеÑ\82 Ñ\82ело **оÑ\82веÑ\82а**. Ð\9dо клиенÑ\82ам не обÑ\8fзаÑ\82елÑ\8cно вÑ\81егда оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c Ñ\82ело **запÑ\80оÑ\81а**.
+Ð\92аÑ\88 API поÑ\87Ñ\82и вÑ\81егда должен оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c Ñ\82ело **оÑ\82веÑ\82а**. Ð\9dо клиенÑ\82ам не обÑ\8fзаÑ\82елÑ\8cно вÑ\81егда оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c **Ñ\82ело запÑ\80оÑ\81а**: иногда они запÑ\80аÑ\88иваÑ\8eÑ\82 Ñ\82олÑ\8cко пÑ\83Ñ\82Ñ\8c, возможно Ñ\81 некоÑ\82оÑ\80Ñ\8bми паÑ\80амеÑ\82Ñ\80ами запÑ\80оÑ\81а, но без Ñ\82ела.
-ЧÑ\82обÑ\8b обÑ\8aÑ\8fвиÑ\82Ñ\8c Ñ\82ело **запÑ\80оÑ\81а**, необÑ\85одимо иÑ\81полÑ\8cзоваÑ\82Ñ\8c модели <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, со всей их мощью и преимуществами.
+ЧÑ\82обÑ\8b обÑ\8aÑ\8fвиÑ\82Ñ\8c Ñ\82ело **запÑ\80оÑ\81а**, иÑ\81полÑ\8cзÑ\83йÑ\82е модели <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, со всей их мощью и преимуществами.
/// info | Информация
-ЧÑ\82обÑ\8b оÑ\82пÑ\80авиÑ\82Ñ\8c даннÑ\8bе, необÑ\85одимо иÑ\81полÑ\8cзоваÑ\82Ñ\8c один из меÑ\82одов: `POST` (обÑ\8bÑ\87но), `PUT`, `DELETE` или `PATCH`.
+ЧÑ\82обÑ\8b оÑ\82пÑ\80авиÑ\82Ñ\8c даннÑ\8bе, иÑ\81полÑ\8cзÑ\83йÑ\82е один из меÑ\82одов: `POST` (Ñ\87аÑ\89е вÑ\81его), `PUT`, `DELETE` или `PATCH`.
-Отправка тела с запросом `GET` имеет неопределенное поведение в спецификациях, тем не менее, оно поддерживается FastAPI только для очень сложных/экстремальных случаев использования.
+Отправка тела с запросом `GET` имеет неопределённое поведение в спецификациях, тем не менее это поддерживается FastAPI, но только для очень сложных/крайних случаев использования.
-Поскольку это не рекомендуется, интерактивная документация со Swagger UI не будет отображать информацию для тела при использовании метода GET, а промежуточные прокси-серверы могут не поддерживать такой вариант запроса.
+Поскольку это не рекомендуется, интерактивная документация со Swagger UI не будет отображать информацию для тела при использовании `GET`, а промежуточные прокси-серверы могут не поддерживать такой вариант запроса.
///
-## Импортирование `BaseModel` из Pydantic
+## Импортируйте `BaseModel` из Pydantic { #import-pydantics-basemodel }
-Ð\9fеÑ\80вое, Ñ\87Ñ\82о вам необÑ\85одимо Ñ\81делаÑ\82Ñ\8c, Ñ\8dÑ\82о импортировать `BaseModel` из пакета `pydantic`:
+Ð\9fеÑ\80вое, Ñ\87Ñ\82о нÑ\83жно Ñ\81делаÑ\82Ñ\8c, â\80\94 импортировать `BaseModel` из пакета `pydantic`:
-{* ../../docs_src/body/tutorial001.py hl[4] *}
+{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
-## Создание ваÑ\88ей Ñ\81обÑ\81Ñ\82венной модели
+## СоздайÑ\82е моделÑ\8c даннÑ\8bÑ\85 { #create-your-data-model }
-Ð\9fоÑ\81ле Ñ\8dÑ\82ого вÑ\8b опиÑ\81Ñ\8bваеÑ\82е ваÑ\88Ñ\83 моделÑ\8c даннÑ\8bÑ\85 как клаÑ\81Ñ\81, наÑ\81ледÑ\83Ñ\8eÑ\89ий от `BaseModel`.
+Ð\97аÑ\82ем опиÑ\88иÑ\82е Ñ\81воÑ\8e моделÑ\8c даннÑ\8bÑ\85 как клаÑ\81Ñ\81, наÑ\81ледÑ\83Ñ\8eÑ\89ийÑ\81Ñ\8f от `BaseModel`.
-Используйте аннотации типов Python для всех атрибутов:
+Используйте стандартные типы Python для всех атрибутов:
-{* ../../docs_src/body/tutorial001.py hl[7:11] *}
+{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
-Также как и при описании параметров запроса, когда атрибут модели имеет значение по умолчанию, он является необязательным. Иначе он обязателен. Используйте `None`, чтобы сделать его необязательным без использования конкретных значений по умолчанию.
+Так же, как при объявлении параметров запроса: когда атрибут модели имеет значение по умолчанию, он не обязателен. Иначе он обязателен. Используйте `None`, чтобы сделать его просто необязательным.
-Например, модель выше описывает вот такой JSON "объект" (или словарь Python):
+Например, модель выше описывает такой JSON "объект" (или Python `dict`):
```JSON
{
}
```
-...поскольку `description` и `tax` являются необязательными (с `None` в качестве значения по умолчанию), вот такой JSON "объект" также подходит:
+...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "объект" тоже будет корректным:
```JSON
{
}
```
-## Ð\9eбÑ\8aÑ\8fвление как паÑ\80амеÑ\82Ñ\80а Ñ\84Ñ\83нкÑ\86ии
+## Ð\9eбÑ\8aÑ\8fвиÑ\82е еÑ\91 как паÑ\80амеÑ\82Ñ\80 { #declare-it-as-a-parameter }
-ЧÑ\82обÑ\8b добавиÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 к ваÑ\88емÑ\83 *обÑ\80абоÑ\82Ñ\87икÑ\83*, обÑ\8aÑ\8fвиÑ\82е его Ñ\82акже, как вÑ\8b обÑ\8aÑ\8fвлÑ\8fли паÑ\80амеÑ\82Ñ\80Ñ\8b пÑ\83Ñ\82и или параметры запроса:
+ЧÑ\82обÑ\8b добавиÑ\82Ñ\8c еÑ\91 в ваÑ\88Ñ\83 *опеÑ\80аÑ\86иÑ\8e пÑ\83Ñ\82и*, обÑ\8aÑ\8fвиÑ\82е еÑ\91 Ñ\82ак же, как вÑ\8b обÑ\8aÑ\8fвлÑ\8fли паÑ\80амеÑ\82Ñ\80Ñ\8b пÑ\83Ñ\82и и параметры запроса:
-{* ../../docs_src/body/tutorial001.py hl[18] *}
+{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
-...и Ñ\83кажиÑ\82е Ñ\81озданнÑ\83Ñ\8e моделÑ\8c в каÑ\87еÑ\81Ñ\82ве Ñ\82ипа паÑ\80амеÑ\82Ñ\80а, `Item`.
+...и Ñ\83кажиÑ\82е Ñ\82ип паÑ\80амеÑ\82Ñ\80а как Ñ\81озданнÑ\83Ñ\8e вами моделÑ\8c, `Item`.
-## Результаты
+## Результаты { #results }
-Всего лишь с помощью аннотации типов Python, **FastAPI**:
+Всего лишь с этой аннотацией типов Python **FastAPI**:
-* Читает тело запроса как JSON.
-* Ð\9fÑ\80иводиÑ\82 к Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89им Ñ\82ипам (еÑ\81ли еÑ\81Ñ\82Ñ\8c необÑ\85одимоÑ\81Ñ\82Ñ\8c).
-* Проверяет корректность данных.
- * Ð\95Ñ\81ли даннÑ\8bе некоÑ\80Ñ\80екÑ\82нÑ\8b, бÑ\83деÑ\82 возÑ\80аÑ\89ена Ñ\87иÑ\82аемаÑ\8f и понÑ\8fÑ\82наÑ\8f оÑ\88ибка, показÑ\8bваÑ\8eÑ\89аÑ\8f Ñ\87Ñ\82о именно и в каком меÑ\81Ñ\82е некоÑ\80Ñ\80екÑ\82но в даннÑ\8bÑ\85.
-* СкладÑ\8bвает полученные данные в параметр `item`.
- * Ð\9fоÑ\81колÑ\8cкÑ\83 внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии вÑ\8b обÑ\8aÑ\8fвили его Ñ\81 Ñ\82ипом `Item`, Ñ\82о Ñ\82епеÑ\80Ñ\8c Ñ\83 ваÑ\81 еÑ\81Ñ\82Ñ\8c поддеÑ\80жка Ñ\81о Ñ\81Ñ\82оÑ\80онÑ\8b Ñ\80едакÑ\82оÑ\80а (авÑ\82одополнение и Ñ\82.п.) для всех атрибутов и их типов.
-* Ð\93енеÑ\80иÑ\80Ñ\83еÑ\82 деклаÑ\80аÑ\82ивное опиÑ\81ание модели в виде <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a>, Ñ\82ак Ñ\87Ñ\82о вÑ\8b можеÑ\82е его иÑ\81полÑ\8cзоваÑ\82Ñ\8c где Ñ\83годно, еÑ\81ли Ñ\8dÑ\82о имееÑ\82 знаÑ\87ение для вашего проекта.
-* Эти схемы являются частью сгенерированной схемы OpenAPI и используются для автоматического документирования <abbr title="Пользовательских интерфейсов (User Interfaces)">UI</abbr>.
+* СÑ\87итает тело запроса как JSON.
+* Ð\9fÑ\80иведÑ\91Ñ\82 даннÑ\8bе к Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89им Ñ\82ипам (еÑ\81ли поÑ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f).
+* Проведёт валидацию данных.
+ * Ð\95Ñ\81ли даннÑ\8bе некоÑ\80Ñ\80екÑ\82нÑ\8b, веÑ\80нÑ\91Ñ\82 понÑ\8fÑ\82нÑ\83Ñ\8e и наглÑ\8fднÑ\83Ñ\8e оÑ\88ибкÑ\83, Ñ\83казÑ\8bваÑ\8eÑ\89Ñ\83Ñ\8e, где именно и Ñ\87Ñ\82о бÑ\8bло некоÑ\80Ñ\80екÑ\82но.
+* Ð\9fеÑ\80едаÑ\81т полученные данные в параметр `item`.
+ * Ð\9fоÑ\81колÑ\8cкÑ\83 внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии вÑ\8b обÑ\8aÑ\8fвили его Ñ\81 Ñ\82ипом `Item`, Ñ\83 ваÑ\81 бÑ\83деÑ\82 поддеÑ\80жка Ñ\81о Ñ\81Ñ\82оÑ\80онÑ\8b Ñ\80едакÑ\82оÑ\80а кода (авÑ\82озавеÑ\80Ñ\88ение и Ñ\82. п.) для всех атрибутов и их типов.
+* СгенеÑ\80иÑ\80Ñ\83еÑ\82 опÑ\80еделениÑ\8f <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> длÑ\8f ваÑ\88ей модели; вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c иÑ\85 и в дÑ\80Ñ\83гиÑ\85 меÑ\81Ñ\82аÑ\85, еÑ\81ли Ñ\8dÑ\82о имееÑ\82 Ñ\81мÑ\8bÑ\81л для вашего проекта.
+* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces – Пользовательские интерфейсы">UIs</abbr>.
-## Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81кое докÑ\83менÑ\82иÑ\80ование
+## Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81каÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f { #automatic-docs }
-Схема JSON ваших моделей будет частью сгенерированной схемы OpenAPI и будет отображена в интерактивной документации API:
+JSON Schema ваших моделей будет частью сгенерированной схемы OpenAPI и будет отображаться в интерактивной документации API:
<img src="/img/tutorial/body/image01.png">
-Также она бÑ\83деÑ\82 Ñ\83казана в докÑ\83менÑ\82аÑ\86ии по API внÑ\83Ñ\82Ñ\80и каждой *опеÑ\80аÑ\86ии пÑ\83Ñ\82и*, в коÑ\82оÑ\80ой иÑ\81полÑ\8cзÑ\83Ñ\8eтся:
+Ð\90 Ñ\82акже они бÑ\83дÑ\83Ñ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f в докÑ\83менÑ\82аÑ\86ии API внÑ\83Ñ\82Ñ\80и каждой *опеÑ\80аÑ\86ии пÑ\83Ñ\82и*, где Ñ\8dÑ\82о Ñ\82Ñ\80ебÑ\83ется:
<img src="/img/tutorial/body/image02.png">
-## Поддержка редактора
+## Поддержка редактора кода { #editor-support }
-Ð\92 ваÑ\88ем Ñ\80едакÑ\82оÑ\80е внÑ\83Ñ\82Ñ\80и ваÑ\88ей Ñ\84Ñ\83нкÑ\86ии Ñ\83 ваÑ\81 бÑ\83дÑ\83Ñ\82 подÑ\81казки по Ñ\82ипам и авÑ\82одополнение (Ñ\8dÑ\82о не бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c, еÑ\81ли вÑ\8b полÑ\83Ñ\87аеÑ\82е Ñ\81ловаÑ\80Ñ\8c вместо модели Pydantic):
+Ð\92 ваÑ\88ем Ñ\80едакÑ\82оÑ\80е кода внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии вÑ\8b полÑ\83Ñ\87иÑ\82е подÑ\81казки по Ñ\82ипам и авÑ\82озавеÑ\80Ñ\88ение повÑ\81Ñ\8eдÑ\83 (Ñ\8dÑ\82ого бÑ\8b не бÑ\8bло, еÑ\81ли бÑ\8b вÑ\8b полÑ\83Ñ\87али `dict` вместо модели Pydantic):
<img src="/img/tutorial/body/image03.png">
-Также вÑ\8b бÑ\83деÑ\82е полÑ\83Ñ\87аÑ\82Ñ\8c оÑ\88ибки в Ñ\81лÑ\83Ñ\87ае неÑ\81ооÑ\82веÑ\82Ñ\81Ñ\82виÑ\8f Ñ\82ипов:
+Также вÑ\8b полÑ\83Ñ\87иÑ\82е пÑ\80овеÑ\80кÑ\83 оÑ\88ибок пÑ\80и некоÑ\80Ñ\80екÑ\82нÑ\8bÑ\85 опеÑ\80аÑ\86иÑ\8fÑ\85 Ñ\81 Ñ\82ипами:
<img src="/img/tutorial/body/image04.png">
-Это не случайно, весь фреймворк построен вокруг такого дизайна.
+Это не случайность — весь фреймворк построен вокруг такого дизайна.
-Ð\98 Ñ\8dÑ\82о вÑ\81е Ñ\82Ñ\89аÑ\82елÑ\8cно пÑ\80оÑ\82еÑ\81Ñ\82иÑ\80овано еÑ\89е на Ñ\8dÑ\82апе Ñ\80азÑ\80абоÑ\82ки дизайна, до Ñ\80еализаÑ\86ии, Ñ\87Ñ\82обÑ\8b Ñ\8dÑ\82о Ñ\80абоÑ\82ало со всеми редакторами.
+Ð\98 Ñ\8dÑ\82о бÑ\8bло Ñ\82Ñ\89аÑ\82елÑ\8cно пÑ\80оÑ\82еÑ\81Ñ\82иÑ\80овано еÑ\89Ñ\91 на Ñ\8dÑ\82апе пÑ\80оекÑ\82иÑ\80ованиÑ\8f, до Ñ\80еализаÑ\86ии, Ñ\87Ñ\82обÑ\8b Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о вÑ\81Ñ\91 бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c со всеми редакторами.
-Ð\94лÑ\8f поддеÑ\80жки Ñ\8dÑ\82ого даже бÑ\8bли внеÑ\81енÑ\8b некоÑ\82оÑ\80Ñ\8bе изменениÑ\8f в Ñ\81ам Pydantic.
+Ð\92 Ñ\81ам Pydantic даже бÑ\8bли внеÑ\81енÑ\8b некоÑ\82оÑ\80Ñ\8bе изменениÑ\8f длÑ\8f поддеÑ\80жки Ñ\8dÑ\82ого.
-Ð\9dа вÑ\81еÑ\85 пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 Ñ\81кÑ\80инÑ\88оÑ\82аÑ\85 иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
+Ð\9fÑ\80едÑ\8bдÑ\83Ñ\89ие Ñ\81кÑ\80инÑ\88оÑ\82Ñ\8b Ñ\81деланÑ\8b в <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
-Но у вас будет такая же поддержка и с <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>, и вообще с любым редактором Python:
+Но вы получите такую же поддержку редактора кода в <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> и большинстве других редакторов Python:
<img src="/img/tutorial/body/image05.png">
-/// tip | Ð\9fодÑ\81казка
+/// tip | СовеÑ\82
-Если вы используете <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> в качестве редактора, то вам стоит попробовать плагин <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
+Если вы используете <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> в качестве редактора кода, вы можете использовать плагин <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
-Он улучшает поддержку редактором моделей Pydantic в части:
+Он улучшает поддержку моделей Pydantic в редакторе кода, включая:
-* авÑ\82одополнениÑ\8f,
-* проверки типов,
-* рефакторинга,
-* поиска,
-* инÑ\81пекÑ\82иÑ\80ованиÑ\8f.
+* авÑ\82озавеÑ\80Ñ\88ение
+* проверки типов
+* рефакторинг
+* поиск
+* инÑ\81пекÑ\86ии
///
-## Использование модели
+## Использование модели { #use-the-model }
Внутри функции вам доступны все атрибуты объекта модели напрямую:
-{* ../../docs_src/body/tutorial002.py hl[21] *}
+{* ../../docs_src/body/tutorial002_py310.py *}
-## Тело запроса + параметры пути
+/// info | Информация
+
+В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
-Вы можете одновременно объявлять параметры пути и тело запроса.
+Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, используйте `.model_dump()`.
+
+///
-**FastAPI** распознает, какие параметры функции соответствуют параметрам пути и должны быть **получены из пути**, а какие параметры функции, объявленные как модели Pydantic, должны быть **получены из тела запроса**.
+## Тело запроса + параметры пути { #request-body-path-parameters }
-{* ../../docs_src/body/tutorial003.py hl[17:18] *}
+Вы можете одновременно объявить параметры пути и тело запроса.
-## Тело запроса + параметры пути + параметры запроса
+**FastAPI** распознает, что параметры функции, соответствующие параметрам пути, должны быть **получены из пути**, а параметры функции, объявленные как модели Pydantic, должны быть **получены из тела запроса**.
-Вы также можете одновременно объявить параметры для **пути**, **запроса** и **тела запроса**.
+{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
-**FastAPI** распознает каждый из них и возьмет данные из правильного источника.
+## Тело запроса + параметры пути + параметры запроса { #request-body-path-query-parameters }
-{* ../../docs_src/body/tutorial004.py hl[18] *}
+Вы также можете одновременно объявить параметры **тела**, **пути** и **запроса**.
-Параметры функции распознаются следующим образом:
+**FastAPI** распознает каждый из них и возьмёт данные из правильного источника.
-* Если параметр также указан в **пути**, то он будет использоваться как параметр пути.
-* Если аннотация типа параметра содержит **примитивный тип** (`int`, `float`, `str`, `bool` и т.п.), он будет интерпретирован как параметр **запроса**.
-* Если аннотация типа параметра представляет собой **модель Pydantic**, он будет интерпретирован как параметр **тела запроса**.
+{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
+
+Параметры функции будут распознаны следующим образом:
+
+* Если параметр также объявлен в **пути**, он будет использоваться как параметр пути.
+* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**.
+* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.
/// note | Заметка
-FastAPI понимает, что значение параметра `q` не является обязательным, потому что имеет значение по умолчанию `= None`.
+FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.
+
+Аннотации типов `str | None` (Python 3.10+) или `Union[str, None]` (Python 3.8+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
-Ð\90нноÑ\82аÑ\86иÑ\8f `Optional` в `Optional[str]` не иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f FastAPI, но помогаеÑ\82 ваÑ\88емÑ\83 Ñ\80едакÑ\82оÑ\80Ñ\83 лÑ\83Ñ\87Ñ\88е понимаÑ\82Ñ\8c ваÑ\88 код и обнаруживать ошибки.
+Ð\9dо добавление анноÑ\82аÑ\86ий Ñ\82ипов позволиÑ\82 ваÑ\88емÑ\83 Ñ\80едакÑ\82оÑ\80Ñ\83 кода лÑ\83Ñ\87Ñ\88е ваÑ\81 поддеÑ\80живаÑ\82Ñ\8c и обнаруживать ошибки.
///
-## Без Pydantic
+## Без Pydantic { #without-pydantic }
-Если вы не хотите использовать модели Pydantic, вы все еще можете использовать параметры **тела запроса**. Читайте в документации раздел [Тело - Несколько параметров: Единичные значения в теле](body-multiple-params.md#_2){.internal-link target=_blank}.
+Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело — Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
-# Модели параметров cookie
+# Модели параметров cookie { #cookie-parameter-models }
Если у вас есть группа **cookies**, которые связаны между собой, вы можете создать **Pydantic-модель** для их объявления. 🍪
///
-## Pydantic-модель для cookies
+## Pydantic-модель для cookies { #cookies-with-a-pydantic-model }
Объявите параметры **cookie**, которые вам нужны, в **Pydantic-модели**, а затем объявите параметр как `Cookie`:
**FastAPI** **извлечёт** данные для **каждого поля** из **cookies**, полученных в запросе, и выдаст вам объявленную Pydantic-модель.
-## Проверка сгенерированной документации
+## Проверка сгенерированной документации { #check-the-docs }
Вы можете посмотреть объявленные cookies в графическом интерфейсе Документации по пути `/docs`:
///
-## Запрет дополнительных cookies
+## Запрет дополнительных cookies { #forbid-extra-cookies }
В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** cookies, которые вы хотите получать.
"type": "extra_forbidden",
"loc": ["cookie", "santa_tracker"],
"msg": "Extra inputs are not permitted",
- "input": "good-list-please"
+ "input": "good-list-please",
}
]
}
```
-## Заключение
+## Заключение { #summary }
Вы можете использовать **Pydantic-модели** для объявления <abbr title="Съешьте последнюю печеньку, прежде чем уйти. 🍪">**cookies**</abbr> в **FastAPI**. 😎
-# Параметры Cookie
+# Параметры Cookie { #cookie-parameters }
Вы можете задать параметры Cookie таким же способом, как `Query` и `Path` параметры.
-## Импорт `Cookie`
+## Импорт `Cookie` { #import-cookie }
Сначала импортируйте `Cookie`:
-{* ../../docs_src/cookie_params/tutorial001_py310.py hl[1] *}
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
-## Объявление параметров `Cookie`
+## Объявление параметров `Cookie` { #declare-cookie-parameters }
Затем объявляйте параметры cookie, используя ту же структуру, что и с `Path` и `Query`.
-Ð\9fеÑ\80вое знаÑ\87ение - Ñ\8dÑ\82о знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e, вÑ\8b можеÑ\82е пеÑ\80едаÑ\82Ñ\8c вÑ\81е дополниÑ\82елÑ\8cнÑ\8bе паÑ\80амеÑ\82Ñ\80Ñ\8b пÑ\80овеÑ\80ки или аннотации:
+Ð\92Ñ\8b можеÑ\82е задаÑ\82Ñ\8c знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e, а Ñ\82акже вÑ\81е дополниÑ\82елÑ\8cнÑ\8bе паÑ\80амеÑ\82Ñ\80Ñ\8b валидаÑ\86ии или аннотации:
-{* ../../docs_src/cookie_params/tutorial001_py310.py hl[7] *}
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
/// note | Технические детали
///
-## Резюме
+/// info | Дополнительная информация
+
+Имейте в виду, что, поскольку браузеры обрабатывают cookies особым образом и «за кулисами», они не позволяют JavaScript просто так получать к ним доступ.
+
+Если вы откроете интерфейс документации API на `/docs`, вы сможете увидеть документацию по cookies для ваших операций пути.
+
+Но даже если вы заполните данные и нажмёте «Execute», поскольку UI документации работает с JavaScript, cookies отправлены не будут, и вы увидите сообщение об ошибке, как будто вы не указали никаких значений.
+
+///
+
+## Резюме { #recap }
Объявляйте cookies с помощью `Cookie`, используя тот же общий шаблон, что и `Query`, и `Path`.
-# CORS (Cross-Origin Resource Sharing)
+# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Понятие CORS или "Cross-Origin Resource Sharing"</a> относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом "источнике" ("origin").
-## Источник
+## Источник { #origin }
-Источник - это совокупность протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`).
+Источник — это совокупность протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`).
Поэтому это три разных источника:
* `https://localhost`
* `http://localhost:8080`
-Даже если они все расположены в `localhost`, они используют разные протоколы и порты, а значит, являются разными источниками.
+Даже если они все расположены в `localhost`, они используют разные протоколы или порты, а значит, являются разными источниками.
-## Шаги
+## Шаги { #steps }
-Допустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`).
+Допустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`).
-Ð\97аÑ\82ем бÑ\80аÑ\83зеÑ\80 оÑ\82пÑ\80авиÑ\82 бÑ\8dкендÑ\83 HTTP-запÑ\80оÑ\81 `OPTIONS`, и еÑ\81ли бÑ\8dкенд веÑ\80нÑ\91Ñ\82 Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89ие заголовки длÑ\8f авÑ\82оÑ\80изаÑ\86ии взаимодейÑ\81Ñ\82виÑ\8f Ñ\81 дÑ\80Ñ\83гим иÑ\81Ñ\82оÑ\87ником (`http://localhost:8080`), Ñ\82о бÑ\80аÑ\83зеÑ\80 Ñ\80азÑ\80еÑ\88иÑ\82 JavaScript-кодÑ\83 на Ñ\84Ñ\80онÑ\82енде оÑ\82пÑ\80авиÑ\82Ñ\8c запÑ\80оÑ\81 на Ñ\8dÑ\82оÑ\82 бÑ\8dкенд.
+Ð\97аÑ\82ем бÑ\80аÑ\83зеÑ\80 оÑ\82пÑ\80авиÑ\82 на бÑ\8dкенд на `:80` HTTP-запÑ\80оÑ\81 `OPTIONS`, и еÑ\81ли бÑ\8dкенд веÑ\80нÑ\91Ñ\82 Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89ие HTTP-заголовки, авÑ\82оÑ\80изÑ\83Ñ\8eÑ\89ие взаимодейÑ\81Ñ\82вие Ñ\81 дÑ\80Ñ\83гим иÑ\81Ñ\82оÑ\87ником (`http://localhost:8080`), Ñ\82о бÑ\80аÑ\83зеÑ\80 на `:8080` Ñ\80азÑ\80еÑ\88иÑ\82 JavaScript на Ñ\84Ñ\80онÑ\82енде оÑ\82пÑ\80авиÑ\82Ñ\8c Ñ\81вой запÑ\80оÑ\81 на бÑ\8dкенд на `:80`.
-Чтобы это работало, у бэкенда должен быть список "разрешённых источников" ("allowed origins").
+ЧÑ\82обÑ\8b Ñ\8dÑ\82о Ñ\80абоÑ\82ало, Ñ\83 бÑ\8dкенда на `:80` должен бÑ\8bÑ\82Ñ\8c Ñ\81пиÑ\81ок "Ñ\80азÑ\80еÑ\88Ñ\91ннÑ\8bÑ\85 иÑ\81Ñ\82оÑ\87ников" ("allowed origins").
-В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд работал корректно.
+В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд на `:8080` работал корректно.
-## Подстановочный символ `"*"`
+## Подстановочный символ "*" { #wildcards }
В качестве списка источников можно указать подстановочный символ `"*"` ("wildcard"), чтобы разрешить любые источники.
-Ð\9dо Ñ\82огда не бÑ\83дÑ\83Ñ\82 Ñ\80азÑ\80еÑ\88енÑ\8b некоÑ\82оÑ\80Ñ\8bе видÑ\8b взаимодейÑ\81Ñ\82виÑ\8f, вклÑ\8eÑ\87аÑ\8f вÑ\81Ñ\91 Ñ\81вÑ\8fзанное Ñ\81 Ñ\83Ñ\87Ñ\91Ñ\82нÑ\8bми даннÑ\8bми: кÑ\83ки, заголовки Authorization Ñ\81 Bearer-Ñ\82окенами наподобие Ñ\82еÑ\85, коÑ\82оÑ\80Ñ\8bе мÑ\8b иÑ\81полÑ\8cзовали Ñ\80анее и т.п.
+Ð\9dо Ñ\82огда бÑ\83дÑ\83Ñ\82 Ñ\80азÑ\80еÑ\88енÑ\8b Ñ\82олÑ\8cко некоÑ\82оÑ\80Ñ\8bе видÑ\8b взаимодейÑ\81Ñ\82виÑ\8f, и вÑ\81Ñ\91, Ñ\87Ñ\82о Ñ\81вÑ\8fзано Ñ\81 Ñ\83Ñ\87Ñ\91Ñ\82нÑ\8bми даннÑ\8bми, бÑ\83деÑ\82 иÑ\81клÑ\8eÑ\87ено: кÑ\83ки, HTTP-заголовки Authorization, как пÑ\80и иÑ\81полÑ\8cзовании Bearer-Ñ\82окенов, и т.п.
Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.
-## Использование `CORSMiddleware`
+## Использование `CORSMiddleware` { #use-corsmiddleware }
-Вы можете настроить этот механизм в вашем **FastAPI** приложении, используя `CORSMiddleware`.
+Вы можете настроить это в вашем **FastAPI**-приложении, используя `CORSMiddleware`.
* Импортируйте `CORSMiddleware`.
* Создайте список разрешённых источников (в виде строк).
-* Добавьте его как "middleware" к вашему **FastAPI** приложению.
+* Добавьте его как "middleware" (промежуточный слой) к вашему **FastAPI**-приложению.
Вы также можете указать, разрешает ли ваш бэкенд использование:
-* Учётных данных (включая заголовки Authorization, куки и т.п.).
+* Учётных данных (HTTP-заголовки Authorization, куки и т.п.).
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
-`CORSMiddleware` использует для параметров "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
+`CORSMiddleware` использует "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
Поддерживаются следующие аргументы:
* `allow_origins` - Список источников, на которые разрешено выполнять кросс-доменные запросы. Например, `['https://example.org', 'https://www.example.org']`. Можно использовать `['*']`, чтобы разрешить любые источники.
-* `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\.example\.org'`.
-* `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию равно `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы.
-* `allow_headers` - Список HTTP-заголовков, которые должны поддерживаться при кросс-доменных запросах. По умолчанию равно `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">простых CORS-запросов</a>.
-* `allow_credentials` - указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. Также, `allow_origins` нельзя присвоить `['*']`, если разрешено использование учётных данных. В таком случае должен быть указан список источников.
-* `expose_headers` - Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию равно `[]`.
-* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию равно `600`.
+* `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\.example\.org'`.
+* `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы.
+* `allow_headers` - Список HTTP-заголовков запроса, которые должны поддерживаться при кросс-доменных запросах. По умолчанию `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">простых CORS-запросов</a>.
+* `allow_credentials` - Указывает, что куки разрешены в кросс-доменных запросах. По умолчанию `False`.
+
+ Ни один из параметров `allow_origins`, `allow_methods` и `allow_headers` не может быть установлен в `['*']`, если `allow_credentials` имеет значение `True`. Все они должны быть <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">указаны явно</a>.
+
+* `expose_headers` - Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию `[]`.
+* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию `600`.
`CORSMiddleware` отвечает на два типа HTTP-запросов...
-### CORS-запросы с предварительной проверкой
+### CORS-запросы с предварительной проверкой { #cors-preflight-requests }
-Это любые `OPTIONS` запросы с заголовками `Origin` и `Access-Control-Request-Method`.
+Это любые `OPTIONS`-запросы с заголовками `Origin` и `Access-Control-Request-Method`.
В этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` в информационных целях.
-### Простые запросы
+### Простые запросы { #simple-requests }
Любые запросы с заголовком `Origin`. В этом случае middleware передаст запрос дальше как обычно, но добавит соответствующие CORS-заголовки к ответу.
-## Больше информации
+## Больше информации { #more-info }
-Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Документации CORS от Mozilla</a>.
+Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing – совместное использование ресурсов между источниками">CORS</abbr> обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">документации CORS от Mozilla</a>.
/// note | Технические детали
-# Отладка
+# Отладка { #debugging }
Вы можете подключить отладчик в своем редакторе, например, в Visual Studio Code или PyCharm.
-## Вызов `uvicorn`
+## Вызов `uvicorn` { #call-uvicorn }
В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
-### Описание `__name__ == "__main__"`
+### Описание `__name__ == "__main__"` { #about-name-main }
Главная цель использования `__name__ == "__main__"` в том, чтобы код выполнялся при запуске файла с помощью:
from myapp import app
```
-#### Больше деталей
+#### Больше деталей { #more-details }
Давайте назовём ваш файл `myapp.py`.
///
-## Запуск вашего кода с помощью отладчика
+## Запуск вашего кода с помощью отладчика { #run-your-code-with-your-debugger }
Так как вы запускаете сервер Uvicorn непосредственно из вашего кода, вы можете вызвать Python программу (ваше FastAPI приложение) напрямую из отладчика.
-# Классы как зависимости
+# Классы как зависимости { #classes-as-dependencies }
Прежде чем углубиться в систему **Внедрения Зависимостей**, давайте обновим предыдущий пример.
-## `Словарь` из предыдущего примера
+## `dict` из предыдущего примера { #a-dict-from-the-previous-example }
-В предыдущем примере мы возвращали `словарь` из нашей зависимости:
+В предыдущем примере мы возвращали `dict` из нашей зависимости:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
-Но затем мы получаем `словарь` в параметре `commons` *функции операции пути*. И мы знаем, что редакторы не могут обеспечить достаточную поддержку для `словаря`, поскольку они не могут знать их ключи и типы значений.
+Но затем мы получаем `dict` в параметре `commons` *функции-обработчика пути*.
+
+И мы знаем, что редакторы кода не могут обеспечить достаточную поддержку (например, автозавершение) для `dict`, поскольку они не могут знать их ключи и типы значений.
Мы можем сделать лучше...
-## Что делает зависимость
+## Что делает зависимость { #what-makes-a-dependency }
До сих пор вы видели зависимости, объявленные как функции.
-Но это не единственный способ объявления зависимостей (хотя, вероятно, более распространенный).
+Но это не единственный способ объявления зависимостей (хотя он, вероятно, более распространенный).
-Ключевым фактором является то, что зависимость должна быть "вызываемой".
+Ключевым фактором является то, что зависимость должна быть «вызываемой».
-В Python "**вызываемый**" - это все, что Python может "вызвать", как функцию.
+В Python «**вызываемый**» — это всё, что Python может «вызвать», как функцию.
-Так, если у вас есть объект `something` (который может _не_ быть функцией) и вы можете "вызвать" его (выполнить) как:
+Так, если у вас есть объект `something` (который может и _не_ быть функцией) и вы можете «вызвать» его (выполнить) так:
```Python
something()
something(some_argument, some_keyword_argument="foo")
```
-в таком случае он является "вызываемым".
+в таком случае он является «вызываемым».
-## Классы как зависимости
+## Классы как зависимости { #classes-as-dependencies_1 }
Вы можете заметить, что для создания экземпляра класса в Python используется тот же синтаксис.
В данном случае `fluffy` является экземпляром класса `Cat`.
-А чтобы создать `fluffy`, вы "вызываете" `Cat`.
+А чтобы создать `fluffy`, вы «вызываете» `Cat`.
Таким образом, класс в Python также является **вызываемым**.
Тогда в **FastAPI** в качестве зависимости можно использовать класс Python.
-На самом деле FastAPI проверяет, что переданный объект является "вызываемым" (функция, класс или что-либо еще) и указаны необходимые для его вызова параметры.
+На самом деле FastAPI проверяет, что переданный объект является «вызываемым» (функция, класс или что-либо еще) и какие параметры у него определены.
-Если вы передаёте что-то, что можно "вызывать" в качестве зависимости в **FastAPI**, то он будет анализировать параметры, необходимые для "вызова" этого объекта и обрабатывать их так же, как параметры *функции операции пути*. Включая подзависимости.
+Если вы передаёте «вызываемый» объект в качестве зависимости в **FastAPI**, он проанализирует параметры, необходимые для этого «вызываемого» объекта, и обработает их так же, как параметры *функции-обработчика пути*. Включая подзависимости.
-Это относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций операции пути* без параметров.
+Это относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций-обработчиков пути* без параметров.
Теперь мы можем изменить зависимость `common_parameters`, указанную выше, на класс `CommonQueryParams`:
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
-...имеет те же параметры, что и ранее используемая функция `common_parameters`:
+...он имееÑ\82 Ñ\82е же паÑ\80амеÑ\82Ñ\80Ñ\8b, Ñ\87Ñ\82о и Ñ\80анее иÑ\81полÑ\8cзÑ\83емаÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f `common_parameters`:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
-Эти параметры и будут использоваться **FastAPI** для "решения" зависимости.
+Эти параметры и будут использоваться **FastAPI** для «решения» зависимости.
В обоих случаях она будет иметь:
* Необязательный параметр запроса `q`, представляющий собой `str`.
* Параметр запроса `skip`, представляющий собой `int`, по умолчанию `0`.
-* Параметр запроса `limit`, представляющий собой `int`, по умолчанию равный `100`.
+* Параметр запроса `limit`, представляющий собой `int`, по умолчанию `100`.
-Ð\92 обоиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 даннÑ\8bе бÑ\83дÑ\83Ñ\82 конвеÑ\80Ñ\82иÑ\80ованÑ\8b, валидиÑ\80ованÑ\8b, докÑ\83менÑ\82иÑ\80ованÑ\8b по схеме OpenAPI и т.д.
+Ð\92 обоиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 даннÑ\8bе бÑ\83дÑ\83Ñ\82 конвеÑ\80Ñ\82иÑ\80ованÑ\8b, валидиÑ\80ованÑ\8b, задокÑ\83менÑ\82иÑ\80ованÑ\8b в схеме OpenAPI и т.д.
-## Как это использовать
+## Как это использовать { #use-it }
Теперь вы можете объявить свою зависимость, используя этот класс.
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
-**FastAPI** вызывает класс `CommonQueryParams`. При этом создается "экземпляр" этого класса, который будет передан в качестве параметра `commons` в вашу функцию.
+**FastAPI** вызывает класс `CommonQueryParams`. При этом создается «экземпляр» этого класса, который будет передан в качестве параметра `commons` в вашу функцию.
-## Аннотация типа или `Depends`
+## Аннотация типа и `Depends` { #type-annotation-vs-depends }
Обратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`:
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
+//// tab | Python 3.8+
```Python
-commons: CommonQueryParams = Depends(CommonQueryParams)
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
-//// tab | Python 3.6+
+//// tab | Python 3.8+ non-Annotated
+
+/// tip | Подсказка
+
+Рекомендуется использовать версию с `Annotated`, если возможно.
+
+///
```Python
-commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+commons: CommonQueryParams = Depends(CommonQueryParams)
```
////
-Последний параметр `CommonQueryParams`, в:
+Последний `CommonQueryParams`, в:
```Python
... Depends(CommonQueryParams)
...это то, что **FastAPI** будет использовать, чтобы узнать, что является зависимостью.
-Из него FastAPI извлечёт объявленные параметры и именно их будет вызывать.
+Из него FastAPI извлечёт объявленные параметры, и именно его FastAPI будет вызывать.
---
В этом случае первый `CommonQueryParams`, в:
-//// tab | Python 3.6+
+//// tab | Python 3.8+
```Python
commons: Annotated[CommonQueryParams, ...
////
-//// tab | Python 3.6+ без Annotated
+//// tab | Python 3.8+ non-Annotated
/// tip | Подсказка
-Рекомендуется использовать версию с `Annotated` если возможно.
+Рекомендуется использовать версию с `Annotated`, если возможно.
///
На самом деле можно написать просто:
-//// tab | Python 3.6+
+//// tab | Python 3.8+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
////
-//// tab | Python 3.6+ без Annotated
+//// tab | Python 3.8+ non-Annotated
/// tip | Подсказка
-Рекомендуется использовать версию с `Annotated` если возможно.
+Рекомендуется использовать версию с `Annotated`, если возможно.
///
{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
-Ð\9dо обÑ\8aÑ\8fвление Ñ\82ипа пÑ\80ивеÑ\82Ñ\81Ñ\82вÑ\83еÑ\82Ñ\81Ñ\8f, Ñ\82ак как в Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае ваÑ\88 Ñ\80едакÑ\82оÑ\80 бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о бÑ\83деÑ\82 пеÑ\80едано в каÑ\87еÑ\81Ñ\82ве паÑ\80амеÑ\82Ñ\80а `commons`, и Ñ\82огда он Ñ\81можеÑ\82 помоÑ\87Ñ\8c вам Ñ\81 авÑ\82одополнением, пÑ\80овеÑ\80кой Ñ\82ипов и Ñ\82.д:
+Ð\9dо обÑ\8aÑ\8fвление Ñ\82ипа пÑ\80ивеÑ\82Ñ\81Ñ\82вÑ\83еÑ\82Ñ\81Ñ\8f, Ñ\82ак как в Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае ваÑ\88 Ñ\80едакÑ\82оÑ\80 кода бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о бÑ\83деÑ\82 пеÑ\80едано в каÑ\87еÑ\81Ñ\82ве паÑ\80амеÑ\82Ñ\80а `commons`, и Ñ\82огда он Ñ\81можеÑ\82 помоÑ\87Ñ\8c вам Ñ\81 авÑ\82озавеÑ\80Ñ\88ением, пÑ\80овеÑ\80кой Ñ\82ипов и Ñ\82.д.:
<img src="/img/tutorial/dependencies/image02.png">
-## Сокращение
+## Сокращение { #shortcut }
Но вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`:
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
+//// tab | Python 3.8+
```Python
-commons: CommonQueryParams = Depends(CommonQueryParams)
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
-//// tab | Python 3.6+
+//// tab | Python 3.8+ non-Annotated
+
+/// tip | Подсказка
+
+Рекомендуется использовать версию с `Annotated`, если возможно.
+
+///
```Python
-commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+commons: CommonQueryParams = Depends(CommonQueryParams)
```
////
-Для случаев, когда зависимостью является *конкретный* класс, который **FastAPI** "вызовет" для создания экземпляра этого класса, можно использовать укороченную запись.
+**FastAPI** предоставляет сокращение для таких случаев, когда зависимость — это *конкретный* класс, который **FastAPI** будет «вызывать» для создания экземпляра этого класса.
+Для этих конкретных случаев вы можете сделать следующее.
Вместо того чтобы писать:
-//// tab | Python 3.6+
+//// tab | Python 3.8+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.6+ без Annotated
+//// tab | Python 3.8+ non-Annotated
/// tip | Подсказка
-Рекомендуется использовать версию с `Annotated` если возможно.
+Рекомендуется использовать версию с `Annotated`, если возможно.
///
...следует написать:
-//// tab | Python 3.6+
+//// tab | Python 3.8+
```Python
commons: Annotated[CommonQueryParams, Depends()]
////
-//// tab | Python 3.6 без Annotated
+//// tab | Python 3.8 non-Annotated
/// tip | Подсказка
-Рекомендуется использовать версию с `Annotated` если возможно.
+Рекомендуется использовать версию с `Annotated`, если возможно.
///
/// tip | Подсказка
-Если это покажется вам более запутанным, чем полезным, не обращайте внимания, это вам не *нужно*.
+Если это покажется вам более запутанным, чем полезным, не обращайте внимания — это вам не *нужно*.
Это просто сокращение. Потому что **FastAPI** заботится о том, чтобы помочь вам свести к минимуму повторение кода.
-# Зависимости в декораторах операции пути
+# Зависимости в декораторах операции пути { #dependencies-in-path-operation-decorators }
В некоторых случаях, возвращаемое значение зависимости не используется внутри *функции операции пути*.
Для таких ситуаций, вместо объявления *функции операции пути* с параметром `Depends`, вы можете добавить список зависимостей `dependencies` в *декоратор операции пути*.
-## Добавление `dependencies` в *декоратор операции пути*
+## Добавление `dependencies` (зависимостей) в *декоратор операции пути* { #add-dependencies-to-the-path-operation-decorator }
*Декоратор операции пути* получает необязательный аргумент `dependencies`.
///
-## Исключения в dependencies и возвращаемые значения
+## Исключения в Зависимостях и возвращаемые значения { #dependencies-errors-and-return-values }
Вы можете использовать те же *функции* зависимостей, что и обычно.
-### Требования к зависимостям
+### Требования к зависимостям { #dependency-requirements }
Они могут объявлять требования к запросу (например заголовки) или другие подзависимости:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
-### Вызов исключений
+### Вызов исключений { #raise-exceptions }
Зависимости из dependencies могут вызывать исключения с помощью `raise`, как и обычные зависимости:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
-### Возвращаемые значения
+### Возвращаемые значения { #return-values }
И они могут возвращать значения или нет, эти значения использоваться не будут.
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
-## Dependencies для группы *операций путей*
+## Зависимости для группы *операций путей* { #dependencies-for-a-group-of-path-operations }
-Позже, читая о том как структурировать большие приложения ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), возможно, многофайловые, вы узнаете как объявить единый параметр `dependencies` для всей группы *операций путей*.
+Позже, читая о том как структурировать большие приложения ([Большие приложения — несколько файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}), возможно, многофайловые, вы узнаете как объявить единый параметр `dependencies` для всей группы *операций путей*.
-## Ð\93лобалÑ\8cнÑ\8bй Dependencies
+## Ð\93лобалÑ\8cнÑ\8bе Ð\97авиÑ\81имоÑ\81Ñ\82и { #global-dependencies }
Далее мы увидим, как можно добавить dependencies для всего `FastAPI` приложения, так чтобы они применялись к каждой *операции пути*.
-# Зависимости с yield
+# Зависимости с yield { #dependencies-with-yield }
-FastAPI поддерживает зависимости, которые выполняют некоторые <abbr title='также известные как "exit", "cleanup", "teardown", "close", "context managers", ...'>дополнительные действия после завершения работы</abbr>.
+FastAPI поддерживает зависимости, которые выполняют некоторые <abbr title='иногда также называемые "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code" и т.п.'>дополнительные шаги после завершения</abbr>.
-Ð\94лÑ\8f Ñ\8dÑ\82ого иÑ\81полÑ\8cзÑ\83йÑ\82е `yield` вмеÑ\81Ñ\82о `return`, а дополниÑ\82елÑ\8cнÑ\8bй код напишите после него.
+Ð\94лÑ\8f Ñ\8dÑ\82ого иÑ\81полÑ\8cзÑ\83йÑ\82е `yield` вмеÑ\81Ñ\82о `return`, а дополниÑ\82елÑ\8cнÑ\8bе Ñ\88аги (код) напишите после него.
/// tip | Подсказка
-Ð\9eбÑ\8fзаÑ\82елÑ\8cно иÑ\81полÑ\8cзÑ\83йÑ\82е `yield` один-единÑ\81Ñ\82веннÑ\8bй Ñ\80аз.
+УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о иÑ\81полÑ\8cзÑ\83еÑ\82е `yield` Ñ\82олÑ\8cко один Ñ\80аз на однÑ\83 завиÑ\81имоÑ\81Ñ\82Ñ\8c.
///
/// note | Технические детали
-Ð\9bÑ\8eбаÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f, Ñ\81 коÑ\82оÑ\80ой можеÑ\82 Ñ\80абоÑ\82ать:
+Ð\9bÑ\8eбаÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f, Ñ\81 коÑ\82оÑ\80ой можно коÑ\80Ñ\80екÑ\82но иÑ\81полÑ\8cзовать:
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> или
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
-будет корректно использоваться в качестве **FastAPI**-зависимости.
+будет корректной для использования в качестве зависимости **FastAPI**.
-На самом деле, FastAPI использует эту пару декораторов "под капотом".
+На самом деле, FastAPI использует эти два декоратора внутренне.
///
-## Зависимость базы данных с помощью `yield`
+## Зависимость базы данных с помощью `yield` { #a-database-dependency-with-yield }
-Например, с его помощью можно создать сессию работы с базой данных и закрыть его после завершения.
+Например, с его помощью можно создать сессию работы с базой данных и закрыть её после завершения.
-Перед созданием ответа будет выполнен только код до и включая `yield`.
+Перед созданием ответа будет выполнен только код до и включая оператор `yield`:
{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *}
-Ð\9fолÑ\83Ñ\87енное знаÑ\87ение и еÑ\81Ñ\82Ñ\8c Ñ\82о, Ñ\87Ñ\82о бÑ\83деÑ\82 внедÑ\80ено в Ñ\84Ñ\83нкÑ\86иÑ\8e опеÑ\80аÑ\86ии пÑ\83Ñ\82и и другие зависимости:
+Ð\97наÑ\87ение, полÑ\83Ñ\87енное из `yield`, внедÑ\80Ñ\8fеÑ\82Ñ\81Ñ\8f в *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* и другие зависимости:
{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
-Ð\9aод, Ñ\81ледÑ\83Ñ\8eÑ\89ий за опеÑ\80аÑ\82оÑ\80ом `yield`, вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f поÑ\81ле доÑ\81Ñ\82авки оÑ\82веÑ\82а:
+Код, следующий за оператором `yield`, выполняется после ответа:
{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *}
/// tip | Подсказка
-Можно использовать как `async` так и обычные функции.
+Можно использовать как `async`, так и обычные функции.
-**FastAPI** это корректно обработает, и в обоих случаях будет делать то же самое, что и с обычными зависимостями.
+**FastAPI** корректно обработает каждый вариант, так же как и с обычными зависимостями.
///
-## Зависимость с `yield` и `try` одновременно
+## Зависимость с `yield` и `try` { #a-dependency-with-yield-and-try }
-Ð\95Ñ\81ли иÑ\81полÑ\8cзоваÑ\82Ñ\8c блок `try` в завиÑ\81имоÑ\81Ñ\82и Ñ\81 `yield`, Ñ\82о бÑ\83деÑ\82 полÑ\83Ñ\87ено вÑ\81Ñ\8fкое исключение, которое было выброшено при использовании зависимости.
+Ð\95Ñ\81ли иÑ\81полÑ\8cзоваÑ\82Ñ\8c блок `try` в завиÑ\81имоÑ\81Ñ\82и Ñ\81 `yield`, Ñ\82о вÑ\8b полÑ\83Ñ\87иÑ\82е лÑ\8eбое исключение, которое было выброшено при использовании зависимости.
-Например, если какой-то код в какой-то момент в середине, в другой зависимости или в *функции операции пути*, сделал "откат" транзакции базы данных или создал любую другую ошибку, то вы получите исключение в своей зависимости.
+Например, если какой-то код в какой-то момент в середине, в другой зависимости или в *операции пути*, сделал "откат" транзакции базы данных или создал любую другую ошибку, то вы получите это исключение в своей зависимости.
Таким образом, можно искать конкретное исключение внутри зависимости с помощью `except SomeException`.
-Таким же обÑ\80азом можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c `finally`, Ñ\87Ñ\82обÑ\8b Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о обÑ\8fзаÑ\82елÑ\8cнÑ\8bе Ñ\88аги пÑ\80и вÑ\8bÑ\85оде вÑ\8bполненÑ\8b, независимо от того, было ли исключение или нет.
+ТоÑ\87но Ñ\82ак же можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c `finally`, Ñ\87Ñ\82обÑ\8b Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о обÑ\8fзаÑ\82елÑ\8cнÑ\8bе Ñ\88аги пÑ\80и вÑ\8bÑ\85оде вÑ\8bполненÑ\8b независимо от того, было ли исключение или нет.
{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
-## Подзависимости с `yield`
+## Подзависимости с `yield` { #sub-dependencies-with-yield }
Вы можете иметь подзависимости и "деревья" подзависимостей любого размера и формы, и любая из них или все они могут использовать `yield`.
-**FastAPI** бÑ\83деÑ\82 Ñ\81ледиÑ\82Ñ\8c за Ñ\82ем, Ñ\87Ñ\82обÑ\8b "код по вÑ\8bÑ\85одÑ\83" в каждой зависимости с `yield` выполнялся в правильном порядке.
+**FastAPI** пÑ\80оÑ\81ледиÑ\82 за Ñ\82ем, Ñ\87Ñ\82обÑ\8b «код вÑ\8bÑ\85ода» в каждой зависимости с `yield` выполнялся в правильном порядке.
-Ð\9dапÑ\80имеÑ\80, `dependency_c` можеÑ\82 имеÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82Ñ\8c оÑ\82 `dependency_b`, а `dependency_b` от `dependency_a`:
+Ð\9dапÑ\80имеÑ\80, `dependency_c` можеÑ\82 завиÑ\81еÑ\82Ñ\8c оÑ\82 `dependency_b`, а `dependency_b` â\80\94 от `dependency_a`:
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
И все они могут использовать `yield`.
-Ð\92 Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае `dependency_c` длÑ\8f вÑ\8bполнениÑ\8f Ñ\81воего кода вÑ\8bÑ\85ода нÑ\83ждаеÑ\82Ñ\81Ñ\8f в Ñ\82ом, Ñ\87Ñ\82обÑ\8b знаÑ\87ение из `dependency_b` (здеÑ\81Ñ\8c `dep_b`) бÑ\8bло еÑ\89е доступно.
+Ð\92 Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае `dependency_c` длÑ\8f вÑ\8bполнениÑ\8f Ñ\81воего кода вÑ\8bÑ\85ода нÑ\83ждаеÑ\82Ñ\81Ñ\8f в Ñ\82ом, Ñ\87Ñ\82обÑ\8b знаÑ\87ение из `dependency_b` (здеÑ\81Ñ\8c `dep_b`) вÑ\81Ñ\91 еÑ\89Ñ\91 бÑ\8bло доступно.
-И, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для ее завершающего кода.
+И, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для её кода выхода.
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
-Точно так же можно иметь часть зависимостей с `yield`, часть с `return`, и какие-то из них могут зависеть друг от друга.
+Точно так же можно иметь часть зависимостей с `yield`, часть — с `return`, и какие-то из них могут зависеть друг от друга.
Либо у вас может быть одна зависимость, которая требует несколько других зависимостей с `yield` и т.д.
-Комбинации зависимостей могут быть какими вам угодно.
+Комбинации зависимостей могут быть какими угодно.
-**FastAPI** проследит за тем, чтобы все выполнялось в правильном порядке.
+**FastAPI** проследит за тем, чтобы всё выполнялось в правильном порядке.
/// note | Технические детали
-Это работает благодаря <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">Контекстным менеджерам</a> в Python.
+Это работает благодаря <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">менеджерам контекста</a> в Python.
+
+**FastAPI** использует их внутренне для достижения этого.
///
- **FastAPI** использует их "под капотом" с этой целью.
+## Зависимости с `yield` и `HTTPException` { #dependencies-with-yield-and-httpexception }
-## Зависимости с `yield` и `HTTPException`
+Вы видели, что можно использовать зависимости с `yield` и иметь блоки `try`, которые пытаются выполнить некоторый код, а затем запускают код выхода в `finally`.
-Ð\92Ñ\8b видели, Ñ\87Ñ\82о можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82и Ñ\81 `yield` Ñ\81овмеÑ\81Ñ\82но Ñ\81 блоком `try`, оÑ\82лавливаÑ\8eÑ\89ие иÑ\81клÑ\8eÑ\87ениÑ\8f.
+Также вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c `except`, Ñ\87Ñ\82обÑ\8b поймаÑ\82Ñ\8c вÑ\8bзванное иÑ\81клÑ\8eÑ\87ение и Ñ\87Ñ\82о-Ñ\82о Ñ\81 ним Ñ\81делаÑ\82Ñ\8c.
-Таким же обÑ\80азом вÑ\8b можеÑ\82е поднÑ\8fÑ\82Ñ\8c иÑ\81клÑ\8eÑ\87ение `HTTPException` или Ñ\87Ñ\82о-Ñ\82о подобное в завеÑ\80Ñ\88аÑ\8eÑ\89ем коде, поÑ\81ле `yield`.
+Ð\9dапÑ\80имеÑ\80, вÑ\8b можеÑ\82е <abbr title="«raise» доÑ\81ловно - «поднÑ\8fÑ\82Ñ\8c», но «вÑ\8bзваÑ\82Ñ\8c», «Ñ\81генеÑ\80иÑ\80оваÑ\82Ñ\8c» или «вÑ\8bбÑ\80оÑ\81иÑ\82Ñ\8c» Ñ\83поÑ\82Ñ\80еблÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\89е">вÑ\8bзваÑ\82Ñ\8c</abbr> дÑ\80Ñ\83гое иÑ\81клÑ\8eÑ\87ение, напÑ\80имеÑ\80 `HTTPException`.
-Код выхода в зависимостях с `yield` выполняется *после* отправки ответа, поэтому [Обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} уже будет запущен. В коде выхода (после `yield`) нет ничего, перехватывающего исключения, брошенные вашими зависимостями.
+/// tip | Подсказка
-Таким обÑ\80азом, еÑ\81ли поÑ\81ле `yield` возникаеÑ\82 `HTTPException`, Ñ\82о Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bй (или лÑ\8eбой полÑ\8cзоваÑ\82елÑ\8cÑ\81кий) обÑ\80абоÑ\82Ñ\87ик иÑ\81клÑ\8eÑ\87ений, коÑ\82оÑ\80Ñ\8bй пеÑ\80еÑ\85ваÑ\82Ñ\8bваеÑ\82 `HTTPException` и возвÑ\80аÑ\89аеÑ\82 оÑ\82веÑ\82 HTTP 400, Ñ\83же не Ñ\81можеÑ\82 пеÑ\80еÑ\85ваÑ\82иÑ\82Ñ\8c Ñ\8dÑ\82о иÑ\81клÑ\8eÑ\87ение.
+ÐÑ\82о доволÑ\8cно пÑ\80одвинÑ\83Ñ\82аÑ\8f Ñ\82еÑ\85ника, и в болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев она вам не понадобиÑ\82Ñ\81Ñ\8f, Ñ\82ак как вÑ\8b можеÑ\82е вÑ\8bзÑ\8bваÑ\82Ñ\8c иÑ\81клÑ\8eÑ\87ениÑ\8f (вклÑ\8eÑ\87аÑ\8f `HTTPException`) в оÑ\81Ñ\82алÑ\8cном коде ваÑ\88его пÑ\80иложениÑ\8f, напÑ\80имеÑ\80, в *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87ике пÑ\83Ñ\82и*.
-Ð\91лагодаÑ\80Ñ\8f Ñ\8dÑ\82омÑ\83 вÑ\81е, Ñ\87Ñ\82о Ñ\83Ñ\81Ñ\82ановлено в завиÑ\81имоÑ\81Ñ\82и (напÑ\80имеÑ\80, Ñ\81еанÑ\81 Ñ\80абоÑ\82Ñ\8b Ñ\81 Ð\91Ð\94), можеÑ\82 бÑ\8bÑ\82Ñ\8c иÑ\81полÑ\8cзовано, напÑ\80имеÑ\80, Ñ\84оновÑ\8bми задаÑ\87ами.
+Ð\9dо еÑ\81ли понадобиÑ\82Ñ\81Ñ\8f â\80\94 возможноÑ\81Ñ\82Ñ\8c еÑ\81Ñ\82Ñ\8c. ð\9f¤\93
-Фоновые задачи выполняются *после* отправки ответа. Поэтому нет возможности поднять `HTTPException`, так как нет даже возможности изменить уже отправленный ответ.
+///
-Но если фоновая задача создает ошибку в БД, то, по крайней мере, можно сделать откат или чисто закрыть сессию в зависимости с помощью `yield`, а также, возможно, занести ошибку в журнал или сообщить о ней в удаленную систему отслеживания.
+{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
-Если у вас есть код, который, как вы знаете, может вызвать исключение, сделайте самую обычную/"питонячью" вещь и добавьте блок `try` в этот участок кода.
+Если вы хотите перехватывать исключения и формировать на их основе пользовательский ответ, создайте [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
-Если у вас есть пользовательские исключения, которые вы хотите обрабатывать *до* возврата ответа и, возможно, модифицировать ответ, даже вызывая `HTTPException`, создайте [Cобственный обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
+## Зависимости с `yield` и `except` { #dependencies-with-yield-and-except }
-/// tip | Подсказка
+Если вы ловите исключение с помощью `except` в зависимости с `yield` и не вызываете его снова (или не вызываете новое исключение), FastAPI не сможет заметить, что было исключение — так же, как это происходит в обычном Python:
-Вы все еще можете вызывать исключения, включая `HTTPException`, *до* `yield`. Но не после.
+{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
-///
+В этом случае клиент получит *HTTP 500 Internal Server Error*, как и должно быть, поскольку мы не вызываем `HTTPException` или что-то подобное, но на сервере **не будет никаких логов** или других указаний на то, какая была ошибка. 😱
+
+### Всегда делайте `raise` в зависимостях с `yield` и `except` { #always-raise-in-dependencies-with-yield-and-except }
+
+Если вы ловите исключение в зависимости с `yield`, то, если вы не вызываете другой `HTTPException` или что-то подобное, вам следует повторно вызвать исходное исключение.
+
+Вы можете повторно вызвать то же самое исключение с помощью `raise`:
-Последовательность выполнения примерно такая, как на этой схеме. Время течет сверху вниз. А каждый столбец - это одна из частей, взаимодействующих с кодом или выполняющих код.
+{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
+
+Теперь клиент получит тот же *HTTP 500 Internal Server Error*, но на сервере в логах будет наше пользовательское `InternalError`. 😎
+
+## Выполнение зависимостей с `yield` { #execution-of-dependencies-with-yield }
+
+Последовательность выполнения примерно такая, как на этой схеме. Время течёт сверху вниз. А каждый столбец — это одна из частей, взаимодействующих с кодом или выполняющих код.
```mermaid
sequenceDiagram
participant operation as Path Operation
participant tasks as Background tasks
- Note over client,tasks: Can raise exception for dependency, handled after response is sent
- Note over client,operation: Can raise HTTPException and can change the response
+ Note over client,operation: Can raise exceptions, including HTTPException
client ->> dep: Start request
Note over dep: Run code up to yield
- opt raise
- dep -->> handler: Raise HTTPException
+ opt raise Exception
+ dep -->> handler: Raise Exception
handler -->> client: HTTP error response
- dep -->> dep: Raise other exception
end
dep ->> operation: Run dependency, e.g. DB session
opt raise
- operation -->> dep: Raise HTTPException
- dep -->> handler: Auto forward exception
+ operation -->> dep: Raise Exception (e.g. HTTPException)
+ opt handle
+ dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
+ end
handler -->> client: HTTP error response
- operation -->> dep: Raise other exception
- dep -->> handler: Auto forward exception
end
+
operation ->> client: Return response to client
Note over client,operation: Response is already sent, can't change it anymore
opt Tasks
operation -->> tasks: Send background tasks
end
opt Raise other exception
- tasks -->> dep: Raise other exception
- end
- Note over dep: After yield
- opt Handle other exception
- dep -->> dep: Handle exception, can't change response. E.g. close DB session.
+ tasks -->> tasks: Handle exceptions in the background task code
end
```
/// info | Дополнительная информация
-Клиенту будет отправлен только **один ответ**. Это может быть один из ответов об ошибке или это будет ответ от *операции пути*.
-
-После отправки одного из этих ответов никакой другой ответ не может быть отправлен.
+Клиенту будет отправлен только **один ответ**. Это может быть один из ответов об ошибке или ответ от *операции пути*.
-///
-
-/// tip | Подсказка
-
-На этой диаграмме показано "HttpException", но вы также можете вызвать любое другое исключение, для которого вы создаете [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
-
-Если вы создадите какое-либо исключение, оно будет передано зависимостям с yield, включая `HttpException`, а затем **снова** обработчикам исключений. Если для этого исключения нет обработчика исключений, то оно будет обработано внутренним "ServerErrorMiddleware" по умолчанию, возвращающим код состояния HTTP 500, чтобы уведомить клиента, что на сервере произошла ошибка.
+После отправки одного из этих ответов никакой другой ответ отправить нельзя.
///
-## Зависимости с `yield`, `HTTPException` и фоновыми задачами
-
-/// warning | Внимание
-
-Скорее всего, вам не нужны эти технические подробности, вы можете пропустить этот раздел и продолжить ниже.
-
-Эти подробности полезны, главным образом, если вы использовали версию FastAPI до 0.106.0 и использовали ресурсы из зависимостей с `yield` в фоновых задачах.
-
-///
-
-До версии FastAPI 0.106.0 вызывать исключения после `yield` было невозможно, код выхода в зависимостях с `yield` выполнялся *после* отправки ответа, поэтому [Обработчик Ошибок](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} уже был бы запущен.
-
-Это было сделано главным образом для того, чтобы позволить использовать те же объекты, "отданные" зависимостями, внутри фоновых задач, поскольку код выхода будет выполняться после завершения фоновых задач.
-
-Тем не менее, поскольку это означало бы ожидание ответа в сети, а также ненужное удержание ресурса в зависимости от доходности (например, соединение с базой данных), это было изменено в FastAPI 0.106.0.
-
/// tip | Подсказка
-Кроме того, фоновая задача обычно представляет собой независимый набор логики, который должен обрабатываться отдельно, со своими собственными ресурсами (например, собственным подключением к базе данных).
-Таким образом, вы, вероятно, получите более чистый код.
+Если вы вызовете какое-либо исключение в коде из *функции-обработчика пути*, оно будет передано зависимостям с `yield`, включая `HTTPException`. В большинстве случаев вы захотите повторно вызвать то же самое исключение или новое из зависимости с `yield`, чтобы убедиться, что оно корректно обработано.
///
-Если вы полагались на это поведение, то теперь вам следует создавать ресурсы для фоновых задач внутри самой фоновой задачи, а внутри использовать только те данные, которые не зависят от ресурсов зависимостей с `yield`.
+## Зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }
-Ð\9dапÑ\80имеÑ\80, вмеÑ\81Ñ\82о Ñ\82ого Ñ\87Ñ\82обÑ\8b иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82Ñ\83 же Ñ\81еÑ\81Ñ\81иÑ\8e базÑ\8b даннÑ\8bÑ\85, вÑ\8b Ñ\81оздадиÑ\82е новÑ\83Ñ\8e Ñ\81еÑ\81Ñ\81иÑ\8e базÑ\8b даннÑ\8bÑ\85 внÑ\83Ñ\82Ñ\80и Ñ\84оновой задаÑ\87и и бÑ\83деÑ\82е полÑ\83Ñ\87аÑ\82Ñ\8c обÑ\8aекÑ\82Ñ\8b из базÑ\8b даннÑ\8bÑ\85 Ñ\81 помоÑ\89Ñ\8cÑ\8e Ñ\8dÑ\82ой новой Ñ\81еÑ\81Ñ\81ии. Ð\90 заÑ\82ем, вмеÑ\81Ñ\82о Ñ\82ого Ñ\87Ñ\82обÑ\8b пеÑ\80едаваÑ\82Ñ\8c обÑ\8aекÑ\82 из базÑ\8b даннÑ\8bÑ\85 в каÑ\87еÑ\81Ñ\82ве паÑ\80амеÑ\82Ñ\80а в Ñ\84Ñ\83нкÑ\86иÑ\8e Ñ\84оновой задаÑ\87и, вÑ\8b пеÑ\80едадиÑ\82е иденÑ\82иÑ\84икаÑ\82оÑ\80 Ñ\8dÑ\82ого обÑ\8aекÑ\82а, а заÑ\82ем Ñ\81нова полÑ\83Ñ\87иÑ\82е обÑ\8aекÑ\82 в Ñ\84Ñ\83нкÑ\86ии Ñ\84оновой задаÑ\87и.
+Ð\97авиÑ\81имоÑ\81Ñ\82и Ñ\81 `yield` Ñ\81о вÑ\80еменем Ñ\8dволÑ\8eÑ\86иониÑ\80овали, Ñ\87Ñ\82обÑ\8b покÑ\80Ñ\8bÑ\82Ñ\8c Ñ\80азнÑ\8bе Ñ\81Ñ\86енаÑ\80ии и иÑ\81пÑ\80авиÑ\82Ñ\8c некоÑ\82оÑ\80Ñ\8bе пÑ\80облемÑ\8b.
-## Контекстные менеджеры
+Если вы хотите посмотреть, что менялось в разных версиях FastAPI, вы можете прочитать об этом подробнее в продвинутом руководстве: [Продвинутые зависимости — зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}.
+## Контекстные менеджеры { #context-managers }
-### Что такое "контекстные менеджеры"
+### Что такое «контекстные менеджеры» { #what-are-context-managers }
-"Контекстные менеджеры" - это любые объекты Python, которые можно использовать в операторе `with`.
+«Контекстные менеджеры» — это любые объекты Python, которые можно использовать в операторе `with`.
Например, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank">можно использовать `with` для чтения файла</a>:
print(contents)
```
-Под капотом" open("./somefile.txt") создаёт объект называемый "контекстным менеджером".
+Под капотом вызов `open("./somefile.txt")` создаёт объект, называемый «контекстным менеджером».
Когда блок `with` завершается, он обязательно закрывает файл, даже если были исключения.
-Когда вы создаете зависимость с помощью `yield`, **FastAPI** внутренне преобразует ее в контекстный менеджер и объединяет с некоторыми другими связанными инструментами.
+Когда вы создаёте зависимость с `yield`, **FastAPI** внутренне создаёт для неё менеджер контекста и сочетает его с некоторыми другими связанными инструментами.
-### Использование менеджеров контекста в зависимостях с помощью `yield`
+### Использование менеджеров контекста в зависимостях с `yield` { #using-context-managers-in-dependencies-with-yield }
/// warning | Внимание
-Это более или менее "продвинутая" идея.
+Это, более или менее, «продвинутая» идея.
Если вы только начинаете работать с **FastAPI**, то лучше пока пропустить этот пункт.
///
-Ð\92 Python длÑ\8f Ñ\81озданиÑ\8f менеджеÑ\80ов конÑ\82екÑ\81Ñ\82а можно <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">Ñ\81оздаÑ\82Ñ\8c класс с двумя методами: `__enter__()` и `__exit__()`</a>.
+Ð\92 Python можно Ñ\81оздаваÑ\82Ñ\8c менеджеÑ\80Ñ\8b конÑ\82екÑ\81Ñ\82а, <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">Ñ\81оздав класс с двумя методами: `__enter__()` и `__exit__()`</a>.
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c иÑ\85 внÑ\83Ñ\82Ñ\80и завиÑ\81имоÑ\81Ñ\82ей **FastAPI** Ñ\81 `yield`, иÑ\81полÑ\8cзÑ\83я операторы
+Ð\98Ñ\85 Ñ\82акже можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c внÑ\83Ñ\82Ñ\80и завиÑ\81имоÑ\81Ñ\82ей **FastAPI** Ñ\81 `yield`, пÑ\80именÑ\8fя операторы
`with` или `async with` внутри функции зависимости:
{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *}
/// tip | Подсказка
-Ð\94Ñ\80Ñ\83гой Ñ\81поÑ\81об Ñ\81озданиÑ\8f конÑ\82екÑ\81Ñ\82ного менеджеÑ\80а - с помощью:
+Ð\94Ñ\80Ñ\83гой Ñ\81поÑ\81об Ñ\81озданиÑ\8f менеджеÑ\80а конÑ\82екÑ\81Ñ\82а â\80\94 с помощью:
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> или
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
-иÑ\81полÑ\8cзÑ\83йÑ\82е иÑ\85 длÑ\8f оÑ\84оÑ\80млениÑ\8f Ñ\84Ñ\83нкÑ\86ии с одним `yield`.
+оÑ\84оÑ\80мив ими Ñ\84Ñ\83нкÑ\86иÑ\8e с одним `yield`.
-ÐÑ\82о Ñ\82о, Ñ\87Ñ\82о **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 внÑ\83Ñ\82Ñ\80и Ñ\81ебÑ\8f для зависимостей с `yield`.
+Ð\98менно Ñ\8dÑ\82о **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 внÑ\83Ñ\82Ñ\80енне для зависимостей с `yield`.
-Но использовать декораторы для зависимостей FastAPI не обязательно (да и не стоит).
+Но использовать эти декораторы для зависимостей FastAPI не обязательно (и не стоит).
FastAPI сделает это за вас на внутреннем уровне.
-# Глобальные зависимости
+# Глобальные зависимости { #global-dependencies }
Для некоторых типов приложений может потребоваться добавить зависимости ко всему приложению.
-Подобно тому, как вы можете [добавлять зависимости через параметр `dependencies` в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению.
+Подобно тому, как вы можете [добавлять `dependencies` (зависимости) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению.
В этом случае они будут применяться ко всем *операциям пути* в приложении:
{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *}
-Все способы [добавления зависимостей в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
+Все способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
-## Зависимости для групп *операций пути*
+## Зависимости для групп *операций пути* { #dependencies-for-groups-of-path-operations }
-Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр dependencies для целой группы *операций пути*.
+Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*.
-# Зависимости
+# Зависимости { #dependencies }
-**FastAPI** имеет очень мощную и интуитивную систему **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>**.
+**FastAPI** имеет очень мощную, но интуитивную систему **<abbr title="также известно как: компоненты, ресурсы, провайдеры, сервисы, внедряемые зависимости">Инъекция зависимостей</abbr>**.
-Она проектировалась таким образом, чтобы быть простой в использовании и облегчить любому разработчику интеграцию других компонентов с **FastAPI**.
+Она спроектирована так, чтобы быть очень простой в использовании и облегчать любому разработчику интеграцию других компонентов с **FastAPI**.
-## Что такое "Dependency Injection" (инъекция зависимости)
+## Что такое инъекция зависимостей («Dependency Injection») { #what-is-dependency-injection }
-**"Dependency Injection"** в программировании означает, что у вашего кода (в данном случае, вашей *функции обработки пути*) есть способы объявить вещи, которые запрашиваются для работы и использования: "зависимости".
+В программировании **«Dependency Injection»** означает, что у вашего кода (в данном случае у ваших *функций обработки пути*) есть способ объявить вещи, которые требуются для его работы и использования: «зависимости».
-Ð\98 поÑ\82ом Ñ\8dÑ\82а Ñ\81иÑ\81Ñ\82ема (в наÑ\88ем Ñ\81лÑ\83Ñ\87ае **FastAPI**) оÑ\80ганизÑ\83еÑ\82 вÑ\81Ñ\91, Ñ\87Ñ\82о Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f, Ñ\87Ñ\82обÑ\8b обеÑ\81пеÑ\87иÑ\82Ñ\8c ваÑ\88 код Ñ\8dÑ\82ой завиÑ\81имоÑ\81Ñ\82Ñ\8cÑ\8e (Ñ\81делаÑ\82Ñ\8c "инÑ\8aекÑ\86иÑ\8e" завиÑ\81имоÑ\81Ñ\82и).
+Ð\98 заÑ\82ем Ñ\8dÑ\82а Ñ\81иÑ\81Ñ\82ема (в наÑ\88ем Ñ\81лÑ\83Ñ\87ае **FastAPI**) позабоÑ\82иÑ\82Ñ\81Ñ\8f о Ñ\82ом, Ñ\87Ñ\82обÑ\8b Ñ\81делаÑ\82Ñ\8c вÑ\81Ñ\91 необÑ\85одимое длÑ\8f пÑ\80едоÑ\81Ñ\82авлениÑ\8f ваÑ\88емÑ\83 кодÑ\83 Ñ\8dÑ\82иÑ\85 завиÑ\81имоÑ\81Ñ\82ей (Ñ\81делаÑ\82Ñ\8c «инÑ\8aекÑ\86иÑ\8e» завиÑ\81имоÑ\81Ñ\82ей).
Это очень полезно, когда вам нужно:
* Обеспечить общую логику (один и тот же алгоритм снова и снова).
-* Ð\9eбÑ\89ее Ñ\81оединение с базой данных.
-* Ð\9eбеÑ\81пеÑ\87ение безопаÑ\81ноÑ\81Ñ\82и, аÑ\83Ñ\82енÑ\82иÑ\84икаÑ\86ии, запÑ\80оÑ\81а Ñ\80оли и Ñ\82.п.
-* И многое другое.
+* РазделÑ\8fÑ\82Ñ\8c Ñ\81оединениÑ\8f с базой данных.
+* Ð\9eбеÑ\81пеÑ\87иÑ\82Ñ\8c безопаÑ\81ноÑ\81Ñ\82Ñ\8c, аÑ\83Ñ\82енÑ\82иÑ\84икаÑ\86иÑ\8e, Ñ\82Ñ\80ебованиÑ\8f к Ñ\80олÑ\8fм и Ñ\82. п.
+* И многое другое...
-Ð\92Ñ\81Ñ\91 Ñ\8dÑ\82о минимизиÑ\80Ñ\83еÑ\82 повÑ\82оÑ\80ение кода.
+Ð\92Ñ\81Ñ\91 Ñ\8dÑ\82о пÑ\80и минимизаÑ\86ии повÑ\82оÑ\80ениÑ\8f кода.
-## Первые шаги
+## Первые шаги { #first-steps }
-Ð\94авайÑ\82е Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82ой пÑ\80имеÑ\80. Ð\9eн наÑ\81Ñ\82олÑ\8cко пÑ\80оÑ\81Ñ\82ой, Ñ\87Ñ\82о на даннÑ\8bй моменÑ\82 поÑ\87Ñ\82и беÑ\81полезнÑ\8bй.
+Ð\94авайÑ\82е Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82ой пÑ\80имеÑ\80. Ð\9eн наÑ\81Ñ\82олÑ\8cко пÑ\80оÑ\81Ñ\82ой, Ñ\87Ñ\82о пока не оÑ\87енÑ\8c полезен.
-Но таким способом мы можем сфокусироваться на том, как же всё таки работает система **Dependency Injection**.
+Но так мы сможем сосредоточиться на том, как работает система **Dependency Injection**.
-### Создание зависимости или "зависимого"
-Давайте для начала сфокусируемся на зависимостях.
+### Создайте зависимость, или «dependable» (от чего что-то зависит) { #create-a-dependency-or-dependable }
+
+Сначала сосредоточимся на зависимости.
+
+Это просто функция, которая может принимать те же параметры, что и *функция обработки пути*:
-Это просто функция, которая может принимать все те же параметры, что и *функции обработки пути*:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
-**И всё.**
+И всё.
**2 строки.**
-И теперь она той же формы и структуры, что и все ваши *функции обработки пути*.
+И она имеет ту же форму и структуру, что и все ваши *функции обработки пути*.
-Ð\92Ñ\8b можеÑ\82е дÑ\83маÑ\82Ñ\8c об *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и* как о Ñ\84Ñ\83нкÑ\86ии без "декоÑ\80аÑ\82оÑ\80а" (без `@app.get("/some-path")`).
+Ð\9cожно дÑ\83маÑ\82Ñ\8c о ней как о *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и* без «декоÑ\80аÑ\82оÑ\80а» (без `@app.get("/some-path")`).
-И она может возвращать всё, что требуется.
+И она может возвращать что угодно.
-В этом случае, эта зависимость ожидает:
+В этом случае эта зависимость ожидает:
-* Ð\9dеобÑ\8fзаÑ\82елÑ\8cнÑ\8bй query-паÑ\80амеÑ\82Ñ\80 `q` Ñ\81 Ñ\82ипом `str`
-* Ð\9dеобÑ\8fзаÑ\82елÑ\8cнÑ\8bй query-паÑ\80амеÑ\82Ñ\80 `skip` Ñ\81 Ñ\82ипом `int`, и знаÑ\87ением по Ñ\83молÑ\87аниÑ\8e `0`
-* Ð\9dеобÑ\8fзаÑ\82елÑ\8cнÑ\8bй query-паÑ\80амеÑ\82Ñ\80 `limit` Ñ\81 Ñ\82ипом `int`, и знаÑ\87ением по Ñ\83молÑ\87аниÑ\8e `100`
+* Ð\9dеобÑ\8fзаÑ\82елÑ\8cнÑ\8bй query-паÑ\80амеÑ\82Ñ\80 `q` Ñ\82ипа `str`.
+* Ð\9dеобÑ\8fзаÑ\82елÑ\8cнÑ\8bй query-паÑ\80амеÑ\82Ñ\80 `skip` Ñ\82ипа `int`, по Ñ\83молÑ\87аниÑ\8e `0`.
+* Ð\9dеобÑ\8fзаÑ\82елÑ\8cнÑ\8bй query-паÑ\80амеÑ\82Ñ\80 `limit` Ñ\82ипа `int`, по Ñ\83молÑ\87аниÑ\8e `100`.
-Ð\98 в конÑ\86е она возвращает `dict`, содержащий эти значения.
+Ð\90 заÑ\82ем пÑ\80оÑ\81Ñ\82о возвращает `dict`, содержащий эти значения.
/// info | Информация
-**FastAPI** добавил поддержку для `Annotated` (и начал её рекомендовать) в версии 0.95.0.
+FastAPI добавил поддержку `Annotated` (и начал рекомендовать его использование) в версии 0.95.0.
- Если у вас более старая версия, будут ошибки при попытке использовать `Annotated`.
+Если у вас более старая версия, вы получите ошибки при попытке использовать `Annotated`.
-УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b [Ð\9eбновили FastAPI веÑ\80Ñ\81иÑ\8e](../../deployment/versions.md#fastapi_2){.internal-link target=_blank} до, как минимÑ\83м 0.95.1, пеÑ\80ед Ñ\82ем как использовать `Annotated`.
+УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b [обновили веÑ\80Ñ\81иÑ\8e FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} как минимÑ\83м до 0.95.1, пÑ\80ежде Ñ\87ем использовать `Annotated`.
///
-### Import `Depends`
+### Импорт `Depends` { #import-depends }
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
-### Объявите зависимость в "зависимом"
+### Объявите зависимость в «зависимом» { #declare-the-dependency-in-the-dependant }
-Точно так же, как вы использовали `Body`, `Query` и т.д. с вашей *функцией обработки пути* для параметров, используйте `Depends` с новым параметром:
+Точно так же, как вы используете `Body`, `Query` и т. д. с параметрами вашей *функции обработки пути*, используйте `Depends` с новым параметром:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
-`Depends` работает немного иначе. Вы передаёте в `Depends` одиночный параметр, который будет похож на функцию.
+Хотя вы используете `Depends` в параметрах вашей функции так же, как `Body`, `Query` и т. д., `Depends` работает немного иначе.
+
+В `Depends` вы передаёте только один параметр.
+
+Этот параметр должен быть чем-то вроде функции.
-Вы **не вызываете его** на месте (не добавляете скобочки в конце: 👎 *your_best_func()*👎), просто передаёте как параметр в `Depends()`.
+Вы **не вызываете её** напрямую (не добавляйте круглые скобки в конце), просто передаёте её как параметр в `Depends()`.
-И потом функция берёт параметры так же, как *функция обработки пути*.
+И эта функция принимает параметры так же, как *функции обработки пути*.
/// tip | Подсказка
-Ð\92 Ñ\81ледÑ\83Ñ\8eÑ\89ей главе вÑ\8b Ñ\83видиÑ\82е, какие дÑ\80Ñ\83гие веÑ\89и, помимо функций, можно использовать в качестве зависимостей.
+Ð\92 Ñ\81ледÑ\83Ñ\8eÑ\89ей главе вÑ\8b Ñ\83видиÑ\82е, какие еÑ\89Ñ\91 «веÑ\89и», помимо функций, можно использовать в качестве зависимостей.
///
-Ð\9aаждÑ\8bй Ñ\80аз, когда новÑ\8bй запÑ\80оÑ\81 пÑ\80иÑ\85одиÑ\82, **FastAPI** позаботится о:
+Ð\9aаждÑ\8bй Ñ\80аз, когда пÑ\80иÑ\85одиÑ\82 новÑ\8bй запÑ\80оÑ\81, **FastAPI** позаботится о:
-* Вызове вашей зависимости ("зависимого") функции с корректными параметрами.
+* Вызове вашей зависимости («dependable») с корректными параметрами.
* Получении результата из вашей функции.
-* Ð\9dазнаÑ\87ении Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82а в паÑ\80амеÑ\82Ñ\80 в вашей *функции обработки пути*.
+* Ð\9fÑ\80иÑ\81ваивании Ñ\8dÑ\82ого Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82а паÑ\80амеÑ\82Ñ\80Ñ\83 в вашей *функции обработки пути*.
```mermaid
graph TB
common_parameters --> read_users
```
-Таким обÑ\80азом, вÑ\8b пиÑ\88еÑ\82е обÑ\89ий код один Ñ\80аз, и **FastAPI** позабоÑ\82иÑ\82Ñ\81Ñ\8f о его вÑ\8bзове длÑ\8f ваÑ\88иÑ\85 *опеÑ\80аÑ\86ий Ñ\81 пÑ\83Ñ\82Ñ\8fми*.
+Таким обÑ\80азом, вÑ\8b пиÑ\88еÑ\82е обÑ\89ий код один Ñ\80аз, а **FastAPI** позабоÑ\82иÑ\82Ñ\81Ñ\8f о его вÑ\8bзове длÑ\8f ваÑ\88иÑ\85 *опеÑ\80аÑ\86ий пÑ\83Ñ\82и*.
/// check | Проверка
-Обратите внимание, что вы не создаёте специальный класс и не передаёте его куда-то в **FastAPI** для регистрации, или что-то в этом роде.
+Обратите внимание, что вам не нужно создавать специальный класс и передавать его куда-то в **FastAPI**, чтобы «зарегистрировать» его или что-то подобное.
-Вы просто передаёте это в `Depends`, и **FastAPI** знает, что делать дальше.
+Вы просто передаёте его в `Depends`, и **FastAPI** знает, что делать дальше.
///
-## Ð\9eбÑ\8aединÑ\8fем Ñ\81 `Annotated` завиÑ\81имоÑ\81Ñ\82Ñ\8fми
+## Ð\98Ñ\81полÑ\8cзование завиÑ\81имоÑ\81Ñ\82и Ñ\81 `Annotated` в неÑ\81колÑ\8cкиÑ\85 меÑ\81Ñ\82аÑ\85 { #share-annotated-dependencies }
-В приведенном выше примере есть небольшое **повторение кода**.
+В приведённых выше примерах есть небольшое **повторение кода**.
-Когда вам нужно использовать `common_parameters()` зависимость, вы должны написать весь параметр с аннотацией типов и `Depends()`:
+Когда вам нужно использовать зависимость `common_parameters()`, вы должны написать весь параметр с аннотацией типа и `Depends()`:
```Python
commons: Annotated[dict, Depends(common_parameters)]
```
-Ð\9dо поÑ\82омÑ\83 Ñ\87Ñ\82о мÑ\8b иÑ\81полÑ\8cзÑ\83ем `Annotated`, мÑ\8b можем Ñ\85Ñ\80аниÑ\82Ñ\8c `Annotated` знаÑ\87ение в пеÑ\80еменной и использовать его в нескольких местах:
+Ð\9dо поÑ\81колÑ\8cкÑ\83 мÑ\8b иÑ\81полÑ\8cзÑ\83ем `Annotated`, мÑ\8b можем Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c Ñ\8dÑ\82о знаÑ\87ение `Annotated` в пеÑ\80еменнÑ\83Ñ\8e и использовать его в нескольких местах:
{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
/// tip | Подсказка
-Это стандартный синтаксис python и называется "type alias", это не особенность **FastAPI**.
+Это стандартный Python, это называется «type alias», и это не особенность **FastAPI**.
-Ð\9dо поÑ\82омÑ\83 Ñ\87Ñ\82о **FastAPI** базиÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f на Ñ\81Ñ\82андаÑ\80Ñ\82аÑ\85 Python, вклÑ\8eÑ\87аÑ\8f `Annotated`, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\82Ñ\80Ñ\8eк в ваÑ\88ем коде. 😎
+Ð\9dо поÑ\81колÑ\8cкÑ\83 **FastAPI** оÑ\81нован на Ñ\81Ñ\82андаÑ\80Ñ\82аÑ\85 Python, вклÑ\8eÑ\87аÑ\8f `Annotated`, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\82Ñ\80Ñ\8eк в Ñ\81воÑ\91м коде. 😎
///
-Зависимости продолжат работу как ожидалось, и **лучшая часть** в том, что **информация о типе будет сохранена**. Это означает, что ваш редактор кода будет корректно обрабатывать **автодополнения**, **встроенные ошибки** и так далее. То же самое относится и к инструментам, таким как `mypy`.
+Зависимости продолжат работать как ожидалось, и **лучшая часть** в том, что **информация о типах будет сохранена**, а значит, ваш редактор кода продолжит предоставлять **автозавершение**, **встроенные ошибки** и т.д. То же относится и к другим инструментам, таким как `mypy`.
-ÐÑ\82о оÑ\87енÑ\8c полезно, когда вÑ\8b инÑ\82егÑ\80иÑ\80Ñ\83еÑ\82е Ñ\8dÑ\82о в **болÑ\8cÑ\88Ñ\83Ñ\8e кодовÑ\83Ñ\8e базÑ\83**, иÑ\81полÑ\8cзÑ\83Ñ\8f **одинаковÑ\8bе завиÑ\81имоÑ\81Ñ\82и** Ñ\81нова и Ñ\81нова во **многиÑ\85** ***операциях пути***.
+ÐÑ\82о оÑ\81обенно полезно, когда вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Ñ\8dÑ\82о в **болÑ\8cÑ\88ой кодовой базе**, где вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е **одни и Ñ\82е же завиÑ\81имоÑ\81Ñ\82и** Ñ\81нова и Ñ\81нова во **многиÑ\85 *операциях пути***.
-## Использовать `async` или не `async`
+## Использовать `async` или не `async` { #to-async-or-not-to-async }
-Ð\94лÑ\8f завиÑ\81имоÑ\81Ñ\82ей, вÑ\8bзваннÑ\8bÑ\85 **FastAPI** (Ñ\82о же Ñ\81амое, Ñ\87Ñ\82о и ваÑ\88и *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и*), Ñ\82е же пÑ\80авила, Ñ\87Ñ\82о пÑ\80инÑ\8fÑ\82Ñ\8b длÑ\8f опÑ\80еделениÑ\8f ваших функций.
+Ð\9fоÑ\81колÑ\8cкÑ\83 завиÑ\81имоÑ\81Ñ\82и Ñ\82акже вÑ\8bзÑ\8bваÑ\8eÑ\82Ñ\81Ñ\8f **FastAPI** (как и ваÑ\88и *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и*), пÑ\80именÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f Ñ\82е же пÑ\80авила пÑ\80и опÑ\80еделении ваших функций.
Вы можете использовать `async def` или обычное `def`.
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82и Ñ\81 `async def` внÑ\83Ñ\82Ñ\80и обÑ\8bÑ\87ной `def` *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и*, или `def` завиÑ\81имоÑ\81Ñ\82и внÑ\83Ñ\82Ñ\80и `async def` *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и*, и Ñ\82ак далее.
+Ð\98 вÑ\8b можеÑ\82е обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82и Ñ\81 `async def` внÑ\83Ñ\82Ñ\80и обÑ\8bÑ\87нÑ\8bÑ\85 *Ñ\84Ñ\83нкÑ\86ий обÑ\80абоÑ\82ки пÑ\83Ñ\82и* `def`, или завиÑ\81имоÑ\81Ñ\82и `def` внÑ\83Ñ\82Ñ\80и *Ñ\84Ñ\83нкÑ\86ий обÑ\80абоÑ\82ки пÑ\83Ñ\82и* `async def` и Ñ\82. д.
-ÐÑ\82о вÑ\81Ñ\91 не важно. **FastAPI** знаеÑ\82, Ñ\87Ñ\82о нÑ\83жно Ñ\81делаÑ\82Ñ\8c. ð\9f\98\8e
+ÐÑ\82о не важно. **FastAPI** знаеÑ\82, Ñ\87Ñ\82о делаÑ\82Ñ\8c.
-/// note | Ð\98нÑ\84оÑ\80маÑ\86иÑ\8f
+/// note | Ð\9fÑ\80имеÑ\87ание
-Если вам эта тема не знакома, прочтите [Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank} раздел о `async` и `await` в документации.
+Если вы не уверены, посмотрите раздел [Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank} о `async` и `await` в документации.
///
-## Интеграция с OpenAPI
+## Интеграция с OpenAPI { #integrated-with-openapi }
-Ð\92Ñ\81е заÑ\8fвлениÑ\8f о запÑ\80оÑ\81аÑ\85, валидаÑ\82оÑ\80Ñ\8b, Ñ\82Ñ\80ебованиÑ\8f ваÑ\88иÑ\85 завиÑ\81имоÑ\81Ñ\82ей (и подзавиÑ\81имоÑ\81Ñ\82ей) бÑ\83дÑ\83Ñ\82 инÑ\82егÑ\80иÑ\80ованÑ\8b в Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89Ñ\83Ñ\8e OpenAPI-Ñ\81Ñ\85емÑ\83.
+Ð\92Ñ\81е обÑ\8aÑ\8fвлениÑ\8f запÑ\80оÑ\81ов, пÑ\80овеÑ\80ки и Ñ\82Ñ\80ебованиÑ\8f ваÑ\88иÑ\85 завиÑ\81имоÑ\81Ñ\82ей (и подзавиÑ\81имоÑ\81Ñ\82ей) бÑ\83дÑ\83Ñ\82 инÑ\82егÑ\80иÑ\80ованÑ\8b в Ñ\82Ñ\83 же Ñ\81Ñ\85емÑ\83 OpenAPI.
-Ð\92 инÑ\82еÑ\80акÑ\82ивной докÑ\83менÑ\82аÑ\86ии бÑ\83деÑ\82 вÑ\81Ñ\8f инÑ\84оÑ\80маÑ\86иÑ\8f по Ñ\8dÑ\82им завиÑ\81имоÑ\81Ñ\82Ñ\8fм Ñ\82оже:
+Ð\9fоÑ\8dÑ\82омÑ\83 в инÑ\82еÑ\80акÑ\82ивной докÑ\83менÑ\82аÑ\86ии бÑ\83деÑ\82 вÑ\81Ñ\8f инÑ\84оÑ\80маÑ\86иÑ\8f и из Ñ\8dÑ\82иÑ\85 завиÑ\81имоÑ\81Ñ\82ей:
<img src="/img/tutorial/dependencies/image01.png">
-## Простое использование
+## Простое использование { #simple-usage }
-Ð\95Ñ\81ли вÑ\8b поÑ\81моÑ\82Ñ\80иÑ\82е на Ñ\84оÑ\82о, *Ñ\84Ñ\83нкÑ\86иÑ\8f обÑ\80абоÑ\82ки пÑ\83Ñ\82и* обÑ\8aÑ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f каждÑ\8bй Ñ\80аз, когда вÑ\8bÑ\87иÑ\81лÑ\8fеÑ\82Ñ\81Ñ\8f пÑ\83Ñ\82Ñ\8c, и Ñ\82огда **FastAPI** позабоÑ\82иÑ\82Ñ\81Ñ\8f о вÑ\8bзове Ñ\84Ñ\83нкÑ\86ии Ñ\81 коÑ\80Ñ\80екÑ\82нÑ\8bми паÑ\80амеÑ\82Ñ\80ами, извлекаÑ\8f инÑ\84оÑ\80маÑ\86иÑ\8e из запроса.
+Ð\95Ñ\81ли поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c, *Ñ\84Ñ\83нкÑ\86ии обÑ\80абоÑ\82ки пÑ\83Ñ\82и* обÑ\8aÑ\8fвлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f длÑ\8f иÑ\81полÑ\8cзованиÑ\8f вÑ\81Ñ\8fкий Ñ\80аз, когда *пÑ\83Ñ\82Ñ\8c* и *опеÑ\80аÑ\86иÑ\8f* Ñ\81овпадаÑ\8eÑ\82, и Ñ\82огда **FastAPI** забоÑ\82иÑ\82Ñ\81Ñ\8f о вÑ\8bзове Ñ\84Ñ\83нкÑ\86ии Ñ\81 коÑ\80Ñ\80екÑ\82нÑ\8bми паÑ\80амеÑ\82Ñ\80ами, извлекаÑ\8f даннÑ\8bе из запроса.
-На самом деле, все (или большинство) веб-фреймворков работают по схожему сценарию.
+На самом деле все (или большинство) веб-фреймворков работают таким же образом.
-Вы никогда не вызываете эти функции на месте. Их вызовет ваш фреймворк (в нашем случае, **FastAPI**).
+Вы никогда не вызываете эти функции напрямую. Их вызывает ваш фреймворк (в нашем случае **FastAPI**).
-С системой Dependency Injection, вы можете сообщить **FastAPI**, что ваша *функция обработки пути* "зависит" от чего-то ещё, что должно быть извлечено перед вашей *функцией обработки пути*, и **FastAPI** позаботится об извлечении и инъекции результата.
+С системой **Dependency Injection** вы также можете сообщить **FastAPI**, что ваша *функция обработки пути* «зависит» от чего-то, что должно быть выполнено перед вашей *функцией обработки пути*, и **FastAPI** позаботится о его выполнении и «инъекции» результатов.
-Ð\94Ñ\80Ñ\83гие Ñ\80аÑ\81пÑ\80оÑ\81Ñ\82Ñ\80анÑ\91ннÑ\8bе Ñ\82еÑ\80минÑ\8b длÑ\8f опиÑ\81аниÑ\8f Ñ\81Ñ\85ожей идеи "dependency injection" Ñ\8fвлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f:
+Ð\94Ñ\80Ñ\83гие Ñ\80аÑ\81пÑ\80оÑ\81Ñ\82Ñ\80анÑ\91ннÑ\8bе Ñ\82еÑ\80минÑ\8b длÑ\8f опиÑ\81аниÑ\8f Ñ\82ой же идеи «dependency injection»:
-- ресурсность
-- доставка
-- сервисность
-- инъекция
-- компонентность
+* ресурсы
+* провайдеры
+* сервисы
+* внедряемые зависимости
+* компоненты
-## **FastAPI** подключаемые модули
+## Плагины **FastAPI** { #fastapi-plug-ins }
-Ð\98нÑ\8aекÑ\86ии и модÑ\83ли могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c поÑ\81Ñ\82Ñ\80оенÑ\8b Ñ\81 иÑ\81полÑ\8cзованием Ñ\81иÑ\81Ñ\82емÑ\8b **Dependency Injection**. Ð\9dо на Ñ\81амом деле, **неÑ\82 необÑ\85одимоÑ\81Ñ\82и Ñ\81оздаваÑ\82Ñ\8c новÑ\8bе модÑ\83ли**, пÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83Ñ\8f завиÑ\81имоÑ\81Ñ\82и, можно обÑ\8aÑ\8fвиÑ\82Ñ\8c беÑ\81конеÑ\87ное колиÑ\87еÑ\81Ñ\82во инÑ\82егÑ\80аÑ\86ий и взаимодейÑ\81Ñ\82вий, коÑ\82оÑ\80Ñ\8bе доÑ\81Ñ\82Ñ\83пнÑ\8b ваÑ\88ей *Ñ\84Ñ\83нкÑ\86ии обработки пути*.
+Ð\98нÑ\82егÑ\80аÑ\86ии и «плагинÑ\8b» могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c поÑ\81Ñ\82Ñ\80оенÑ\8b Ñ\81 иÑ\81полÑ\8cзованием Ñ\81иÑ\81Ñ\82емÑ\8b **Dependency Injection**. Ð\9dо на Ñ\81амом деле **неÑ\82 необÑ\85одимоÑ\81Ñ\82и Ñ\81оздаваÑ\82Ñ\8c «плагинÑ\8b»**, Ñ\82ак как, иÑ\81полÑ\8cзÑ\83Ñ\8f завиÑ\81имоÑ\81Ñ\82и, можно обÑ\8aÑ\8fвиÑ\82Ñ\8c беÑ\81конеÑ\87ное колиÑ\87еÑ\81Ñ\82во инÑ\82егÑ\80аÑ\86ий и взаимодейÑ\81Ñ\82вий, коÑ\82оÑ\80Ñ\8bе Ñ\81Ñ\82ановÑ\8fÑ\82Ñ\81Ñ\8f доÑ\81Ñ\82Ñ\83пнÑ\8bми ваÑ\88им *Ñ\84Ñ\83нкÑ\86иÑ\8fм обработки пути*.
-Ð\98 завиÑ\81имоÑ\81Ñ\82и могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c Ñ\81озданÑ\8b оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82Ñ\8bм и инÑ\82Ñ\83иÑ\82ивнÑ\8bм Ñ\81поÑ\81обом, Ñ\87Ñ\82о позволÑ\8fеÑ\82 вам пÑ\80оÑ\81Ñ\82о импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c нÑ\83жнÑ\8bе пакеÑ\82Ñ\8b Python и инÑ\82егÑ\80иÑ\80оваÑ\82Ñ\8c иÑ\85 в API Ñ\84Ñ\83нкÑ\86ии за паÑ\80Ñ\83 Ñ\81Ñ\82Ñ\80ок.
+Ð\98 завиÑ\81имоÑ\81Ñ\82и можно Ñ\81оздаваÑ\82Ñ\8c оÑ\87енÑ\8c пÑ\80оÑ\81Ñ\82Ñ\8bм и инÑ\82Ñ\83иÑ\82ивнÑ\8bм Ñ\81поÑ\81обом, коÑ\82оÑ\80Ñ\8bй позволÑ\8fеÑ\82 пÑ\80оÑ\81Ñ\82о импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c нÑ\83жнÑ\8bе пакеÑ\82Ñ\8b Python и инÑ\82егÑ\80иÑ\80оваÑ\82Ñ\8c иÑ\85 Ñ\81 ваÑ\88ими API-Ñ\84Ñ\83нкÑ\86иÑ\8fми в паÑ\80Ñ\83 Ñ\81Ñ\82Ñ\80ок кода, *бÑ\83квалÑ\8cно*.
Вы увидите примеры этого в следующих главах о реляционных и NoSQL базах данных, безопасности и т.д.
-## Совместимость с **FastAPI**
+## Совместимость с **FastAPI** { #fastapi-compatibility }
-Простота Dependency Injection делает **FastAPI** совместимым с:
+Простота системы **Dependency Injection** делает **FastAPI** совместимым с:
-- всеми реляционными базами данных
-- NoSQL базами данных
-- внешними пакетами
-- внешними API
-- системами авторизации, аутентификации
-- системами мониторинга использования API
-- системами ввода данных ответов
-- и так далее.
+* всеми реляционными базами данных
+* NoSQL базами данных
+* внешними пакетами
+* внешними API
+* системами аутентификации и авторизации
+* системами мониторинга использования API
+* системами инъекции данных в ответы
+* и т.д.
-## Просто и сильно
+## Просто и мощно { #simple-and-powerful }
-Хотя иерархическая система Dependency Injection очень проста для описания и использования, она по-прежнему очень мощная.
+Хотя иерархическая система dependency injection очень проста для определения и использования, она по-прежнему очень мощная.
-Вы можете описывать зависимости в очередь, и они уже будут вызываться друг за другом.
+Вы можете определять зависимости, которые, в свою очередь, могут иметь собственные зависимости.
-Ð\9aогда иеÑ\80аÑ\80Ñ\85иÑ\87еÑ\81кое деÑ\80ево поÑ\81Ñ\82Ñ\80оено, Ñ\81иÑ\81Ñ\82ема **Dependency Injection** беÑ\80еÑ\82 на Ñ\81ебÑ\8f Ñ\80еÑ\88ение вÑ\81еÑ\85 завиÑ\81имоÑ\81Ñ\82ей длÑ\8f ваÑ\81 (и иÑ\85 подзавиÑ\81имоÑ\81Ñ\82ей) и обеÑ\81пеÑ\87иваеÑ\82 (инÑ\8aекÑ\82иÑ\80Ñ\83еÑ\82) Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82 на каждом шаге.
+Ð\92 иÑ\82оге Ñ\81Ñ\82Ñ\80оиÑ\82Ñ\81Ñ\8f иеÑ\80аÑ\80Ñ\85иÑ\87еÑ\81кое деÑ\80ево завиÑ\81имоÑ\81Ñ\82ей, и Ñ\81иÑ\81Ñ\82ема **Dependency Injection** беÑ\80Ñ\91Ñ\82 на Ñ\81ебÑ\8f Ñ\80еÑ\88ение вÑ\81еÑ\85 Ñ\8dÑ\82иÑ\85 завиÑ\81имоÑ\81Ñ\82ей (и иÑ\85 подзавиÑ\81имоÑ\81Ñ\82ей) и пÑ\80едоÑ\81Ñ\82авлÑ\8fеÑ\82 (инÑ\8aекÑ\82иÑ\80Ñ\83еÑ\82) Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82Ñ\8b на каждом шаге.
Например, у вас есть 4 API-эндпоинта (*операции пути*):
-- `/items/public/`
-- `/items/private/`
-- `/users/{user_id}/activate`
-- `/items/pro/`
+* `/items/public/`
+* `/items/private/`
+* `/users/{user_id}/activate`
+* `/items/pro/`
-Тогда вы можете требовать разные права для каждого из них, используя зависимости и подзависимости:
+тогда вы можете добавить разные требования к правам для каждого из них только с помощью зависимостей и подзависимостей:
```mermaid
graph TB
paying_user --> pro_items
```
-## Интегрировано с **OpenAPI**
+## Интегрировано с **OpenAPI** { #integrated-with-openapi_1 }
-Все эти зависимости, объявляя свои требования, также добавляют параметры, проверки и т.д. к вашим операциям *path*.
+Все эти зависимости, объявляя свои требования, также добавляют параметры, проверки и т.д. к вашим *операциям пути*.
-**FastAPI** позаботится о добавлении всего этого в схему открытого API, чтобы это отображалось в системах интерактивной документации.
+**FastAPI** позаботится о добавлении всего этого в схему OpenAPI, чтобы это отображалось в системах интерактивной документации.
-# Подзависимости
+# Подзависимости { #sub-dependencies }
Вы можете создавать зависимости, которые имеют **подзависимости**.
**FastAPI** сам займётся их управлением.
-## Провайдер зависимости
+## Первая зависимость { #first-dependency-dependable }
Можно создать первую зависимость следующим образом:
Это довольно просто (хотя и не очень полезно), но поможет нам сосредоточиться на том, как работают подзависимости.
-## Вторая зависимость
+## Вторая зависимость, «зависимость» и «зависимая» { #second-dependency-dependable-and-dependant }
-Ð\97аÑ\82ем можно Ñ\81оздаÑ\82Ñ\8c еÑ\89е однÑ\83 Ñ\84Ñ\83нкÑ\86иÑ\8e завиÑ\81имоÑ\81Ñ\82и, коÑ\82оÑ\80аÑ\8f в Ñ\82о же вÑ\80емÑ\8f Ñ\81одеÑ\80жиÑ\82 внÑ\83Ñ\82Ñ\80и Ñ\81ебÑ\8f пеÑ\80вÑ\83Ñ\8e завиÑ\81имоÑ\81Ñ\82Ñ\8c (Ñ\82аким обÑ\80азом, она Ñ\82оже Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f "завиÑ\81имой"):
+Ð\97аÑ\82ем можно Ñ\81оздаÑ\82Ñ\8c еÑ\89е однÑ\83 Ñ\84Ñ\83нкÑ\86иÑ\8e завиÑ\81имоÑ\81Ñ\82и, коÑ\82оÑ\80аÑ\8f одновÑ\80еменно обÑ\8aÑ\8fвлÑ\8fеÑ\82 Ñ\81воÑ\8e Ñ\81обÑ\81Ñ\82веннÑ\83Ñ\8e завиÑ\81имоÑ\81Ñ\82Ñ\8c (Ñ\82аким обÑ\80азом, она Ñ\82оже Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f «завиÑ\81имой»):
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
* Она также объявляет необязательный куки-параметр `last_query` в виде строки.
* Если пользователь не указал параметр `q` в запросе, то мы используем последний использованный запрос, который мы ранее сохранили в куки-параметре `last_query`.
-## Использование зависимости
+## Использование зависимости { #use-the-dependency }
Затем мы можем использовать зависимость вместе с:
query_extractor --> query_or_cookie_extractor --> read_query
```
-## Использование одной и той же зависимости несколько раз
+## Использование одной и той же зависимости несколько раз { #using-the-same-dependency-multiple-times }
Если одна из ваших зависимостей объявлена несколько раз для одной и той же *функции операции пути*, например, несколько зависимостей имеют общую подзависимость, **FastAPI** будет знать, что вызывать эту подзависимость нужно только один раз за запрос.
В расширенном сценарии, когда вы знаете, что вам нужно, чтобы зависимость вызывалась на каждом шаге (возможно, несколько раз) в одном и том же запросе, вместо использования "кэшированного" значения, вы можете установить параметр `use_cache=False` при использовании `Depends`:
-//// tab | Python 3.6+
+//// tab | Python 3.8+
```Python hl_lines="1"
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
////
-//// tab | Python 3.6+ без Annotated
+//// tab | Python 3.8+ без Annotated
/// tip | Подсказка
////
-## Резюме
+## Резюме { #recap }
Помимо всех этих умных слов, используемых здесь, система внедрения зависимостей довольно проста.
-# JSON кодировщик
+# JSON-совместимый кодировщик { #json-compatible-encoder }
В некоторых случаях может потребоваться преобразование типа данных (например, Pydantic-модели) в тип, совместимый с JSON (например, `dict`, `list` и т.д.).
Для этого **FastAPI** предоставляет функцию `jsonable_encoder()`.
-## Использование `jsonable_encoder`
+## Использование `jsonable_encoder` { #using-the-jsonable-encoder }
Представим, что у вас есть база данных `fake_db`, которая принимает только JSON-совместимые данные.
В таком случае объект `datetime` следует преобразовать в строку соответствующую <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">формату ISO</a>.
-Точно так же эта база данных не может принять Pydantic модель (объект с атрибутами), а только `dict`.
+Точно так же эта база данных не может принять Pydantic-модель (объект с атрибутами), а только `dict`.
Для этого можно использовать функцию `jsonable_encoder`.
-Она принимает объект, например, модель Pydantic, и возвращает его версию, совместимую с JSON:
+Она принимает объект, например, Pydantic-модель, и возвращает его версию, совместимую с JSON:
{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
-В данном примере она преобразует Pydantic модель в `dict`, а `datetime` - в `str`.
+В данном примере она преобразует Pydantic-модель в `dict`, а `datetime` - в `str`.
Результатом её вызова является объект, который может быть закодирован с помощью функции из стандартной библиотеки Python – <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.
Функция не возвращает большой `str`, содержащий данные в формате JSON (в виде строки). Она возвращает стандартную структуру данных Python (например, `dict`) со значениями и подзначениями, которые совместимы с JSON.
-/// note | ТеÑ\85ниÑ\87еÑ\81кие деÑ\82али
+/// note | Ð\9fÑ\80имеÑ\87ание
`jsonable_encoder` фактически используется **FastAPI** внутри системы для преобразования данных. Однако он полезен и во многих других сценариях.
-# Дополнительные типы данных
+# Дополнительные типы данных { #extra-data-types }
До сих пор вы использовали простые типы данных, такие как:
Но вы также можете использовать и более сложные типы.
-При этом у вас останутся те же возможности , что и до сих пор:
+При этом у вас останутся те же возможности, что и до сих пор:
-* Отличная поддержка редактора.
+* Отличная поддержка редактора кода.
* Преобразование данных из входящих запросов.
* Преобразование данных для ответа.
* Валидация данных.
* Автоматическая аннотация и документация.
-## Другие типы данных
+## Другие типы данных { #other-data-types }
Ниже перечислены некоторые из дополнительных типов данных, которые вы можете использовать:
* `datetime.timedelta`:
* Встроенный в Python `datetime.timedelta`.
* В запросах и ответах будет представлен в виде общего количества секунд типа `float`.
- * Pydantic также позволяет представить его как "Кодировку разницы во времени ISO 8601", <a href="https://docs.pydantic.dev/latest/concepts/serialization/#json_encoders" class="external-link" target="_blank">см. документацию для получения дополнительной информации</a>.
+ * Pydantic также позволяет представить его как "Кодировку разницы во времени ISO 8601", <a href="https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers" class="external-link" target="_blank">см. документацию для получения дополнительной информации</a>.
* `frozenset`:
* В запросах и ответах обрабатывается так же, как и `set`:
* В запросах будет прочитан список, исключены дубликаты и преобразован в `set`.
* `Decimal`:
* Встроенный в Python `Decimal`.
* В запросах и ответах обрабатывается так же, как и `float`.
-* Вы можете проверить все допустимые типы данных pydantic здесь: <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Типы данных Pydantic</a>.
+* Вы можете проверить все допустимые типы данных Pydantic здесь: <a href="https://docs.pydantic.dev/latest/usage/types/types/" class="external-link" target="_blank">Типы данных Pydantic</a>.
-## Пример
+## Пример { #example }
Вот пример *операции пути* с параметрами, который демонстрирует некоторые из вышеперечисленных типов.
-{* ../../docs_src/extra_data_types/tutorial001.py hl[1,3,12:16] *}
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
Обратите внимание, что параметры внутри функции имеют свой естественный тип данных, и вы, например, можете выполнять обычные манипуляции с датами, такие как:
-{* ../../docs_src/extra_data_types/tutorial001.py hl[18:19] *}
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
-# Дополнительные модели
+# Дополнительные модели { #extra-models }
В продолжение прошлого примера будет уже обычным делом иметь несколько связанных между собой моделей.
///
-## Множественные модели
+## Множественные модели { #multiple-models }
Ниже изложена основная идея того, как могут выглядеть эти модели с полями для паролей, а также описаны места, где они используются:
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
-### Про `**user_in.dict()`
+/// info | Информация
-#### `.dict()` из Pydantic
+В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
+
+В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, следует использовать `.model_dump()`.
+
+///
+
+### Про `**user_in.dict()` { #about-user-in-dict }
+
+#### `.dict()` из Pydantic { #pydantics-dict }
`user_in` - это Pydantic-модель класса `UserIn`.
}
```
-#### Распаковка `dict`
+#### Распаковка `dict` { #unpacking-a-dict }
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
)
```
-#### Pydantic-модель из содержимого другой модели
+#### Pydantic-модель из содержимого другой модели { #a-pydantic-model-from-the-contents-of-another }
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
-#### Распаковка `dict` и дополнительные именованные аргументы
+#### Распаковка `dict` и дополнительные именованные аргументы { #unpacking-a-dict-and-extra-keywords }
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
/// warning | Предупреждение
-ЦелÑ\8c иÑ\81полÑ\8cзованнÑ\8bÑ\85 в пÑ\80имеÑ\80е вÑ\81помогаÑ\82елÑ\8cнÑ\8bÑ\85 Ñ\84Ñ\83нкÑ\86ий - не более Ñ\87ем демонÑ\81Ñ\82Ñ\80аÑ\86иÑ\8f возможнÑ\8bÑ\85 опеÑ\80аÑ\86ий Ñ\81 даннÑ\8bми, но, конеÑ\87но, они не обеспечивают настоящую безопасность.
+Ð\92Ñ\81помогаÑ\82елÑ\8cнÑ\8bе Ñ\84Ñ\83нкÑ\86ии `fake_password_hasher` и `fake_save_user` иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82Ñ\81Ñ\8f Ñ\82олÑ\8cко длÑ\8f демонÑ\81Ñ\82Ñ\80аÑ\86ии возможного поÑ\82ока даннÑ\8bÑ\85 и, конеÑ\87но, не обеспечивают настоящую безопасность.
///
-## Сократите дублирование
+## Сократите дублирование { #reduce-duplication }
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
-## `Union` или `anyOf`
+## `Union` или `anyOf` { #union-or-anyof }
-Вы можете определить ответ как `Union` из двух типов. Это означает, что ответ должен соответствовать одному из них.
+Вы можете определить ответ как `Union` из двух или более типов. Это означает, что ответ должен соответствовать одному из них.
Он будет определён в OpenAPI как `anyOf`.
-Ð\94лÑ\8f Ñ\8dÑ\82ого иÑ\81полÑ\8cзÑ\83йÑ\82е Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе анноÑ\82аÑ\86ии типов в Python <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
+Ð\94лÑ\8f Ñ\8dÑ\82ого иÑ\81полÑ\8cзÑ\83йÑ\82е Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\83Ñ\8e анноÑ\82аÑ\86иÑ\8e типов в Python <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
/// note | Примечание
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
-### `Union` в Python 3.10
+### `Union` в Python 3.10 { #union-in-python-3-10 }
В этом примере мы передаём `Union[PlaneItem, CarItem]` в качестве значения аргумента `response_model`.
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
-## Список моделей
+## Список моделей { #list-of-models }
Таким же образом вы можете определять ответы как списки объектов.
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
-## Ответ с произвольным `dict`
+## Ответ с произвольным `dict` { #response-with-arbitrary-dict }
Вы также можете определить ответ, используя произвольный одноуровневый `dict` и определяя только типы ключей и значений без использования Pydantic-моделей.
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
-## Резюме
+## Резюме { #recap }
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
-# Первые шаги
+# Первые шаги { #first-steps }
-Самый простой FastAPI файл может выглядеть так:
+Самый простой файл FastAPI может выглядеть так:
{* ../../docs_src/first_steps/tutorial001.py *}
-Скопируйте в файл `main.py`.
+Скопируйте это в файл `main.py`.
Запустите сервер в режиме реального времени:
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-<span style="color: green;">INFO</span>: Started reloader process [28720]
-<span style="color: green;">INFO</span>: Started server process [28722]
-<span style="color: green;">INFO</span>: Waiting for application startup.
-<span style="color: green;">INFO</span>: Application startup complete.
-```
+ <span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
-</div>
+ Searching for package file structure from directories
+ with <font color="#3465A4">__init__.py</font> files
+ Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
-/// note | Технические детали
+ <span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
-Команда `uvicorn main:app` обращается к:
+ <span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
+ the following code:
-* `main`: файл `main.py` (модуль Python).
-* `app`: объект, созданный внутри файла `main.py` в строке `app = FastAPI()`.
-* `--reload`: перезапускает сервер после изменения кода. Используйте только для разработки.
+ <u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
-///
+ <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
+ <b>fastapi run</b>
+
+ Logs:
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
+ <b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
+ to quit<b>)</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
+```
+
+</div>
-Ð\92 окне вÑ\8bвода поÑ\8fвиÑ\82Ñ\81Ñ\8f Ñ\81ледÑ\83Ñ\8eÑ\89аÑ\8f Ñ\81Ñ\82Ñ\80ока:
+Ð\92 вÑ\8bводе бÑ\83деÑ\82 Ñ\81Ñ\82Ñ\80ока пÑ\80имеÑ\80но Ñ\82акого вида:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
-Эта строка показывает URL-адрес, по которому приложение доступно на локальной машине.
+Эта строка показывает URL, по которому ваше приложение доступно на локальной машине.
-### Проверьте
+### Проверьте { #check-it }
Откройте браузер по адресу: <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
-Вы увидите JSON-ответ следующего вида:
+Вы увидите JSON-ответ вида:
```JSON
{"message": "Hello World"}
```
-### Интерактивная документация API
+### Интерактивная документация API { #interactive-api-docs }
-Ð\9fерейдите по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+ТепеÑ\80Ñ\8c перейдите по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
-Вы увидите автоматически сгенерированную, интерактивную документацию по API (предоставленную <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
+Вы увидите автоматически сгенерированную интерактивную документацию по API (предоставлено <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):

-### Альтернативная документация API
+### Альтернативная документация API { #alternative-api-docs }
-Теперь перейдите по адресу <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
+Ð\98 Ñ\82еперь перейдите по адресу <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
-Ð\92Ñ\8b Ñ\83видиÑ\82е алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\83Ñ\8e авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\81генеÑ\80иÑ\80ованнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e (пÑ\80едоÑ\81Ñ\82авленнÑ\83Ñ\8e <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
+Ð\92Ñ\8b Ñ\83видиÑ\82е алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\83Ñ\8e авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\81генеÑ\80иÑ\80ованнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e (пÑ\80едоÑ\81Ñ\82авлено <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):

-### OpenAPI
+### OpenAPI { #openapi }
-**FastAPI** генерирует "схему" всего API, используя стандарт **OpenAPI**.
+**FastAPI** генерирует «схему» всего вашего API, используя стандарт **OpenAPI** для описания API.
-#### "Схема"
+#### «Схема» { #schema }
-"Схема" - это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание.
+«Схема» — это определение или описание чего-либо. Не код, который это реализует, а только абстрактное описание.
-#### API "схема"
+#### «Схема» API { #api-schema }
-<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> - это спецификация, которая определяет, как описывать схему API.
+В данном случае <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> — это спецификация, которая определяет, как описывать схему вашего API.
-Ð\9eпÑ\80еделение Ñ\81Ñ\85емÑ\8b Ñ\81одеÑ\80жиÑ\82 пÑ\83Ñ\82и (paths) API, иÑ\85 паÑ\80амеÑ\82Ñ\80Ñ\8b и Ñ\82.п.
+ÐÑ\82о опÑ\80еделение Ñ\81Ñ\85емÑ\8b вклÑ\8eÑ\87аеÑ\82 пÑ\83Ñ\82и ваÑ\88его API, возможнÑ\8bе паÑ\80амеÑ\82Ñ\80Ñ\8b, коÑ\82оÑ\80Ñ\8bе они пÑ\80инимаÑ\8eÑ\82, и Ñ\82. п.
-#### "Схема" данных
+#### «Схема» данных { #data-schema }
-Термин "схема" также может относиться к формату или структуре некоторых данных, например, JSON.
+Термин «схема» также может относиться к форме некоторых данных, например, к содержимому JSON.
-Тогда, подÑ\80азÑ\83меваÑ\8eÑ\82Ñ\81Ñ\8f аÑ\82Ñ\80ибÑ\83Ñ\82Ñ\8b JSON, иÑ\85 Ñ\82ипÑ\8b даннÑ\8bÑ\85 и Ñ\82.п.
+Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае Ñ\8dÑ\82о бÑ\83дÑ\83Ñ\82 аÑ\82Ñ\80ибÑ\83Ñ\82Ñ\8b JSON, иÑ\85 Ñ\82ипÑ\8b даннÑ\8bÑ\85 и Ñ\82. п.
-#### OpenAPI и JSON Schema
+#### OpenAPI и JSON Schema { #openapi-and-json-schema }
-OpenAPI описывает схему API. Эта схема содержит определения (или "схемы") данных, отправляемых и получаемых API. Для описания структуры данных в JSON используется стандарт **JSON Schema**.
+OpenAPI определяет схему API для вашего API. И эта схема включает определения (или «схемы») данных, отправляемых и получаемых вашим API, с использованием стандарта **JSON Schema** для схем данных JSON.
-#### РаÑ\81Ñ\81моÑ\82Ñ\80им `openapi.json`
+#### Ð\9fоÑ\81моÑ\82Ñ\80иÑ\82е `openapi.json` { #check-the-openapi-json }
-Ð\95Ñ\81ли Ð\92аÑ\81 инÑ\82еÑ\80еÑ\81Ñ\83еÑ\82, как вÑ\8bглÑ\8fдиÑ\82 иÑ\81Ñ\85однаÑ\8f Ñ\81Ñ\85ема OpenAPI, Ñ\82о FastAPI авÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80Ñ\83еÑ\82 JSON-Ñ\81Ñ\85емÑ\83 Ñ\81о вÑ\81еми опиÑ\81аниÑ\8fми API.
+Ð\95Ñ\81ли вам инÑ\82еÑ\80еÑ\81но, как вÑ\8bглÑ\8fдиÑ\82 иÑ\81Ñ\85однаÑ\8f Ñ\81Ñ\85ема OpenAPI, FastAPI авÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80Ñ\83еÑ\82 JSON (Ñ\81Ñ\85емÑ\83) Ñ\81 опиÑ\81анием вÑ\81его ваÑ\88его API.
-Ð\9cожеÑ\82е поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c здеÑ\81Ñ\8c: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
+Ð\92Ñ\8b можеÑ\82е поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c еÑ\91 напÑ\80Ñ\8fмÑ\83Ñ\8e по адÑ\80еÑ\81Ñ\83: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
-Вы увидите примерно такой JSON:
+Вы увидите JSON, начинающийся примерно так:
```JSON
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
...
```
-#### Для чего нужен OpenAPI
+#### Для чего нужен OpenAPI { #what-is-openapi-for }
-Схема OpenAPI является основой для обеих систем интерактивной документации.
+Схема OpenAPI является основой для обеих включённых систем интерактивной документации.
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83Ñ\8eÑ\82 деÑ\81Ñ\8fÑ\82ки алÑ\8cÑ\82еÑ\80наÑ\82ивнÑ\8bÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, оÑ\81нованнÑ\8bÑ\85 на OpenAPI. Ð\92Ñ\8b можеÑ\82е легко добавиÑ\82Ñ\8c лÑ\8eбой из ниÑ\85 к **FastAPI** пÑ\80иложениÑ\8e.
+Ð\95Ñ\81Ñ\82Ñ\8c деÑ\81Ñ\8fÑ\82ки алÑ\8cÑ\82еÑ\80наÑ\82ив, вÑ\81е оÑ\81нованÑ\8b на OpenAPI. Ð\92Ñ\8b можеÑ\82е легко добавиÑ\82Ñ\8c лÑ\8eбÑ\83Ñ\8e из ниÑ\85 в ваÑ\88е пÑ\80иложение, Ñ\81озданное Ñ\81 **FastAPI**.
-Вы также можете использовать OpenAPI для автоматической генерации кода для клиентов, которые взаимодействуют с API. Например, для фронтенд-, мобильных или IoT-приложений.
+Вы также можете использовать её для автоматической генерации кода для клиентов, которые взаимодействуют с вашим API. Например, для фронтенд-, мобильных или IoT-приложений.
-## Рассмотрим поэтапно
+## Рассмотрим поэтапно { #recap-step-by-step }
-### Шаг 1: импортируйте `FastAPI`
+### Шаг 1: импортируйте `FastAPI` { #step-1-import-fastapi }
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
-`FastAPI` это класс в Python, который предоставляет всю функциональность для API.
+`FastAPI` — это класс на Python, который предоставляет всю функциональность для вашего API.
/// note | Технические детали
-`FastAPI` это класс, который наследуется непосредственно от `Starlette`.
+`FastAPI` — это класс, который напрямую наследуется от `Starlette`.
-Вы можете использовать всю функциональность <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> в `FastAPI`.
+Вы можете использовать весь функционал <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> и в `FastAPI`.
///
-### Шаг 2: создайте экземпляр `FastAPI`
+### Шаг 2: создайте экземпляр `FastAPI` { #step-2-create-a-fastapi-instance }
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
-Переменная `app` является экземпляром класса `FastAPI`.
-
-Это единая точка входа для создания и взаимодействия с API.
-
-Именно к этой переменной `app` обращается `uvicorn` в команде:
-
-<div class="termy">
-
-```console
-$ uvicorn main:app --reload
-
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-</div>
-
-Если создать такое приложение:
-
-{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
-
-И поместить его в `main.py`, тогда вызов `uvicorn` будет таким:
+Здесь переменная `app` будет экземпляром класса `FastAPI`.
-<div class="termy">
-
-```console
-$ uvicorn main:my_awesome_api --reload
-
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-</div>
+Это будет основная точка взаимодействия для создания всего вашего API.
-### Шаг 3: определите *операцию пути (path operation)*
+### Шаг 3: создайте *операцию пути (path operation)* { #step-3-create-a-path-operation }
-#### Путь (path)
+#### Путь (path) { #path }
-"Путь" это часть URL, после первого символа `/`, следующего за именем домена.
+Здесь «путь» — это последняя часть URL, начиная с первого символа `/`.
-Ð\94лÑ\8f URL:
+Ð\98Ñ\82ак, в Ñ\82аком URL:
```
https://example.com/items/foo
```
-...пÑ\83Ñ\82Ñ\8c вÑ\8bглÑ\8fдиÑ\82 Ñ\82ак:
+...пÑ\83Ñ\82Ñ\8c бÑ\83деÑ\82:
```
/items/foo
```
-/// info | Ð\94ополниÑ\82елÑ\8cнаÑ\8f иформация
+/// info | Ð\98нформация
-Термин "path" также часто называется "endpoint" или "route".
+«Путь» также часто называют «эндпоинт» или «маршрут».
///
-При создании API, "путь" является основным способом разделения "задач" и "ресурсов".
+При создании API «путь» — это основной способ разделения «задач» и «ресурсов».
-#### Операция (operation)
+#### Операция (operation) { #operation }
-"Операция" это один из "методов" HTTP.
+«Операция» здесь — это один из HTTP-«методов».
-ТакиÑ\85, как:
+Ð\9eдин из:
* `POST`
* `GET`
* `PUT`
* `DELETE`
-...и более экзотических:
+...и более экзотические:
* `OPTIONS`
* `HEAD`
* `PATCH`
* `TRACE`
-Ð\9fо пÑ\80оÑ\82околÑ\83 HTTP можно обÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f к каждомÑ\83 пÑ\83Ñ\82и, иÑ\81полÑ\8cзÑ\83Ñ\8f один (или неÑ\81колÑ\8cко) из Ñ\8dÑ\82иÑ\85 "меÑ\82одов".
+Ð\92 пÑ\80оÑ\82околе HTTP можно обÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f к каждомÑ\83 пÑ\83Ñ\82и, иÑ\81полÑ\8cзÑ\83Ñ\8f один (или неÑ\81колÑ\8cко) из Ñ\8dÑ\82иÑ\85 «меÑ\82одов».
---
-Ð\9fÑ\80и Ñ\81оздании API пÑ\80инÑ\8fÑ\82о иÑ\81полÑ\8cзоваÑ\82Ñ\8c конкÑ\80еÑ\82нÑ\8bе HTTP-меÑ\82одÑ\8b длÑ\8f вÑ\8bполнениÑ\8f опÑ\80еделенных действий.
+Ð\9fÑ\80и Ñ\81оздании API обÑ\8bÑ\87но иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 конкÑ\80еÑ\82нÑ\8bе HTTP-меÑ\82одÑ\8b длÑ\8f вÑ\8bполнениÑ\8f конкÑ\80еÑ\82ных действий.
Обычно используют:
* `POST`: создать данные.
-* `GET`: прочитать.
-* `PUT`: измениÑ\82Ñ\8c (обновиÑ\82Ñ\8c).
-* `DELETE`: удалить.
+* `GET`: прочитать данные.
+* `PUT`: обновиÑ\82Ñ\8c даннÑ\8bе.
+* `DELETE`: удалить данные.
-Ð\92 OpenAPI каждÑ\8bй HTTP меÑ\82од назÑ\8bваеÑ\82Ñ\81Ñ\8f "**опеÑ\80аÑ\86иÑ\8f**".
+Таким обÑ\80азом, в OpenAPI каждÑ\8bй HTTP-меÑ\82од назÑ\8bваеÑ\82Ñ\81Ñ\8f «опеÑ\80аÑ\86ией».
-Ð\9cÑ\8b Ñ\82акже бÑ\83дем пÑ\80идеÑ\80живаÑ\82Ñ\8cÑ\81Ñ\8f Ñ\8dÑ\82ого Ñ\82еÑ\80мина.
+Ð\9cÑ\8b Ñ\82оже бÑ\83дем назÑ\8bваÑ\82Ñ\8c иÑ\85 «опеÑ\80аÑ\86иÑ\8fми».
-#### Определите *декоратор операции пути (path operation decorator)*
+#### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator }
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
-Декоратор `@app.get("/")` указывает **FastAPI**, что функция, прямо под ним, отвечает за обработку запросов, поступающих по адресу:
+`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих:
-* путь `/`
-* использующих <abbr title="HTTP GET метод"><code>get</code> операцию</abbr>
+* по пути `/`
+* с использованием <abbr title="метод HTTP GET"><code>get</code> операции</abbr>
-/// info | `@decorator` Дополнительная информация
+/// info | Информация о `@decorator`
-Синтаксис `@something` в Python называется "декоратор".
+Синтаксис `@something` в Python называется «декоратор».
-Ð\92Ñ\8b помеÑ\89аеÑ\82е его над Ñ\84Ñ\83нкÑ\86ией. Ð\9aак кÑ\80аÑ\81ивÑ\83Ñ\8e декоÑ\80аÑ\82ивнÑ\83Ñ\8e Ñ\88лÑ\8fпÑ\83 (дÑ\83маÑ\8e, Ñ\87Ñ\82о оÑ\82Ñ\82Ñ\83да и пÑ\80оиÑ\81Ñ\85одиÑ\82 Ñ\8dÑ\82оÑ\82 термин).
+Ð\95го Ñ\80азмеÑ\89аÑ\8eÑ\82 над Ñ\84Ñ\83нкÑ\86ией. Ð\9aак кÑ\80аÑ\81иваÑ\8f декоÑ\80аÑ\82ивнаÑ\8f Ñ\88лÑ\8fпа (кажеÑ\82Ñ\81Ñ\8f, оÑ\82Ñ\81Ñ\8eда и поÑ\88Ñ\91л термин).
-"Декоратор" принимает функцию ниже и выполняет с ней какое-то действие.
+«Декоратор» берёт функцию ниже и делает с ней что-то.
-В нашем случае, этот декоратор сообщает **FastAPI**, что функция ниже соответствует **пути** `/` и **операции** `get`.
+В нашем случае этот декоратор сообщает **FastAPI**, что функция ниже соответствует **пути** `/` с **операцией** `get`.
-Это и есть "**декоратор операции пути**".
+Это и есть «декоратор операции пути».
///
-Можно также использовать операции:
+Ð\9cожно Ñ\82акже иÑ\81полÑ\8cзоваÑ\82Ñ\8c дÑ\80Ñ\83гие опеÑ\80аÑ\86ии:
* `@app.post()`
* `@app.put()`
/// tip | Подсказка
-Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c каждÑ\83Ñ\8e опеÑ\80аÑ\86иÑ\8e (HTTP-меÑ\82од) по Ñ\81воемÑ\83 Ñ\83Ñ\81моÑ\82Ñ\80ениÑ\8e.
+Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c каждÑ\8bй меÑ\82од (HTTP-опеÑ\80аÑ\86иÑ\8e) Ñ\82ак, как Ñ\81Ñ\87иÑ\82аеÑ\82е нÑ\83жнÑ\8bм.
-**FastAPI** не навÑ\8fзÑ\8bваеÑ\82 опÑ\80еделенного знаÑ\87ениÑ\8f длÑ\8f каждого меÑ\82ода.
+**FastAPI** не навÑ\8fзÑ\8bваеÑ\82 какого-либо конкÑ\80еÑ\82ного Ñ\81мÑ\8bÑ\81ла.
-Ð\98нÑ\84оÑ\80маÑ\86иÑ\8f здеÑ\81Ñ\8c пÑ\80едÑ\81Ñ\82авлена как рекомендация, а не требование.
+ÐÑ\82а инÑ\84оÑ\80маÑ\86иÑ\8f дана как рекомендация, а не требование.
-Например, при использовании GraphQL обычно все действия выполняются только с помощью POST операций.
+Например, при использовании GraphQL обычно все действия выполняются только с помощью POST-операций.
///
-### Шаг 4: определите **функцию операции пути**
+### Шаг 4: определите **функцию операции пути** { #step-4-define-the-path-operation-function }
-Вот "**функция операции пути**":
+Вот наша «функция операции пути»:
* **путь**: `/`.
* **операция**: `get`.
-* **функция**: функция ниже "декоратора" (ниже `@app.get("/")`).
+* **функция**: функция ниже «декоратора» (ниже `@app.get("/")`).
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
-Это обычная Python функция.
+Это функция на Python.
-**FastAPI** будет вызывать её каждый раз при получении `GET` запроса к URL "`/`".
+**FastAPI** будет вызывать её каждый раз, когда получает запрос к URL «`/`» с операцией `GET`.
-В данном случае это асинхронная функция.
+В данном случае это асинхронная (`async`) функция.
---
-Вы также можете определить ее как обычную функцию вместо `async def`:
+Вы также можете определить её как обычную функцию вместо `async def`:
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
-/// note | ТеÑ\85ниÑ\87еÑ\81кие деÑ\82али
+/// note | Ð\9fÑ\80имеÑ\87ание
-Ð\95Ñ\81ли не знаеÑ\82е в Ñ\87Ñ\91м Ñ\80азниÑ\86а, поÑ\81моÑ\82Ñ\80иÑ\82е [Ð\9aонкÑ\83Ñ\80енÑ\82ноÑ\81Ñ\82Ñ\8c: *"Ð\9dеÑ\82 вÑ\80емени?"*](../async.md#_1){.internal-link target=_blank}.
+Ð\95Ñ\81ли вÑ\8b не знаеÑ\82е, в Ñ\87Ñ\91м Ñ\80азниÑ\86а, поÑ\81моÑ\82Ñ\80иÑ\82е [Ð\90Ñ\81инÑ\85Ñ\80онноÑ\81Ñ\82Ñ\8c: *"Ð\9dеÑ\82 вÑ\80емени?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
///
-### Шаг 5: веÑ\80ниÑ\82е Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82
+### Шаг 5: веÑ\80ниÑ\82е Ñ\81одеÑ\80жимое { #step-5-return-the-content }
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.
-Также можно вернуть модели Pydantic (рассмотрим это позже).
+Также можно вернуть модели Pydantic (подробнее об этом позже).
-Ð\9cногие обÑ\8aекÑ\82Ñ\8b и модели бÑ\83дÑ\83Ñ\82 авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80еобÑ\80азованÑ\8b в JSON (вклÑ\8eÑ\87аÑ\8f ORM). Ð\9fÑ\80обÑ\83йÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c дÑ\80Ñ\83гие обÑ\8aекÑ\82Ñ\8b, коÑ\82оÑ\80Ñ\8bе пÑ\80едпоÑ\87Ñ\82иÑ\82елÑ\8cней длÑ\8f Ð\92аÑ\81, веÑ\80оÑ\8fÑ\82но, они уже поддерживаются.
+Ð\9cногие дÑ\80Ñ\83гие обÑ\8aекÑ\82Ñ\8b и модели бÑ\83дÑ\83Ñ\82 авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80еобÑ\80азованÑ\8b в JSON (вклÑ\8eÑ\87аÑ\8f ORM и Ñ\82. п.). Ð\9fопÑ\80обÑ\83йÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82е, Ñ\87Ñ\82о вам пÑ\80ивÑ\8bÑ\87нее, Ñ\81 вÑ\8bÑ\81окой веÑ\80оÑ\8fÑ\82ноÑ\81Ñ\82Ñ\8cÑ\8e они уже поддерживаются.
-## Резюме
+## Резюме { #recap }
-* Ð\98мпоÑ\80Ñ\82иÑ\80Ñ\83ем `FastAPI`.
-* Создаём экземпляр `app`.
-* Ð\9fиÑ\88ем **декоÑ\80аÑ\82оÑ\80 опеÑ\80аÑ\86ии пÑ\83Ñ\82и** (Ñ\82акой как `@app.get("/")`).
-* Ð\9fиÑ\88ем **Ñ\84Ñ\83нкÑ\86иÑ\8e опеÑ\80аÑ\86ии пÑ\83Ñ\82и** (`def root(): ...`).
-* Запускаем сервер в режиме разработки (`uvicorn main:app --reload`).
+* Ð\98мпоÑ\80Ñ\82иÑ\80Ñ\83йÑ\82е `FastAPI`.
+* Создайте экземпляр `app`.
+* Ð\9dапиÑ\88иÑ\82е **декоÑ\80аÑ\82оÑ\80 опеÑ\80аÑ\86ии пÑ\83Ñ\82и**, напÑ\80имеÑ\80 `@app.get("/")`.
+* Ð\9eпÑ\80еделиÑ\82е **Ñ\84Ñ\83нкÑ\86иÑ\8e опеÑ\80аÑ\86ии пÑ\83Ñ\82и**; напÑ\80имеÑ\80, `def root(): ...`.
+* Запустите сервер разработки командой `fastapi dev`.
-# Обработка ошибок
+# Обработка ошибок { #handling-errors }
Существует множество ситуаций, когда необходимо сообщить об ошибке клиенту, использующему ваш API.
Помните ли ошибки **"404 Not Found "** (и шутки) ?
-## Использование `HTTPException`
+## Использование `HTTPException` { #use-httpexception }
Для возврата клиенту HTTP-ответов с ошибками используется `HTTPException`.
-### Импортируйте `HTTPException`
+### Импортируйте `HTTPException` { #import-httpexception }
{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
-### Вызовите `HTTPException` в своем коде
+### Вызовите `HTTPException` в своем коде { #raise-an-httpexception-in-your-code }
`HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API.
{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
-### Возвращаемый ответ
+### Возвращаемый ответ { #the-resulting-response }
Если клиент запросит `http://example.com/items/foo` (`item_id` `"foo"`), то он получит статус-код 200 и ответ в формате JSON:
///
-## Добавление пользовательских заголовков
+## Добавление пользовательских заголовков { #add-custom-headers }
В некоторых ситуациях полезно иметь возможность добавлять пользовательские заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
-## Установка пользовательских обработчиков исключений
+## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers }
Вы можете добавить пользовательские обработчики исключений с помощью <a href="https://www.starlette.io/exceptions/" class="external-link" target="_blank">то же самое исключение - утилиты от Starlette</a>.
///
-## Переопределение стандартных обработчиков исключений
+## Переопределение стандартных обработчиков исключений { #override-the-default-exception-handlers }
**FastAPI** имеет некоторые обработчики исключений по умолчанию.
Вы можете переопределить эти обработчики исключений на свои собственные.
-### Переопределение исключений проверки запроса
+### Переопределение исключений проверки запроса { #override-request-validation-exceptions }
Когда запрос содержит недопустимые данные, **FastAPI** внутренне вызывает ошибку `RequestValidationError`.
value is not a valid integer (type=type_error.integer)
```
-#### `RequestValidationError` или `ValidationError`
+#### `RequestValidationError` или `ValidationError` { #requestvalidationerror-vs-validationerror }
/// warning | Внимание
И пока вы не устраните ошибку, ваши клиенты/пользователи не должны иметь доступа к внутренней информации о ней, так как это может привести к уязвимости в системе безопасности.
-### Переопределите обработчик ошибок `HTTPException`
+### Переопределите обработчик ошибок `HTTPException` { #override-the-httpexception-error-handler }
Аналогичным образом можно переопределить обработчик `HTTPException`.
///
-### Используйте тело `RequestValidationError`
+### Используйте тело `RequestValidationError` { #use-the-requestvalidationerror-body }
Ошибка `RequestValidationError` содержит полученное `тело` с недопустимыми данными.
}
```
-#### `HTTPException` в FastAPI или в Starlette
+#### `HTTPException` в FastAPI или в Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
**FastAPI** имеет собственный `HTTPException`.
Класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`.
-Единственное отличие заключается в том, что `HTTPException` от **FastAPI** позволяет добавлять заголовки, которые будут включены в ответ.
-
-Он необходим/используется внутри системы для OAuth 2.0 и некоторых утилит безопасности.
+Единственное отличие состоит в том, что `HTTPException` в **FastAPI** принимает любые данные, пригодные для преобразования в JSON, в поле `detail`, тогда как `HTTPException` в Starlette принимает для него только строки.
Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своем коде.
Но когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette.
-Таким образом, если какая-либо часть внутреннего кода Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.
+Таким образом, если какая-либо часть внутреннего кодa Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.
В данном примере, чтобы иметь возможность использовать оба `HTTPException` в одном коде, исключения Starlette переименованы в `StarletteHTTPException`:
from starlette.exceptions import HTTPException as StarletteHTTPException
```
-### Переиспользование обработчиков исключений **FastAPI**
+### Переиспользование обработчиков исключений **FastAPI** { #reuse-fastapis-exception-handlers }
Если вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`:
-# Модели Header-параметров
+# Модели Header-параметров { #header-parameter-models }
Если у вас есть группа связанных **header-параметров**, то вы можете объединить их в одну **Pydantic-модель**.
///
-## Header-параметры в виде Pydantic-модели
+## Header-параметры в виде Pydantic-модели { #header-parameters-with-a-pydantic-model }
Объявите нужные **header-параметры** в **Pydantic-модели** и затем аннотируйте параметр как `Header`:
**FastAPI** **извлечёт** данные для **каждого поля** из **заголовков** запроса и выдаст заданную вами Pydantic-модель.
-## Проверьте документацию
+## Проверьте документацию { #check-the-docs }
Вы можете посмотреть нужные header-параметры в графическом интерфейсе сгенерированной документации по пути `/docs`:
<img src="/img/tutorial/header-param-models/image01.png">
</div>
-## Как запретить дополнительные заголовки
+## Как запретить дополнительные заголовки { #forbid-extra-headers }
В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** заголовки, которые вы хотите получать.
}
```
-## Как отключить автоматическое преобразование подчеркиваний
+## Как отключить автоматическое преобразование подчеркиваний { #disable-convert-underscores }
Как и в случае с обычными заголовками, если у вас в именах параметров имеются символы подчеркивания, они **автоматически преобразовываются в дефис**.
///
-## Резюме
+## Резюме { #summary }
Вы можете использовать **Pydantic-модели** для объявления **header-параметров** в **FastAPI**. 😎
-# Header-параметры
+# Header-параметры { #header-parameters }
Вы можете определить параметры заголовка таким же образом, как вы определяете параметры `Query`, `Path` и `Cookie`.
-## Импорт `Header`
+## Импорт `Header` { #import-header }
Сперва импортируйте `Header`:
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
-## Объявление параметров `Header`
+## Объявление параметров `Header` { #declare-header-parameters }
Затем объявите параметры заголовка, используя ту же структуру, что и с `Path`, `Query` и `Cookie`.
///
-/// info | Ð\94ополниÑ\82елÑ\8cнаÑ\8f информация
+/// info | Ð\98нформация
Чтобы объявить заголовки, важно использовать `Header`, иначе параметры интерпретируются как query-параметры.
///
-## Автоматическое преобразование
+## Автоматическое преобразование { #automatic-conversion }
`Header` обладает небольшой дополнительной функциональностью в дополнение к тому, что предоставляют `Path`, `Query` и `Cookie`.
///
-## Повторяющиеся заголовки
+## Повторяющиеся заголовки { #duplicate-headers }
Есть возможность получать несколько заголовков с одним и тем же именем, но разными значениями.
}
```
-## Резюме
+## Резюме { #recap }
Объявляйте заголовки с помощью `Header`, используя тот же общий шаблон, как при `Query`, `Path` и `Cookie`.
-# Учебник - Руководство пользователя
+# Учебник - Руководство пользователя { #tutorial-user-guide }
-В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций.
+В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций.
-Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API.
+Каждый раздел постепенно основывается на предыдущих, но структура разделяет темы, так что вы можете сразу перейти к нужной теме для решения ваших конкретных задач по API.
-Ð\9eн Ñ\82акже Ñ\81оздан длÑ\8f иÑ\81полÑ\8cзованиÑ\8f в каÑ\87еÑ\81Ñ\82ве бÑ\83дÑ\83Ñ\89его Ñ\81пÑ\80авоÑ\87ника.
+Ð\9eн Ñ\82акже Ñ\81оздан как Ñ\81пÑ\80авоÑ\87ник на бÑ\83дÑ\83Ñ\89ее, Ñ\87Ñ\82обÑ\8b вÑ\8b могли веÑ\80нÑ\83Ñ\82Ñ\8cÑ\81Ñ\8f и поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c именно Ñ\82о, Ñ\87Ñ\82о вам нÑ\83жно.
-Так что вы можете вернуться и посмотреть именно то, что вам нужно.
+## Запустите код { #run-the-code }
-## Запустите код
+Все блоки кода можно копировать и использовать напрямую (это действительно протестированные файлы Python).
-Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python).
-
-Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `uvicorn` с параметрами:
+Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с:
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
+
+ <span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
+
+ Searching for package file structure from directories
+ with <font color="#3465A4">__init__.py</font> files
+ Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
+ the following code:
+
+ <u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
+ <b>fastapi run</b>
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-<span style="color: green;">INFO</span>: Started reloader process [28720]
-<span style="color: green;">INFO</span>: Started server process [28722]
-<span style="color: green;">INFO</span>: Waiting for application startup.
-<span style="color: green;">INFO</span>: Application startup complete.
+ Logs:
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
+ <b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
+ to quit<b>)</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
```
</div>
-**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально.
+**НАСТОЯТЕЛЬНО рекомендуется** написать или скопировать код, отредактировать его и запустить локально.
-Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д.
+Использование кода в вашем редакторе кода — это то, что действительно показывает преимущества FastAPI: вы увидите, как мало кода нужно написать, все проверки типов, автозавершение и т.д.
---
-## Установка FastAPI
+## Установка FastAPI { #install-fastapi }
Первый шаг — установить FastAPI.
-Ð\94лÑ\8f Ñ\80Ñ\83ководÑ\81Ñ\82ва вÑ\8b, возможно, заÑ\85оÑ\82иÑ\82е Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c его Ñ\81о вÑ\81еми дополниÑ\82елÑ\8cнÑ\8bми завиÑ\81имоÑ\81Ñ\82Ñ\8fми и Ñ\84Ñ\83нкÑ\86иÑ\8fми:
+УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b Ñ\81оздали [виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение](../virtual-environments.md){.internal-link target=_blank}, акÑ\82ивиÑ\80овали его, и заÑ\82ем **Ñ\83Ñ\81Ñ\82ановиÑ\82е FastAPI**:
<div class="termy">
```console
-$ pip install "fastapi[all]"
+$ pip install "fastapi[standard]"
---> 100%
```
</div>
-...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код.
-
-/// note | Технические детали
-
-Вы также можете установить его по частям.
+/// note | Примечание
-ÐÑ\82о Ñ\82о, Ñ\87Ñ\82о вÑ\8b, веÑ\80оÑ\8fÑ\82но, Ñ\81делаеÑ\82е, когда заÑ\85оÑ\82иÑ\82е Ñ\80азвеÑ\80нÑ\83Ñ\82Ñ\8c Ñ\81вое пÑ\80иложение в Ñ\80абоÑ\87ей Ñ\81Ñ\80еде:
+Ð\9fÑ\80и Ñ\83Ñ\81Ñ\82ановке Ñ\81 помоÑ\89Ñ\8cÑ\8e `pip install "fastapi[standard]"` добавлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f некоÑ\82оÑ\80Ñ\8bе Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе необÑ\8fзаÑ\82елÑ\8cнÑ\8bе завиÑ\81имоÑ\81Ñ\82и по Ñ\83молÑ\87аниÑ\8e, вклÑ\8eÑ\87аÑ\8f `fastapi-cloud-cli`, коÑ\82оÑ\80Ñ\8bй позволÑ\8fеÑ\82 Ñ\80азвеÑ\80нÑ\83Ñ\82Ñ\8c пÑ\80иложение на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
-```
-pip install fastapi
-```
-
-Также установите `uvicorn` для работы в качестве сервера:
-
-```
-pip install "uvicorn[standard]"
-```
+Если вы не хотите иметь эти необязательные зависимости, установите просто `pip install fastapi`.
-Ð\98 Ñ\82о же Ñ\81амое длÑ\8f каждой из необÑ\8fзаÑ\82елÑ\8cнÑ\8bÑ\85 завиÑ\81имоÑ\81Ñ\82ей, коÑ\82оÑ\80Ñ\8bе вÑ\8b Ñ\85оÑ\82иÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c.
+Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bе завиÑ\81имоÑ\81Ñ\82и, но без `fastapi-cloud-cli`, Ñ\83Ñ\81Ñ\82ановиÑ\82е `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
///
-## Продвинутое руководство пользователя
+## Продвинутое руководство пользователя { #advanced-user-guide }
-Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**.
+Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после **Учебник - Руководство пользователя**.
-**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям.
+**Продвинутое руководство пользователя** основано на этом, использует те же концепции и обучает некоторым дополнительным функциям.
-Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
+Но сначала вам следует прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
-Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**.
+Оно спроектировано так, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя дополнительные идеи из **Продвинутого руководства пользователя**.
-# URL-адреса метаданных и документации
+# URL-адреса метаданных и документации { #metadata-and-docs-urls }
Вы можете настроить несколько конфигураций метаданных в вашем **FastAPI** приложении.
-## Метаданные для API
+## Метаданные для API { #metadata-for-api }
Вы можете задать следующие поля, которые используются в спецификации OpenAPI и в UI автоматической документации API:
| Параметр | Тип | Описание |
-|------------|--|-------------|
+|------------|------|-------------|
| `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>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</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>Выражение лицензии <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> для 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> |
Вы можете задать их следующим образом:
-{* ../../docs_src/metadata/tutorial001.py hl[3:16,19:31] *}
+{* ../../docs_src/metadata/tutorial001.py hl[3:16, 19:32] *}
/// tip | Подсказка
///
-С этой конфигурацией автоматическая документация API будут выглядеть так:
+С этой конфигурацией автоматическая документация API будет выглядеть так:
<img src="/img/tutorial/metadata/image01.png">
-## Метаданные для тегов
+## Идентификатор лицензии { #license-identifier }
+
+Начиная с OpenAPI 3.1.0 и FastAPI 0.99.0, вы также можете задать `license_info` с помощью `identifier` вместо `url`.
+
+К примеру:
+
+{* ../../docs_src/metadata/tutorial001_1.py hl[31] *}
+
+## Метаданные для тегов { #metadata-for-tags }
Вы также можете добавить дополнительные метаданные для различных тегов, используемых для группировки ваших операций пути с помощью параметра `openapi_tags`.
* `description`: `str`-значение с кратким описанием для внешней документации.
* `url` (**обязательно**): `str`-значение с URL-адресом для внешней документации.
-### Создание метаданных для тегов
+### Создание метаданных для тегов { #create-metadata-for-tags }
Давайте попробуем сделать это на примере с тегами для `users` и `items`.
///
-### Используйте собственные теги
+### Используйте собственные теги { #use-your-tags }
+
Используйте параметр `tags` с вашими *операциями пути* (и `APIRouter`ами), чтобы присвоить им различные теги:
{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
/// info | Дополнительная информация
-Узнайте больше о тегах в [Конфигурации операции пути](path-operation-configuration.md#_3){.internal-link target=_blank}.
+Узнайте больше о тегах в [Конфигурации операции пути](path-operation-configuration.md#tags){.internal-link target=_blank}.
///
-### Проверьте документацию
+### Проверьте документацию { #check-the-docs }
Теперь, если вы проверите документацию, вы увидите всю дополнительную информацию:
<img src="/img/tutorial/metadata/image02.png">
-### Порядок расположения тегов
+### Порядок расположения тегов { #order-of-tags }
-Порядок расположения словарей метаданных для каждого тега определяет также порядок, отображаемый в документах UI
+Порядок расположения словарей метаданных для каждого тега определяет также порядок, отображаемый в UI документации.
К примеру, несмотря на то, что `users` будут идти после `items` в алфавитном порядке, они отображаются раньше, потому что мы добавляем свои метаданные в качестве первого словаря в списке.
-## URL-адреса OpenAPI
+## URL-адрес OpenAPI { #openapi-url }
По умолчанию схема OpenAPI отображена по адресу `/openapi.json`.
{* ../../docs_src/metadata/tutorial002.py hl[3] *}
-Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые его использует.
+Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые её используют.
-## URL-адреса документации
+## URL-адреса документации { #docs-urls }
-Вы можете изменить конфигурацию двух пользовательских интерфейсов документации, среди которых
+Вы можете изменить конфигурацию двух пользовательских интерфейсов документации, которые включены:
* **Swagger UI**: отображаемый по адресу `/docs`.
* Вы можете задать его URL с помощью параметра `docs_url`.
-# Middleware (Промежуточный слой)
+# Middleware (Промежуточный слой) { #middleware }
Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
Если у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware.
-Если у вас имеются некие фоновые задачи (см. документацию), то они будут запущены после middleware.
+Если были какие‑либо фоновые задачи (рассматриваются в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}, вы увидите это позже), они будут запущены *после* всех middleware.
///
-## Создание middleware
+## Создание middleware { #create-a-middleware }
Для создания middleware используйте декоратор `@app.middleware("http")`.
///
-### До и после `response`
+### До и после `response` { #before-and-after-the-response }
Вы можете добавить код, использующий `request` до передачи его какой-либо *операции пути*.
///
-## Другие middleware
+## Порядок выполнения нескольких middleware { #multiple-middleware-execution-order }
+
+Когда вы добавляете несколько middleware с помощью декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, формируя стек. Последнее добавленное middleware — самое внешнее (*outermost*), а первое — самое внутреннее (*innermost*).
+
+На пути обработки запроса сначала выполняется самое внешнее middleware.
+
+На пути формирования ответа оно выполняется последним.
+
+Например:
+
+```Python
+app.add_middleware(MiddlewareA)
+app.add_middleware(MiddlewareB)
+```
+
+Это приводит к следующему порядку выполнения:
+
+* **Запрос**: MiddlewareB → MiddlewareA → маршрут
+
+* **Ответ**: маршрут → MiddlewareA → MiddlewareB
+
+Такое стековое поведение обеспечивает предсказуемый и управляемый порядок выполнения middleware.
+
+## Другие middleware { #other-middlewares }
О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
-В следующем разделе вы можете прочитать, как настроить <abbr title="Cross-Origin Resource Sharing">CORS</abbr> с помощью middleware.
+В следующем разделе вы можете прочитать, как настроить <abbr title="Cross-Origin Resource Sharing – совместное использование ресурсов между источниками">CORS</abbr> с помощью middleware.
-# Конфигурация операций пути
+# Конфигурация операций пути { #path-operation-configuration }
Существует несколько параметров, которые вы можете передать вашему *декоратору операций пути* для его настройки.
///
-## Ð\9aодÑ\8b Ñ\81оÑ\81Ñ\82оÑ\8fниÑ\8f
+## СÑ\82аÑ\82Ñ\83Ñ\81-код оÑ\82веÑ\82а { #response-status-code }
Вы можете определить (HTTP) `status_code`, который будет использован в ответах вашей *операции пути*.
{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
-Этот код состояния будет использован в ответе и будет добавлен в схему OpenAPI.
+Этот статус-код будет использован в ответе и будет добавлен в схему OpenAPI.
/// note | Технические детали
///
-## Теги
+## Теги { #tags }
Вы можете добавлять теги к вашим *операциям пути*, добавив параметр `tags` с `list` заполненным `str`-значениями (обычно в нём только одна строка):
<img src="/img/tutorial/path-operation-configuration/image01.png">
-### Теги с перечислениями
+### Теги с перечислениями { #tags-with-enums }
Если у вас большое приложение, вы можете прийти к необходимости добавить **несколько тегов**, и возможно, вы захотите убедиться в том, что всегда используете **один и тот же тег** для связанных *операций пути*.
{* ../../docs_src/path_operation_configuration/tutorial002b.py hl[1,8:10,13,18] *}
-## Краткое и развёрнутое содержание
+## Краткое и развёрнутое содержание { #summary-and-description }
Вы можете добавить параметры `summary` и `description`:
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
-## Описание из строк документации
+## Описание из строк документации { #description-from-docstring }
Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в функции <abbr title="многострочный текст, первое выражение внутри функции (не присвоенный какой-либо переменной), используемый для документации">строки документации</abbr> и **FastAPI** прочитает её отсюда.
<img src="/img/tutorial/path-operation-configuration/image02.png">
-## Описание ответа
+## Описание ответа { #response-description }
Вы можете указать описание ответа с помощью параметра `response_description`:
///
-/// check | Технические детали
+/// check
OpenAPI указывает, что каждой *операции пути* необходимо описание ответа.
<img src="/img/tutorial/path-operation-configuration/image03.png">
-## Обозначение *операции пути* как устаревшей
+## Обозначение *операции пути* как устаревшей { #deprecate-a-path-operation }
Если вам необходимо пометить *операцию пути* как <abbr title="устаревшее, не рекомендовано к использованию">устаревшую</abbr>, при этом не удаляя её, передайте параметр `deprecated`:
<img src="/img/tutorial/path-operation-configuration/image05.png">
-## Резюме
+## Резюме { #recap }
Вы можете легко конфигурировать и добавлять метаданные в ваши *операции пути*, передавая параметры *декораторам операций пути*.
-# Path-параметры и валидация числовых данных
+# Path-параметры и валидация числовых данных { #path-parameters-and-numeric-validations }
Так же, как с помощью `Query` вы можете добавлять валидацию и метаданные для query-параметров, так и с помощью `Path` вы можете добавлять такую же валидацию и метаданные для path-параметров.
-## Импорт Path
+## Импорт `Path` { #import-path }
Сначала импортируйте `Path` из `fastapi`, а также импортируйте `Annotated`:
Если вы используете более старую версию, вы столкнётесь с ошибками при попытке использовать `Annotated`.
-Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#fastapi_2){.internal-link target=_blank} как минимум до 0.95.1 перед тем, как использовать `Annotated`.
+Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} как минимум до 0.95.1 перед тем, как использовать `Annotated`.
///
-## Определите метаданные
+## Определите метаданные { #declare-metadata }
Вы можете указать все те же параметры, что и для `Query`.
/// note | Примечание
-Path-параметр всегда является обязательным, поскольку он составляет часть пути.
-
-Поэтому следует объявить его с помощью `...`, чтобы обозначить, что этот параметр обязательный.
-
-Тем не менее, даже если вы объявите его как `None` или установите для него значение по умолчанию, это ни на что не повлияет и параметр останется обязательным.
+Path-параметр всегда является обязательным, поскольку он должен быть частью пути. Даже если вы объявите его как `None` или зададите значение по умолчанию, это ни на что не повлияет — параметр всё равно будет обязательным.
///
-## Задайте нужный вам порядок параметров
+## Задайте нужный вам порядок параметров { #order-the-parameters-as-you-need }
/// tip | Подсказка
Поэтому вы можете определить функцию так:
-//// tab | Python 3.8 без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/path_params_numeric_validations/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
-Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете `Query()` или `Path()` в качестве значения по умолчанию для параметра функции.
+Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете значения по умолчанию параметров функции для `Query()` или `Path()`.
-{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
-## Задайте нужный вам порядок параметров, полезные приёмы
+## Задайте нужный вам порядок параметров, полезные приёмы { #order-the-parameters-as-you-need-tricks }
/// tip | Подсказка
Передайте `*` в качестве первого параметра функции.
-Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>, даже если у них нет значений по умолчанию.
+Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как <abbr title="От: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>, даже если у них нет значений по умолчанию.
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
-### Лучше с `Annotated`
+### Лучше с `Annotated` { #better-with-annotated }
-Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о еÑ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е `Annotated`, Ñ\82о, поÑ\81колÑ\8cкÑ\83 вÑ\8b не иÑ\81полÑ\8cзÑ\83еÑ\82е знаÑ\87ений по Ñ\83молÑ\87аниÑ\8e длÑ\8f паÑ\80амеÑ\82Ñ\80ов Ñ\84Ñ\83нкÑ\86ии, Ñ\82о Ñ\83 ваÑ\81 не возникнеÑ\82 подобной пÑ\80облемÑ\8b и вам не придётся использовать `*`.
+Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о еÑ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е `Annotated`, Ñ\82о, поÑ\81колÑ\8cкÑ\83 вÑ\8b не иÑ\81полÑ\8cзÑ\83еÑ\82е знаÑ\87ений по Ñ\83молÑ\87аниÑ\8e длÑ\8f паÑ\80амеÑ\82Ñ\80ов Ñ\84Ñ\83нкÑ\86ии, Ñ\83 ваÑ\81 не возникнеÑ\82 подобной пÑ\80облемÑ\8b и вам, веÑ\80оÑ\8fÑ\82но, не придётся использовать `*`.
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
-## Валидация числовых данных: больше или равно
+## Валидация числовых данных: больше или равно { #number-validations-greater-than-or-equal }
С помощью `Query` и `Path` (и других классов, которые мы разберём позже) вы можете добавлять ограничения для числовых данных.
-В этом примере при указании `ge=1`, параметр `item_id` должен быть больше или равен `1` ("`g`reater than or `e`qual").
+В этом примере при указании `ge=1`, параметр `item_id` должен быть целым числом "`g`reater than or `e`qual" — больше или равно `1`.
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
-## Валидация числовых данных: больше и меньше или равно
+## Валидация числовых данных: больше и меньше или равно { #number-validations-greater-than-and-less-than-or-equal }
То же самое применимо к:
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
-## Валидация числовых данных: числа с плавающей точкой, больше и меньше
+## Валидация числовых данных: числа с плавающей точкой, больше и меньше { #number-validations-floats-greater-than-and-less-than }
Валидация также применима к значениям типа `float`.
-В этом случае становится важной возможность добавить ограничение <abbr title="greater than"><code>gt</code></abbr>, вместо <abbr title="greater than or equal"><code>ge</code></abbr>, поскольку в таком случае вы можете, например, создать ограничение, чтобы значение было больше `0`, даже если оно меньше `1`.
+В этом случае становится важной возможность добавить ограничение <abbr title="greater than – больше чем"><code>gt</code></abbr>, вместо <abbr title="greater than or equal – больше или равно"><code>ge</code></abbr>, поскольку в таком случае вы можете, например, создать ограничение, чтобы значение было больше `0`, даже если оно меньше `1`.
Таким образом, `0.5` будет корректным значением. А `0.0` или `0` — нет.
-То же самое справедливо и для <abbr title="less than"><code>lt</code></abbr>.
+То же самое справедливо и для <abbr title="less than – меньше чем"><code>lt</code></abbr>.
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
-## Резюме
+## Резюме { #recap }
С помощью `Query`, `Path` (и других классов, которые мы пока не затронули) вы можете добавлять метаданные и строковую валидацию тем же способом, как и в главе [Query-параметры и валидация строк](query-params-str-validations.md){.internal-link target=_blank}.
/// info | Информация
-`Query`, `Path` и дÑ\80Ñ\83гие клаÑ\81Ñ\81Ñ\8b, коÑ\82оÑ\80Ñ\8bе мÑ\8b Ñ\80азбеÑ\80Ñ\91м позже, являются наследниками общего класса `Param`.
+`Query`, `Path` и дÑ\80Ñ\83гие клаÑ\81Ñ\81Ñ\8b, коÑ\82оÑ\80Ñ\8bе вÑ\8b Ñ\80азбеÑ\80Ñ\91Ñ\82е позже, являются наследниками общего класса `Param`.
Все они используют те же параметры для дополнительной валидации и метаданных, которые вы видели ранее.
-# Path-параметры
+# Path-параметры { #path-parameters }
Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python:
{"item_id":"foo"}
```
-## Параметры пути с типами
+## Параметры пути с типами { #path-parameters-with-types }
-Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python.
+Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python:
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
/// check | Заметка
-ÐÑ\82о обеÑ\81пеÑ\87иÑ\82 поддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии (пÑ\80овеÑ\80ка оÑ\88ибок, авÑ\82одополнение и т.п.).
+ÐÑ\82о обеÑ\81пеÑ\87иÑ\82 поддеÑ\80жкÑ\83 Ñ\80едакÑ\82оÑ\80а кода внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии (пÑ\80овеÑ\80ка оÑ\88ибок, авÑ\82озавеÑ\80Ñ\88ение и т.п.).
///
-## <abbr title="Или сериализация, парсинг">Преобразование</abbr> данных
+## <abbr title="также известное как: сериализация, парсинг, маршаллинг">Преобразование</abbr> данных { #data-conversion }
Если запустите этот пример и перейдёте по адресу: <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, то увидите ответ:
Обратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `"3"`.
-Используя определения типов, **FastAPI** выполняет автоматический <abbr title="преобразование строк из HTTP-запроса в типы данных Python">"парсинг"</abbr> запросов.
+Используя такое объявление типов, **FastAPI** выполняет автоматический <abbr title="преобразование строк из HTTP-запроса в типы данных Python">"парсинг"</abbr> запросов.
///
-## <abbr title="Или валидация">Проверка</abbr> данных
+## Валидация данных { #data-validation }
Если откроете браузер по адресу <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, то увидите интересную HTTP-ошибку:
```JSON
{
- "detail": [
- {
- "loc": [
- "path",
- "item_id"
- ],
- "msg": "value is not a valid integer",
- "type": "type_error.integer"
- }
- ]
+ "detail": [
+ {
+ "type": "int_parsing",
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "Input should be a valid integer, unable to parse string as an integer",
+ "input": "foo"
+ }
+ ]
}
```
-из-за того, что параметр пути `item_id` имеет значение `"foo"`, которое не является типом `int`.
+из-за того, что параметр пути `item_id` имеет значение `"foo"`, которое не является типом `int`.
-Та же ошибка возникнет, если вместо `int` передать `float` , например: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
+Та же ошибка возникнет, если вместо `int` передать `float`, например: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
/// check | Заметка
-**FastAPI** обеÑ\81пеÑ\87иваеÑ\82 пÑ\80овеÑ\80кÑ\83 Ñ\82ипов, используя всё те же определения типов.
+**FastAPI** обеÑ\81пеÑ\87иваеÑ\82 валидаÑ\86иÑ\8e даннÑ\8bÑ\85, используя всё те же определения типов.
-Обратите внимание, что в тексте ошибки явно указано место не прошедшее проверку.
+Обратите внимание, что в тексте ошибки явно указано место, не прошедшее проверку.
Это очень полезно при разработке и отладке кода, который взаимодействует с API.
///
-## Документация
+## Документация { #documentation }
И теперь, когда откроете браузер по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, то увидите вот такую автоматически сгенерированную документацию API:
///
-## Преимущества стандартизации, альтернативная документация
+## Преимущества стандартизации, альтернативная документация { #standards-based-benefits-alternative-documentation }
-Поскольку сгенерированная схема соответствует стандарту <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a>, её можно использовать со множеством совместимых инструментов.
+Поскольку сгенерированная схема соответствует стандарту <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a>, её можно использовать со множеством совместимых инструментов.
-Именно поэтому, FastAPI сам предоставляет альтернативную документацию API (используя ReDoc), которую можно получить по адресу: <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
+Именно поэтому, **FastAPI** сам предоставляет альтернативную документацию API (используя ReDoc), которую можно получить по адресу: <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
<img src="/img/tutorial/path-params/image02.png">
По той же причине, есть множество совместимых инструментов, включая инструменты генерации кода для многих языков.
-## Pydantic
+## Pydantic { #pydantic }
Вся проверка данных выполняется под капотом с помощью <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>. Поэтому вы можете быть уверены в качестве обработки данных.
Некоторые из них рассматриваются в следующих главах данного руководства.
-## Порядок имеет значение
+## Порядок имеет значение { #order-matters }
При создании *операций пути* можно столкнуться с ситуацией, когда путь является фиксированным.
Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:
-
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`.
Первый будет выполняться всегда, так как путь совпадает первым.
-## Предопределенные значения
+## Предопределенные значения { #predefined-values }
Что если нам нужно заранее определить допустимые *параметры пути*, которые *операция пути* может принимать? В таком случае можно использовать стандартное перечисление <abbr title="Enumeration">`Enum`</abbr> Python.
-### Создание класса `Enum`
+### Создание класса `Enum` { #create-an-enum-class }
Импортируйте `Enum` и создайте подкласс, который наследуется от `str` и `Enum`.
/// tip | Подсказка
-Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия <abbr title="Технически, это архитектуры моделей глубокого обучения">моделей</abbr> машинного обучения.
+Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия <abbr title="Технически, архитектуры моделей глубокого обучения">моделей</abbr> Машинного обучения.
///
-### Определение *параметра пути*
+### Определение *параметра пути* { #declare-a-path-parameter }
Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее:
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
-### Проверьте документацию
+### Проверьте документацию { #check-the-docs }
Поскольку доступные значения *параметра пути* определены заранее, интерактивная документация может наглядно их отображать:
<img src="/img/tutorial/path-params/image03.png">
-### Работа с *перечислениями* в Python
+### Работа с *перечислениями* в Python { #working-with-python-enumerations }
Значение *параметра пути* будет *элементом перечисления*.
-#### Сравнение *элементов перечисления*
+#### Сравнение *элементов перечисления* { #compare-enumeration-members }
Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`:
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
-#### Получение *значения перечисления*
+#### Получение *значения перечисления* { #get-the-enumeration-value }
Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:
///
-#### Возврат *элементов перечисления*
+#### Возврат *элементов перечисления* { #return-enumeration-members }
Из *операции пути* можно вернуть *элементы перечисления*, даже вложенные в тело JSON (например в `dict`).
}
```
-## Path-параметры, содержащие пути
+## Path-параметры, содержащие пути { #path-parameters-containing-paths }
Предположим, что есть *операция пути* с путем `/files/{file_path}`.
Тогда URL для этого файла будет такой: `/files/home/johndoe/myfile.txt`.
-### Поддержка OpenAPI
+### Поддержка OpenAPI { #openapi-support }
OpenAPI не поддерживает способов объявления *параметра пути*, содержащего внутри *путь*, так как это может привести к сценариям, которые сложно определять и тестировать.
Документация по-прежнему будет работать, хотя и не добавит никакой информации о том, что параметр должен содержать путь.
-### Конвертер пути
+### Конвертер пути { #path-convertor }
Благодаря одной из опций Starlette, можете объявить *параметр пути*, содержащий *путь*, используя URL вроде:
///
-## Резюме
+## Резюме { #recap }
+
Используя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете:
-* Поддержку редактора (проверку ошибок, автозаполнение и т.п.)
+* Поддержку редактора кода (проверку ошибок, автозавершение и т.п.)
* "<abbr title="преобразование строк из HTTP-запроса в типы данных Python">Парсинг</abbr>" данных
* Валидацию данных
-* Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e API Ñ\81 Ñ\83казанием Ñ\82ипов паÑ\80амеÑ\82Ñ\80ов.
+* Ð\90нноÑ\82аÑ\86ии API и авÑ\82омаÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e
И объявлять типы достаточно один раз.
-# Модели Query-Параметров
+# Модели Query-Параметров { #query-parameter-models }
Если у вас есть группа связанных **query-параметров**, то вы можете объединить их в одну **Pydantic-модель**.
///
-## Pydantic-Модель для Query-Параметров
+## Pydantic-Модель для Query-Параметров { #query-parameters-with-a-pydantic-model }
Объявите нужные **query-параметры** в **Pydantic-модели**, а после аннотируйте параметр как `Query`:
**FastAPI извлечёт** данные соответствующие **каждому полю модели** из **query-параметров** запроса и выдаст вам объявленную Pydantic-модель заполненную ими.
-## Проверьте Сгенерированную Документацию
+## Проверьте Сгенерированную Документацию { #check-the-docs }
Вы можете посмотреть query-параметры в графическом интерфейсе сгенерированной документации по пути `/docs`:
<img src="/img/tutorial/query-param-models/image01.png">
</div>
-## Запретить Дополнительные Query-Параметры
+## Запретить Дополнительные Query-Параметры { #forbid-extra-query-parameters }
В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** query-параметры, которые вы хотите получить.
}
```
-## Заключение
+## Заключение { #summary }
Вы можете использовать **Pydantic-модели** для объявления **query-параметров** в **FastAPI**. 😎
/// tip | Совет
-Спойлер: вы также можете использовать Pydantic-модели для группировки кук (cookies) и заголовков (headers), но об этом вы прочитаете позже. 🤫
+Спойлер: вы также можете использовать Pydantic-модели, чтобы объявлять cookies и HTTP-заголовки, но об этом вы прочитаете позже. 🤫
///
-# Query-параметры и валидация строк
+# Query-параметры и валидация строк { #query-parameters-and-string-validations }
-**FastAPI** позволяет определять дополнительную информацию и валидацию для ваших параметров.
+**FastAPI** позволяет определять дополнительную информацию и выполнять валидацию для ваших параметров.
-Ð\94авайÑ\82е Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им Ñ\81ледÑ\83Ñ\8eÑ\89ий пÑ\80имеÑ\80:
+РаÑ\81Ñ\81моÑ\82Ñ\80им Ñ\8dÑ\82о пÑ\80иложение в каÑ\87еÑ\81Ñ\82ве пÑ\80имеÑ\80а:
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
-Query-параметр `q` имеет тип `Union[str, None]` (или `str | None` в Python 3.10). Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный.
+Query-параметр `q` имеет тип `str | None`, это означает, что он имеет тип `str`, но также может быть `None`. Значение по умолчанию действительно `None`, поэтому FastAPI будет знать, что он не обязателен.
/// note | Технические детали
-FastAPI опÑ\80еделиÑ\82 паÑ\80амеÑ\82Ñ\80 `q` как необÑ\8fзаÑ\82елÑ\8cнÑ\8bй, поÑ\82омÑ\83 Ñ\87Ñ\82о его знаÑ\87ение по умолчанию `= None`.
+FastAPI поймÑ\91Ñ\82, Ñ\87Ñ\82о знаÑ\87ение `q` не обÑ\8fзаÑ\82елÑ\8cно, изâ\80\91за знаÑ\87ениÑ\8f по умолчанию `= None`.
-`Union` в `Union[str, None]` позволит редактору кода оказать вам лучшую поддержку и найти ошибки.
+Аннотация `str | None` позволит вашему редактору кода обеспечить лучшую поддержку и находить ошибки.
///
-## РаÑ\81Ñ\88иÑ\80еннаÑ\8f валидаÑ\86иÑ\8f
+## Ð\94ополниÑ\82елÑ\8cнаÑ\8f валидаÑ\86иÑ\8f { #additional-validation }
-Ð\94обавим дополниÑ\82елÑ\8cное Ñ\83Ñ\81ловие валидаÑ\86ии паÑ\80амеÑ\82Ñ\80а `q` - **длина Ñ\81Ñ\82Ñ\80оки не более 50 Ñ\81имволов** (Ñ\83Ñ\81ловие пÑ\80овеÑ\80Ñ\8fеÑ\82Ñ\81Ñ\8f вÑ\81Ñ\8fкий Ñ\80аз, когда паÑ\80амеÑ\82Ñ\80 `q` не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f `None`).
+Ð\9cÑ\8b Ñ\81обиÑ\80аемÑ\81Ñ\8f добавиÑ\82Ñ\8c огÑ\80аниÑ\87ение: Ñ\85оÑ\82Ñ\8f `q` и необÑ\8fзаÑ\82елен, когда он пеÑ\80едан, **его длина не должна пÑ\80евÑ\8bÑ\88аÑ\82Ñ\8c 50 Ñ\81имволов**.
-### Импорт `Query` и `Annotated`
+### Импорт `Query` и `Annotated` { #import-query-and-annotated }
-Чтобы достичь этого, первым делом нам нужно импортировать:
+Чтобы сделать это, сначала импортируйте:
-* `Query` из пакета `fastapi`:
-* `Annotated` из пакета `typing` (или из `typing_extensions` для Python ниже 3.9)
+* `Query` из `fastapi`
+* `Annotated` из `typing`
-//// tab | Python 3.10+
-
-В Python 3.9 или выше, `Annotated` является частью стандартной библиотеки, таким образом вы можете импортировать его из `typing`.
-
-```Python hl_lines="1 3"
-{!> ../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
-////
-
-//// tab | Python 3.8+
+/// info | Дополнительная информация
-Ð\92 веÑ\80Ñ\81иÑ\8fÑ\85 Python ниже Python 3.9 `Annotation` импоÑ\80Ñ\82иÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f из `typing_extensions`.
+Ð\9fоддеÑ\80жка `Annotated` (и Ñ\80екомендаÑ\86иÑ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c его) поÑ\8fвилаÑ\81Ñ\8c в FastAPI веÑ\80Ñ\81ии 0.95.0.
-ÐÑ\82а библиоÑ\82ека бÑ\83деÑ\82 Ñ\83Ñ\81Ñ\82ановлена вмеÑ\81Ñ\82е Ñ\81 FastAPI.
+Ð\95Ñ\81ли Ñ\83 ваÑ\81 более Ñ\81Ñ\82аÑ\80аÑ\8f веÑ\80Ñ\81иÑ\8f, пÑ\80и попÑ\8bÑ\82ке иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Annotated` вÑ\8b полÑ\83Ñ\87иÑ\82е оÑ\88ибки.
-```Python hl_lines="3-4"
-{!> ../../docs_src/query_params_str_validations/tutorial002_an.py!}
-```
+Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} как минимум до 0.95.1 перед использованием `Annotated`.
-////
+///
-## `Annotated` как тип для query-параметра `q`
+## Использовать `Annotated` в типе для параметра `q` { #use-annotated-in-the-type-for-the-q-parameter }
-Помните, как ранее я говорил об Annotated? Он может быть использован для добавления метаданных для ваших параметров в разделе [Введение в аннотации типов Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
+Помните, я уже говорил, что `Annotated` можно использовать для добавления метаданных к параметрам в разделе [Введение в типы Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
-Ð\9fÑ\80иÑ\88ло вÑ\80емÑ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c иÑ\85 в FastAPI. 🚀
+Ð\9fÑ\80иÑ\88ло вÑ\80емÑ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c его Ñ\81 FastAPI. 🚀
-У нас была аннотация следующего типа:
+У нас была такая аннотация типа:
//// tab | Python 3.10+
////
-Ð\92оÑ\82 Ñ\87Ñ\82о мÑ\8b полÑ\83Ñ\87им, еÑ\81ли обеÑ\80нÑ\91м Ñ\8dÑ\82о в `Annotated`:
+Ð\9cÑ\8b «обеÑ\80нÑ\91м» Ñ\8dÑ\82о в `Annotated`, и полÑ\83Ñ\87иÑ\82Ñ\81Ñ\8f:
//// tab | Python 3.10+
////
-Обе эти версии означают одно и тоже. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`.
+Обе версии означают одно и то же: `q` — параметр, который может быть `str` или `None`, и по умолчанию равен `None`.
-Ð\94авайÑ\82е повеÑ\81елимÑ\81Ñ\8f. 🎉
+Ð\90 Ñ\82епеÑ\80Ñ\8c к Ñ\81амомÑ\83 инÑ\82еÑ\80еÑ\81номÑ\83. 🎉
-## Добавим `Query` в `Annotated` для query-параметра `q`
+## Добавим `Query` в `Annotated` для параметра `q` { #add-query-to-annotated-in-the-q-parameter }
-ТепеÑ\80Ñ\8c, когда Ñ\83 наÑ\81 еÑ\81Ñ\82Ñ\8c `Annotated`, где мÑ\8b можем добавиÑ\82Ñ\8c болÑ\8cÑ\88е меÑ\82аданнÑ\8bÑ\85, добавим `Query` Ñ\81о знаÑ\87ением паÑ\80амеÑ\82Ñ\80а `max_length` Ñ\80авнÑ\8bм 50:
+ТепеÑ\80Ñ\8c, когда Ñ\83 наÑ\81 еÑ\81Ñ\82Ñ\8c `Annotated`, кÑ\83да можно помеÑ\81Ñ\82иÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\83Ñ\8e инÑ\84оÑ\80маÑ\86иÑ\8e (в наÑ\88ем Ñ\81лÑ\83Ñ\87ае â\80\94 дополниÑ\82елÑ\8cнÑ\8bе пÑ\80авила валидаÑ\86ии), добавим `Query` внÑ\83Ñ\82Ñ\80Ñ\8c `Annotated` и Ñ\83Ñ\81Ñ\82ановим паÑ\80амеÑ\82Ñ\80 `max_length` Ñ\80авнÑ\8bм `50`:
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
-Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e вÑ\81Ñ\91 еÑ\89Ñ\91 `None`, Ñ\82ак Ñ\87Ñ\82о параметр остаётся необязательным.
+Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e поâ\80\91пÑ\80ежнемÑ\83 `None`, Ñ\82о еÑ\81Ñ\82Ñ\8c параметр остаётся необязательным.
-Ð\9eднако Ñ\82епеÑ\80Ñ\8c, имеÑ\8f `Query(max_length=50)` внÑ\83Ñ\82Ñ\80и `Annotated`, мÑ\8b говоÑ\80им FastAPI, Ñ\87Ñ\82о мÑ\8b Ñ\85оÑ\82им извлеÑ\87Ñ\8c Ñ\8dÑ\82о знаÑ\87ение из паÑ\80амеÑ\82Ñ\80ов query-запÑ\80оÑ\81а (Ñ\87Ñ\82о пÑ\80оизойдÑ\91Ñ\82 в лÑ\8eбом Ñ\81лÑ\83Ñ\87ае ð\9f¤·), и Ñ\87Ñ\82о мÑ\8b Ñ\85оÑ\82им имеÑ\82Ñ\8c **дополниÑ\82елÑ\8cнÑ\8bе Ñ\83Ñ\81ловиÑ\8f валидаÑ\86ии** длÑ\8f Ñ\8dÑ\82ого знаÑ\87ениÑ\8f (длÑ\8f Ñ\87его мÑ\8b и делаем Ñ\8dÑ\82о - Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87иÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\83Ñ\8e валидаÑ\86иÑ\8e). 😎
+Ð\9dо Ñ\82епеÑ\80Ñ\8c, добавив `Query(max_length=50)` внÑ\83Ñ\82Ñ\80Ñ\8c `Annotated`, мÑ\8b говоÑ\80им FastAPI, Ñ\87Ñ\82о Ñ\8dÑ\82омÑ\83 знаÑ\87ениÑ\8e нÑ\83жна **дополниÑ\82елÑ\8cнаÑ\8f валидаÑ\86иÑ\8f** â\80\94 макÑ\81имÑ\83м 50 Ñ\81имволов. 😎
-Теперь FastAPI:
+/// tip | Совет
-* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов
-* Показывает **исчерпывающую ошибку** (будет описание местонахождения ошибки и её причины) для клиента в случаях, когда данные не валидны
-* **Задокументирует** параметр в схему OpenAPI *операции пути* (что будет отображено в **UI автоматической документации**)
+Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие — `Path()`, `Body()`, `Header()` и `Cookie()`, — они также принимают те же аргументы, что и `Query()`.
-## Альтернативный (устаревший) способ задать `Query` как значение по умолчанию
+///
-Ð\92 пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 веÑ\80Ñ\81иÑ\8fÑ\85 FastAPI (ниже <abbr title="Ñ\80анее 2023-03">0.95.0</abbr>) необÑ\85одимо бÑ\8bло иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Query` как знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e длÑ\8f query-паÑ\80амеÑ\82Ñ\80а. Так бÑ\8bло вмеÑ\81Ñ\82о Ñ\80азмеÑ\89ениÑ\8f его в `Annotated`, Ñ\82ак Ñ\87Ñ\82о велика веÑ\80оÑ\8fÑ\82ноÑ\81Ñ\82Ñ\8c, Ñ\87Ñ\82о вам вÑ\81Ñ\82Ñ\80еÑ\82иÑ\82Ñ\81Ñ\8f Ñ\82акой код. СейÑ\87аÑ\81 обÑ\8aÑ\8fÑ\81нÑ\8e.
+ТепеÑ\80Ñ\8c FastAPI бÑ\83деÑ\82:
-/// tip | Подсказка
+* **валидировать** данные, удостоверяясь, что максимальная длина — 50 символов;
+* показывать **понятную ошибку** клиенту, если данные невалидны;
+* **документировать** параметр в *операции пути* схемы OpenAPI (он будет показан в **UI автоматической документации**).
-При написании нового кода и везде где это возможно, используйте `Annotated`, как было описано ранее. У этого способа есть несколько преимуществ (о них дальше) и никаких недостатков. 🍰
+## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
-///
-
-Вот как вы могли бы использовать `Query()` в качестве значения по умолчанию параметра вашей функции, установив для параметра `max_length` значение 50:
+В предыдущих версиях FastAPI (до <abbr title="до 2023-03">0.95.0</abbr>) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.
-{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
+/// tip | Подсказка
-Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае (без иÑ\81полÑ\8cзованиÑ\8f `Annotated`), мÑ\8b заменили знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e Ñ\81 `None` на `Query()` в Ñ\84Ñ\83нкÑ\86ии. ТепеÑ\80Ñ\8c нам нÑ\83жно Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e длÑ\8f query-паÑ\80амеÑ\82Ñ\80а `Query(default=None)`, Ñ\87Ñ\82о необÑ\85одимо длÑ\8f Ñ\82еÑ\85 же Ñ\86елей, как когда Ñ\80анее пÑ\80оÑ\81Ñ\82о Ñ\83казÑ\8bвалоÑ\81Ñ\8c знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e (по кÑ\80айней меÑ\80е, длÑ\8f FastAPI).
+Ð\94лÑ\8f нового кода и везде, где Ñ\8dÑ\82о возможно, иÑ\81полÑ\8cзÑ\83йÑ\82е `Annotated`, как опиÑ\81ано вÑ\8bÑ\88е. У Ñ\8dÑ\82ого еÑ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82в (Ñ\81м. ниже) и неÑ\82 недоÑ\81Ñ\82аÑ\82ков. ð\9f\8d°
-Таким образом:
+///
-```Python
-q: Union[str, None] = Query(default=None)
-```
+Вот как можно использовать `Query()` как значение по умолчанию для параметра функции, установив `max_length` равным 50:
-...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
+{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
-```Python
-q: Union[str, None] = None
-```
+Так как в этом случае (без `Annotated`) мы заменяем в функции значение по умолчанию `None` на `Query()`, теперь нужно указать значение по умолчанию через параметр `Query(default=None)`, это служит той же цели — задать значение по умолчанию (по крайней мере для FastAPI).
-И для Python 3.10 и выше:
+Итак:
```Python
q: str | None = Query(default=None)
```
-...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
+...делает параметр необязательным со значением по умолчанию `None`, так же как:
```Python
q: str | None = None
```
-Но он явно объявляет его как query-параметр.
-
-/// info | Дополнительная информация
-
-Запомните, важной частью объявления параметра как необязательного является:
-
-```Python
-= None
-```
-
-или:
-
-```Python
-= Query(default=None)
-```
-
-так как `None` указан в качестве значения по умолчанию, параметр будет **необязательным**.
-
-`Union[str, None]` позволит редактору кода оказать вам лучшую поддержку. Но это не то, на что обращает внимание FastAPI для определения необязательности параметра.
-
-///
+Но вариант с `Query` явно объявляет его как query-параметр.
-ТепеÑ\80Ñ\8c, мÑ\8b можем Ñ\83казаÑ\82Ñ\8c болÑ\8cÑ\88е паÑ\80амеÑ\82Ñ\80ов длÑ\8f `Query`. Ð\92 данном Ñ\81лÑ\83Ñ\87ае, паÑ\80амеÑ\82Ñ\80 `max_length` пÑ\80именÑ\8fеÑ\82Ñ\81Ñ\8f к строкам:
+Ð\97аÑ\82ем мÑ\8b можем пеÑ\80едаÑ\82Ñ\8c и дÑ\80Ñ\83гие паÑ\80амеÑ\82Ñ\80Ñ\8b в `Query`. Ð\92 данном Ñ\81лÑ\83Ñ\87ае â\80\94 паÑ\80амеÑ\82Ñ\80 `max_length`, пÑ\80именимÑ\8bй к строкам:
```Python
-q: Union[str, None] = Query(default=None, max_length=50)
+q: str | None = Query(default=None, max_length=50)
```
-Ð\92Ñ\85однÑ\8bе даннÑ\8bе бÑ\83дÑ\83Ñ\82 пÑ\80овеÑ\80енÑ\8b. Ð\95Ñ\81ли даннÑ\8bе недейÑ\81Ñ\82виÑ\82елÑ\8cнÑ\8b, Ñ\82огда бÑ\83деÑ\82 Ñ\83казано на оÑ\88ибкÑ\83 в запÑ\80оÑ\81е (бÑ\83деÑ\82 опиÑ\81ание меÑ\81Ñ\82онаÑ\85ождениÑ\8f оÑ\88ибки и еÑ\91 пÑ\80иÑ\87инÑ\8b). Ð\9aÑ\80оме Ñ\82ого, паÑ\80амеÑ\82Ñ\80 задокÑ\83менÑ\82иÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f в Ñ\81Ñ\85еме OpenAPI данной *опеÑ\80аÑ\86ии пÑ\83Ñ\82и*.
+ÐÑ\82о пÑ\80овалидиÑ\80Ñ\83еÑ\82 даннÑ\8bе, покажеÑ\82 понÑ\8fÑ\82нÑ\83Ñ\8e оÑ\88ибкÑ\83, еÑ\81ли даннÑ\8bе невалиднÑ\8b, и задокÑ\83менÑ\82иÑ\80Ñ\83еÑ\82 паÑ\80амеÑ\82Ñ\80 в *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* Ñ\81Ñ\85емÑ\8b OpenAPI.
-### Использовать `Query` как значение по умолчанию или добавить в `Annotated`
+### `Query` как значение по умолчанию или внутри `Annotated` { #query-as-the-default-value-or-in-annotated }
-Ð\9aогда `Query` иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80и `Annotated`, вÑ\8b не можеÑ\82е иÑ\81полÑ\8cзовать параметр `default` у `Query`.
+Ð\9fомниÑ\82е, Ñ\87Ñ\82о пÑ\80и иÑ\81полÑ\8cзовании `Query` внÑ\83Ñ\82Ñ\80и `Annotated` нелÑ\8cзÑ\8f Ñ\83казÑ\8bвать параметр `default` у `Query`.
-Вместо этого, используйте обычное указание значения по умолчанию для параметра функции. Иначе, это будет несовместимо.
+Вместо этого используйте обычное значение по умолчанию параметра функции. Иначе это будет неоднозначно.
-СледÑ\83Ñ\8eÑ\89ий пÑ\80имеÑ\80 не Ñ\80абоÑ\87ий:
+Ð\9dапÑ\80имеÑ\80, Ñ\82ак делаÑ\82Ñ\8c нелÑ\8cзÑ\8f:
```Python
q: Annotated[str, Query(default="rick")] = "morty"
```
-...поÑ\82омÑ\83 Ñ\87Ñ\82о нелÑ\8cзÑ\8f однознаÑ\87но опÑ\80еделиÑ\82Ñ\8c, Ñ\87Ñ\82о именно должно бÑ\8bÑ\82Ñ\8c знаÑ\87ением по умолчанию: `"rick"` или `"morty"`.
+...поÑ\82омÑ\83 Ñ\87Ñ\82о непонÑ\8fÑ\82но, какое знаÑ\87ение должно бÑ\8bÑ\82Ñ\8c по умолчанию: `"rick"` или `"morty"`.
-Ð\92ам Ñ\81ледÑ\83еÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c (предпочтительно):
+СледоваÑ\82елÑ\8cно, иÑ\81полÑ\8cзÑ\83йÑ\82е (предпочтительно):
```Python
q: Annotated[str, Query()] = "rick"
```
-...или как в Ñ\81Ñ\82аÑ\80ом коде, коÑ\82оÑ\80Ñ\8bй вам можеÑ\82 попаÑ\81Ñ\82Ñ\8cÑ\81Ñ\8f:
+...или в Ñ\81Ñ\82аÑ\80ой кодовой базе вÑ\8b Ñ\83видиÑ\82е:
```Python
q: str = Query(default="rick")
```
-### Преимущества `Annotated`
+### Преимущества `Annotated` { #advantages-of-annotated }
-**РекомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Annotated`** вмеÑ\81Ñ\82о знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e в паÑ\80амеÑ\82Ñ\80аÑ\85 Ñ\84Ñ\83нкÑ\86ии, поÑ\82омÑ\83 Ñ\87Ñ\82о так **лучше** по нескольким причинам. 🤓
+**РекомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Annotated`** вмеÑ\81Ñ\82о заданиÑ\8f знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e в паÑ\80амеÑ\82Ñ\80аÑ\85 Ñ\84Ñ\83нкÑ\86ии â\80\94 так **лучше** по нескольким причинам. 🤓
-Значение **по умолчанию** у **параметров функции** - это **действительно значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌
+**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
-Ð\92Ñ\8b можеÑ\82е **вÑ\8bзваÑ\82Ñ\8c** Ñ\82Ñ\83 же Ñ\84Ñ\83нкÑ\86иÑ\8e в **инÑ\8bÑ\85 меÑ\81Ñ\82аÑ\85** без FastAPI, и она **Ñ\81Ñ\80абоÑ\82аеÑ\82 как ожидаеÑ\82Ñ\81Ñ\8f**. Ð\95Ñ\81ли Ñ\8dÑ\82о **обÑ\8fзаÑ\82елÑ\8cнÑ\8bй** паÑ\80амеÑ\82Ñ\80 (без знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e), ваÑ\88 **Ñ\80едакÑ\82оÑ\80 кода** Ñ\81ообÑ\89иÑ\82 об оÑ\88ибке. **Python** Ñ\82акже Ñ\83кажеÑ\82 на оÑ\88ибкÑ\83, еÑ\81ли вÑ\8b вÑ\8bзовеÑ\82е Ñ\84Ñ\83нкÑ\86иÑ\8e без пеÑ\80едаÑ\87и ей обязательного параметра.
+Ð\92Ñ\8b можеÑ\82е **вÑ\8bзваÑ\82Ñ\8c** Ñ\8dÑ\82Ñ\83 же Ñ\84Ñ\83нкÑ\86иÑ\8e в **дÑ\80Ñ\83гиÑ\85 меÑ\81Ñ\82аÑ\85** без FastAPI, и она бÑ\83деÑ\82 **Ñ\80абоÑ\82аÑ\82Ñ\8c как ожидаеÑ\82Ñ\81Ñ\8f**. Ð\95Ñ\81ли еÑ\81Ñ\82Ñ\8c **обÑ\8fзаÑ\82елÑ\8cнÑ\8bй** паÑ\80амеÑ\82Ñ\80 (без знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e), ваÑ\88 **Ñ\80едакÑ\82оÑ\80 кода** Ñ\81ообÑ\89иÑ\82 об оÑ\88ибке, **Python** Ñ\82оже пожалÑ\83еÑ\82Ñ\81Ñ\8f, еÑ\81ли вÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82е еÑ\91 без пеÑ\80едаÑ\87и обязательного параметра.
-Ð\95Ñ\81ли вÑ\8b вмеÑ\81Ñ\82о `Annotated` иÑ\81полÑ\8cзÑ\83еÑ\82е **(Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ий) Ñ\81Ñ\82илÑ\8c знаÑ\87ений по Ñ\83молÑ\87аниÑ\8e**, Ñ\82огда пÑ\80и вÑ\8bзове Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии без FastAPI в **дÑ\80Ñ\83гом меÑ\81Ñ\82е** вам необÑ\85одимо **помниÑ\82Ñ\8c** о пеÑ\80едаÑ\87е аÑ\80гÑ\83менÑ\82ов Ñ\84Ñ\83нкÑ\86ии, Ñ\87Ñ\82обÑ\8b она Ñ\80абоÑ\82ала коÑ\80Ñ\80екÑ\82но. Ð\92 пÑ\80оÑ\82ивном Ñ\81лÑ\83Ñ\87ае, знаÑ\87ениÑ\8f бÑ\83дÑ\83Ñ\82 оÑ\82лиÑ\87аÑ\82Ñ\8cÑ\81Ñ\8f оÑ\82 Ñ\82еÑ\85, Ñ\87Ñ\82о вÑ\8b ожидаеÑ\82е (напÑ\80имеÑ\80, `QueryInfo` или Ñ\87Ñ\82о-Ñ\82о подобное вмеÑ\81Ñ\82о `str`). Ð\98 ни ваÑ\88 Ñ\80едакÑ\82оÑ\80 кода, ни Python не бÑ\83дÑ\83Ñ\82 жаловаÑ\82Ñ\8cÑ\81Ñ\8f на Ñ\80абоÑ\82Ñ\83 Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии, Ñ\82олÑ\8cко когда вÑ\8bÑ\87иÑ\81лениÑ\8f внÑ\83Ñ\82Ñ\80и дадÑ\83Ñ\82 Ñ\81бой.
+Ð\95Ñ\81ли вÑ\8b не иÑ\81полÑ\8cзÑ\83еÑ\82е `Annotated`, а пÑ\80именÑ\8fеÑ\82е **(Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ий) Ñ\81Ñ\82илÑ\8c Ñ\81о знаÑ\87ением по Ñ\83молÑ\87аниÑ\8e**, Ñ\82о пÑ\80и вÑ\8bзове Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии без FastAPI в **дÑ\80Ñ\83гиÑ\85 меÑ\81Ñ\82аÑ\85** вам нÑ\83жно **помниÑ\82Ñ\8c** о Ñ\82ом, Ñ\87Ñ\82о надо пеÑ\80едаÑ\82Ñ\8c аÑ\80гÑ\83менÑ\82Ñ\8b, Ñ\87Ñ\82обÑ\8b вÑ\81Ñ\91 Ñ\80абоÑ\82ало коÑ\80Ñ\80екÑ\82но, инаÑ\87е знаÑ\87ениÑ\8f бÑ\83дÑ\83Ñ\82 не Ñ\82акими, как вÑ\8b ожидаеÑ\82е (напÑ\80имеÑ\80, вмеÑ\81Ñ\82о `str` бÑ\83деÑ\82 `QueryInfo` или Ñ\87Ñ\82о-Ñ\82о подобное). Ð\98 ни Ñ\80едакÑ\82оÑ\80, ни Python не бÑ\83дÑ\83Ñ\82 Ñ\80Ñ\83гаÑ\82Ñ\8cÑ\81Ñ\8f пÑ\80и Ñ\81амом вÑ\8bзове Ñ\84Ñ\83нкÑ\86ии â\80\94 оÑ\88ибка пÑ\80оÑ\8fвиÑ\82Ñ\81Ñ\8f лиÑ\88Ñ\8c пÑ\80и опеÑ\80аÑ\86иÑ\8fÑ\85 внÑ\83Ñ\82Ñ\80и.
-Так как `Annotated` может принимать более одной аннотации метаданных, то теперь вы можете использовать ту же функцию с другими инструментами, например <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
+Так как `Annotated` может содержать больше одной аннотации метаданных, теперь вы можете использовать ту же функцию и с другими инструментами, например с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
-## Ð\91олÑ\8cÑ\88е валидаÑ\86ии
+## Ð\91олÑ\8cÑ\88е валидаÑ\86ий { #add-more-validations }
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е добавить параметр `min_length`:
+Ð\9cожно Ñ\82акже добавить параметр `min_length`:
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
-## Регулярные выражения
+## Регулярные выражения { #add-regular-expressions }
-Вы можете определить <abbr title="Регулярное выражение, regex или regexp - это последовательность символов, определяющая шаблон для строк.">регулярное выражение</abbr>, которому должен соответствовать параметр:
+Вы можете определить <abbr title="Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
-Данное регулярное выражение проверяет, что полученное значение параметра:
+Данный шаблон регулярного выражения проверяет, что полученное значение параметра:
-* `^`: наÑ\87ало Ñ\81Ñ\82Ñ\80оки.
-* `fixedquery`: в Ñ\82оÑ\87ноÑ\81Ñ\82и Ñ\81одеÑ\80жиÑ\82 Ñ\81Ñ\82Ñ\80окÑ\83 `fixedquery`.
-* `$`: конеÑ\86 Ñ\81Ñ\82Ñ\80оки, не имееÑ\82 Ñ\81имволов поÑ\81ле `fixedquery`.
+* `^`: наÑ\87инаеÑ\82Ñ\81Ñ\8f Ñ\81 Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ñ\81имволов, до ниÑ\85 неÑ\82 Ñ\81имволов.
+* `fixedquery`: имееÑ\82 Ñ\82оÑ\87ное знаÑ\87ение `fixedquery`.
+* `$`: заканÑ\87иваеÑ\82Ñ\81Ñ\8f здеÑ\81Ñ\8c, поÑ\81ле `fixedquery` неÑ\82 никакиÑ\85 Ñ\81имволов.
-Ð\9dе пеÑ\80еживайÑ\82е, еÑ\81ли **"Ñ\80егÑ\83лÑ\8fÑ\80ное вÑ\8bÑ\80ажение"** вÑ\8bзÑ\8bваеÑ\82 Ñ\83 ваÑ\81 Ñ\82Ñ\80Ñ\83дноÑ\81Ñ\82и. ÐÑ\82о доÑ\81Ñ\82аÑ\82оÑ\87но Ñ\81ложнаÑ\8f Ñ\82ема длÑ\8f многиÑ\85 лÑ\8eдей. Ð\92Ñ\8b можеÑ\82е Ñ\81делаÑ\82Ñ\8c множеÑ\81Ñ\82во веÑ\89ей без иÑ\81полÑ\8cзованиÑ\8f Ñ\80егÑ\83лÑ\8fÑ\80нÑ\8bÑ\85 вÑ\8bÑ\80ажений.
+Ð\95Ñ\81ли вÑ\8b Ñ\82еÑ\80Ñ\8fеÑ\82еÑ\81Ñ\8c во вÑ\81еÑ\85 Ñ\8dÑ\82иÑ\85 идеÑ\8fÑ\85 пÑ\80о **«Ñ\80егÑ\83лÑ\8fÑ\80нÑ\8bе вÑ\8bÑ\80ажениÑ\8f»**, не пеÑ\80еживайÑ\82е. ÐÑ\82о Ñ\81ложнаÑ\8f Ñ\82ема длÑ\8f многиÑ\85. Ð\9cногое можно Ñ\81делаÑ\82Ñ\8c и без ниÑ\85.
-Ð\9dо когда они вам понадобÑ\8fÑ\82Ñ\81Ñ\8f, и вÑ\8b законÑ\87иÑ\82е иÑ\85 оÑ\81воение, Ñ\82о не бÑ\83деÑ\82 пÑ\80облемой использовать их в **FastAPI**.
+ТепеÑ\80Ñ\8c вÑ\8b знаеÑ\82е, Ñ\87Ñ\82о когда они понадобÑ\8fÑ\82Ñ\81Ñ\8f, вÑ\8b Ñ\81можеÑ\82е использовать их в **FastAPI**.
-## Значения по умолчанию
+### `regex` из Pydantic v1 вместо `pattern` { #pydantic-v1-regex-instead-of-pattern }
-Ð\92Ñ\8b Ñ\82оÑ\87но Ñ\82акже можеÑ\82е Ñ\83казаÑ\82Ñ\8c лÑ\8eбое знаÑ\87ение `по Ñ\83молÑ\87аниÑ\8e`, как Ñ\80анее Ñ\83казÑ\8bвали `None`.
+Ð\94о Pydantic веÑ\80Ñ\81ии 2 и до FastAPI 0.100.0 Ñ\8dÑ\82оÑ\82 паÑ\80амеÑ\82Ñ\80 назÑ\8bвалÑ\81Ñ\8f `regex`, а не `pattern`, но Ñ\81ейÑ\87аÑ\81 он Ñ\83Ñ\81Ñ\82аÑ\80ел.
-Например, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`:
+Вы всё ещё можете встретить такой код:
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
+
+////
+
+Имейте в виду, что это устарело, и код следует обновить на использование нового параметра `pattern`. 🤓
+
+## Значения по умолчанию { #default-values }
+
+Конечно, можно использовать и другие значения по умолчанию, не только `None`.
+
+Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`:
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
-/// note | ТеÑ\85ниÑ\87еÑ\81кие деÑ\82али
+/// note | Ð\9fÑ\80имеÑ\87ание
-Наличие значения по умолчанию делает параметр необязательным.
+Ð\9dалиÑ\87ие знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e лÑ\8eбого Ñ\82ипа, вклÑ\8eÑ\87аÑ\8f `None`, делаеÑ\82 паÑ\80амеÑ\82Ñ\80 необÑ\8fзаÑ\82елÑ\8cнÑ\8bм.
///
-## Ð\9eбÑ\8fзаÑ\82елÑ\8cнÑ\8bй паÑ\80амеÑ\82Ñ\80
+## Ð\9eбÑ\8fзаÑ\82елÑ\8cнÑ\8bе паÑ\80амеÑ\82Ñ\80Ñ\8b { #required-parameters }
-Ð\9aогда вам не Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f дополниÑ\82елÑ\8cнаÑ\8f валидаÑ\86иÑ\8f или дополниÑ\82елÑ\8cнÑ\8bе меÑ\82аданнÑ\8bе длÑ\8f паÑ\80амеÑ\82Ñ\80а запÑ\80оÑ\81а, вÑ\8b можеÑ\82е Ñ\81делаÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `q` обÑ\8fзаÑ\82елÑ\8cнÑ\8bм пÑ\80оÑ\81Ñ\82о не Ñ\83казÑ\8bваÑ\8f знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e. Ð\9dапример:
+Ð\9aогда не Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\8bе пÑ\80овеÑ\80ки или меÑ\82аданнÑ\8bе, можно Ñ\81делаÑ\82Ñ\8c query-паÑ\80амеÑ\82Ñ\80 `q` обÑ\8fзаÑ\82елÑ\8cнÑ\8bм, пÑ\80оÑ\81Ñ\82о не Ñ\83казÑ\8bваÑ\8f знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e, например:
```Python
q: str
вместо:
```Python
-q: Union[str, None] = None
-```
-
-Но у нас query-параметр определён как `Query`. Например:
-
-//// tab | Annotated
-
-```Python
-q: Annotated[Union[str, None], Query(min_length=3)] = None
+q: str | None = None
```
-////
-
-//// tab | без Annotated
+Но сейчас мы объявляем его через `Query`, например так:
```Python
-q: Union[str, None] = Query(default=None, min_length=3)
+q: Annotated[str | None, Query(min_length=3)] = None
```
-////
-
-В таком случае, чтобы сделать query-параметр `Query` обязательным, вы можете просто не указывать значение по умолчанию:
+Поэтому, когда вам нужно объявить значение как обязательное при использовании `Query`, просто не указывайте значение по умолчанию:
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
-### Обязательный параметр с `None`
+### Обязательный, но может быть `None` { #required-can-be-none }
-Ð\92Ñ\8b можеÑ\82е опÑ\80еделиÑ\82Ñ\8c, Ñ\87Ñ\82о паÑ\80амеÑ\82Ñ\80 можеÑ\82 пÑ\80инимаÑ\82Ñ\8c `None`, но вÑ\81Ñ\91 еÑ\89Ñ\91 Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f обÑ\8fзаÑ\82елÑ\8cнÑ\8bм. ÐÑ\82о можеÑ\82 поÑ\82Ñ\80ебоваÑ\82Ñ\8cÑ\81Ñ\8f длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b полÑ\8cзоваÑ\82ели Ñ\8fвно Ñ\83казали паÑ\80амеÑ\82Ñ\80, даже еÑ\81ли его знаÑ\87ение бÑ\83деÑ\82 `None`.
+Ð\9cожно обÑ\8aÑ\8fвиÑ\82Ñ\8c, Ñ\87Ñ\82о паÑ\80амеÑ\82Ñ\80 можеÑ\82 пÑ\80инимаÑ\82Ñ\8c `None`, но пÑ\80и Ñ\8dÑ\82ом оÑ\81Ñ\82аÑ\91Ñ\82Ñ\81Ñ\8f обÑ\8fзаÑ\82елÑ\8cнÑ\8bм. ÐÑ\82о заÑ\81Ñ\82авиÑ\82 клиенÑ\82ов оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c знаÑ\87ение, даже еÑ\81ли Ñ\8dÑ\82о знаÑ\87ение â\80\94 `None`.
-ЧÑ\82обÑ\8b Ñ\8dÑ\82ого добиÑ\82Ñ\8cÑ\81Ñ\8f, вам нÑ\83жно опÑ\80еделиÑ\82Ñ\8c `None` как валиднÑ\8bй Ñ\82ип длÑ\8f паÑ\80амеÑ\82Ñ\80а запÑ\80оÑ\81а, но Ñ\82акже Ñ\83казаÑ\82Ñ\8c `default=...`:
+Ð\94лÑ\8f Ñ\8dÑ\82ого обÑ\8aÑ\8fвиÑ\82е, Ñ\87Ñ\82о `None` â\80\94 валиднÑ\8bй Ñ\82ип, но пÑ\80оÑ\81Ñ\82о не задавайÑ\82е знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e:
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
-/// tip | Подсказка
-
-Pydantic, мощь которого используется в FastAPI для валидации и сериализации, имеет специальное поведение для `Optional` или `Union[Something, None]` без значения по умолчанию. Вы можете узнать об этом больше в документации Pydantic, раздел <a href="https://docs.pydantic.dev/latest/concepts/models/#required-optional-fields" class="external-link" target="_blank">Обязательные Опциональные поля</a>.
-
-///
-
-## Множество значений для query-параметра
+## Query-параметр - список / несколько значений { #query-parameter-list-multiple-values }
-Ð\94лÑ\8f query-паÑ\80амеÑ\82Ñ\80а `Query` можно Ñ\83казаÑ\82Ñ\8c, Ñ\87Ñ\82о он пÑ\80инимаеÑ\82 Ñ\81пиÑ\81ок знаÑ\87ений (множеÑ\81Ñ\82во знаÑ\87ений).
+Ð\9aогда вÑ\8b Ñ\8fвно обÑ\8aÑ\8fвлÑ\8fеÑ\82е query-паÑ\80амеÑ\82Ñ\80 Ñ\87еÑ\80ез `Query`, можно Ñ\82акже Ñ\83казаÑ\82Ñ\8c, Ñ\87Ñ\82о он пÑ\80инимаеÑ\82 Ñ\81пиÑ\81ок знаÑ\87ений, инаÑ\87е говоÑ\80Ñ\8f â\80\94 неÑ\81колÑ\8cко знаÑ\87ений.
-Например, query-параметр `q` может быть указан в URL несколько раз. И если вы ожидаете такой формат запроса, то можете указать это следующим образом:
+Например, чтобы объявить query-параметр `q`, который может встречаться в URL несколько раз, можно написать:
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
-Ð\97аÑ\82ем, полÑ\83Ñ\87ив Ñ\82акой URL:
+Тогда пÑ\80и Ñ\82аком URL:
```
http://localhost:8000/items/?q=foo&q=bar
```
-вÑ\8b бÑ\8b полÑ\83Ñ\87или неÑ\81колÑ\8cко знаÑ\87ений (`foo` и `bar`), коÑ\82оÑ\80Ñ\8bе оÑ\82ноÑ\81Ñ\8fÑ\82Ñ\81Ñ\8f к паÑ\80амеÑ\82Ñ\80Ñ\83 `q`, в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
+вÑ\8b полÑ\83Ñ\87иÑ\82е множеÑ\81Ñ\82веннÑ\8bе знаÑ\87ениÑ\8f query-паÑ\80амеÑ\82Ñ\80а `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
Таким образом, ответ на этот URL будет:
}
```
-/// tip | Ð\9fодÑ\81казка
+/// tip | СовеÑ\82
-ЧÑ\82обÑ\8b обÑ\8aÑ\8fвиÑ\82Ñ\8c query-паÑ\80амеÑ\82Ñ\80 Ñ\82ипом `list`, как в пÑ\80имеÑ\80е вÑ\8bÑ\88е, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
+ЧÑ\82обÑ\8b обÑ\8aÑ\8fвиÑ\82Ñ\8c query-паÑ\80амеÑ\82Ñ\80 Ñ\82ипа `list`, как в пÑ\80имеÑ\80е вÑ\8bÑ\88е, нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
///
-Ð\98нÑ\82еÑ\80акÑ\82ивнаÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f API бÑ\83деÑ\82 обновлена Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89им обÑ\80азом, где бÑ\83деÑ\82 Ñ\80азÑ\80еÑ\88ено множеÑ\81Ñ\82во значений:
+Ð\98нÑ\82еÑ\80акÑ\82ивнаÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f API обновиÑ\82Ñ\81Ñ\8f Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89им обÑ\80азом и позволиÑ\82 пеÑ\80едаваÑ\82Ñ\8c неÑ\81колÑ\8cко значений:
<img src="/img/tutorial/query-params-str-validations/image02.png">
-### Query-параметр со множеством значений по умолчанию
+### Query-параметр - список / несколько значений со значением по умолчанию { #query-parameter-list-multiple-values-with-defaults }
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е Ñ\83казаÑ\82Ñ\8c Ñ\82ип `list` Ñ\81о Ñ\81пиÑ\81ком знаÑ\87ений по Ñ\83молÑ\87аниÑ\8e на Ñ\81лÑ\83Ñ\87ай, еÑ\81ли вам иÑ\85 не пÑ\80едоÑ\81Ñ\82авÑ\8fÑ\82:
+Ð\9cожно Ñ\82акже опÑ\80еделиÑ\82Ñ\8c знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e как `list`, еÑ\81ли ниÑ\87его не пеÑ\80едано:
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
-Если вы перейдёте по ссылке:
+Если вы перейдёте по адресу:
```
http://localhost:8000/items/
```
-значение по умолчанию для `q` будет: `["foo", "bar"]` и ответом для вас будет:
+значение по умолчанию для `q` будет: `["foo", "bar"]`, и ответом будет:
```JSON
{
}
```
-#### Ð\98Ñ\81полÑ\8cзование `list`
+#### Ð\9fÑ\80оÑ\81Ñ\82о `list` { #using-just-list }
-Ð\92Ñ\8b Ñ\82акже можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c `list` напÑ\80Ñ\8fмÑ\83Ñ\8e вмеÑ\81Ñ\82о `List[str]` (или `list[str]` в Python 3.9+):
+Ð\9cожно иÑ\81полÑ\8cзоваÑ\82Ñ\8c `list` напÑ\80Ñ\8fмÑ\83Ñ\8e вмеÑ\81Ñ\82о `list[str]`:
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note | Технические детали
-Ð\97апомниÑ\82е, Ñ\87Ñ\82о в Ñ\82аком Ñ\81лÑ\83Ñ\87ае, FastAPI не будет проверять содержимое списка.
+Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о в Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае FastAPI не будет проверять содержимое списка.
-Например, для List[int] список будет провалидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
+Например, `list[int]` проверит (и задокументирует), что элементы списка — целые числа. А просто `list` — нет.
///
-## Больше метаданных
+## Больше метаданных { #declare-more-metadata }
-Ð\92Ñ\8b можеÑ\82е добавиÑ\82Ñ\8c болÑ\8cÑ\88е инÑ\84оÑ\80маÑ\86ии об query-параметре.
+Ð\9cожно добавиÑ\82Ñ\8c болÑ\8cÑ\88е инÑ\84оÑ\80маÑ\86ии о параметре.
-УказаннаÑ\8f инÑ\84оÑ\80маÑ\86иÑ\8f бÑ\83деÑ\82 вклÑ\8eÑ\87ена в генеÑ\80иÑ\80Ñ\83емÑ\83Ñ\8e OpenAPI докÑ\83менÑ\82аÑ\86иÑ\8e и иÑ\81полÑ\8cзована в полÑ\8cзоваÑ\82елÑ\8cÑ\81ком инÑ\82еÑ\80Ñ\84ейÑ\81е и внеÑ\88ниÑ\85 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82аÑ\85.
+ÐÑ\82а инÑ\84оÑ\80маÑ\86иÑ\8f бÑ\83деÑ\82 вклÑ\8eÑ\87ена в Ñ\81генеÑ\80иÑ\80ованнÑ\83Ñ\8e OpenAPI-Ñ\81Ñ\85емÑ\83 и иÑ\81полÑ\8cзована инÑ\82еÑ\80Ñ\84ейÑ\81ами докÑ\83менÑ\82аÑ\86ии и внеÑ\88ними инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ами.
/// note | Технические детали
-Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о Ñ\80азнÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b могÑ\83Ñ\82 имеÑ\82Ñ\8c Ñ\80азнÑ\8bе Ñ\83Ñ\80овни поддержки OpenAPI.
+Ð\9fомниÑ\82е, Ñ\87Ñ\82о Ñ\80азнÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b могÑ\83Ñ\82 имеÑ\82Ñ\8c Ñ\80азнÑ\8bй Ñ\83Ñ\80овенÑ\8c поддержки OpenAPI.
-Ð\9dекоÑ\82оÑ\80Ñ\8bе из ниÑ\85 могÑ\83Ñ\82 не оÑ\82обÑ\80ажаÑ\82Ñ\8c (на даннÑ\8bй моменÑ\82) вÑ\81Ñ\8e заÑ\8fвленнÑ\83Ñ\8e дополниÑ\82елÑ\8cнÑ\83Ñ\8e инÑ\84оÑ\80маÑ\86иÑ\8e, Ñ\85оÑ\82Ñ\8f в болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев оÑ\82Ñ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89аÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f уже запланирована к разработке.
+Ð\9dекоÑ\82оÑ\80Ñ\8bе из ниÑ\85 пока могÑ\83Ñ\82 не показÑ\8bваÑ\82Ñ\8c вÑ\81Ñ\8e дополниÑ\82елÑ\8cнÑ\83Ñ\8e инÑ\84оÑ\80маÑ\86иÑ\8e, Ñ\85оÑ\82Ñ\8f в болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев недоÑ\81Ñ\82аÑ\8eÑ\89аÑ\8f возможноÑ\81Ñ\82Ñ\8c уже запланирована к разработке.
///
-Ð\92Ñ\8b можеÑ\82е Ñ\83казаÑ\82Ñ\8c название query-паÑ\80амеÑ\82Ñ\80а, иÑ\81полÑ\8cзÑ\83Ñ\8f паÑ\80амеÑ\82Ñ\80 `title`:
+Ð\9cожно задаÑ\82Ñ\8c `title`:
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
-Ð\94обавиÑ\82Ñ\8c опиÑ\81ание, иÑ\81полÑ\8cзÑ\83Ñ\8f паÑ\80амеÑ\82Ñ\80 `description`:
+Ð\98 `description`:
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
-## Псевдонимы параметров
+## Псевдонимы параметров { #alias-parameters }
-Представьте, что вы хотите использовать query-параметр с названием `item-query`.
+Представьте, что вы хотите, чтобы параметр назывался `item-query`.
Например:
http://127.0.0.1:8000/items/?item-query=foobaritems
```
-Но `item-query` является невалидным именем переменной в Python.
+Но `item-query` — недопустимое имя переменной в Python.
-Ð\9dаиболее поÑ\85ожее валидное имÑ\8f `item_query`.
+Ð\91лижайÑ\88ий ваÑ\80ианÑ\82 â\80\94 `item_query`.
-Но вам всё равно необходим `item-query`...
+Но вам всё равно нужно именно `item-query`...
-Тогда вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c `пÑ\81евдоним`, и Ñ\8dÑ\82оÑ\82 пÑ\81евдоним бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f длÑ\8f поиÑ\81ка знаÑ\87ениÑ\8f паÑ\80амеÑ\82Ñ\80а запÑ\80оÑ\81а:
+Тогда можно обÑ\8aÑ\8fвиÑ\82Ñ\8c `alias`, и Ñ\8dÑ\82оÑ\82 пÑ\81евдоним бÑ\83деÑ\82 иÑ\81полÑ\8cзован длÑ\8f поиÑ\81ка знаÑ\87ениÑ\8f паÑ\80амеÑ\82Ñ\80а:
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
-## УÑ\81Ñ\82аÑ\80евÑ\88ие паÑ\80амеÑ\82Ñ\80Ñ\8b
+## Ð\9cаÑ\80киÑ\80овка паÑ\80амеÑ\82Ñ\80ов как Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88иÑ\85 { #deprecating-parameters }
-Предположим, вы больше не хотите использовать какой-либо параметр.
+Предположим, этот параметр вам больше не нравится.
-Ð\92Ñ\8b Ñ\80еÑ\88или оÑ\81Ñ\82авиÑ\82Ñ\8c его, поÑ\82омÑ\83 Ñ\87Ñ\82о клиенÑ\82Ñ\8b вÑ\81Ñ\91 еÑ\89Ñ\91 им полÑ\8cзÑ\83Ñ\8eÑ\82Ñ\81Ñ\8f. Ð\9dо вÑ\8b Ñ\85оÑ\82иÑ\82е оÑ\82обÑ\80азиÑ\82Ñ\8c Ñ\8dÑ\82о в докÑ\83менÑ\82аÑ\86ии как <abbr title="Ñ\83Ñ\81Ñ\82аÑ\80ело, не Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c">Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ий Ñ\84Ñ\83нкÑ\86ионал</abbr>.
+Ð\95го нÑ\83жно оÑ\81Ñ\82авиÑ\82Ñ\8c на какоеâ\80\91Ñ\82о вÑ\80емÑ\8f, Ñ\82ак как клиенÑ\82Ñ\8b его иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82, но вÑ\8b Ñ\85оÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b в докÑ\83менÑ\82аÑ\86ии он Ñ\8fвно оÑ\82обÑ\80ажалÑ\81Ñ\8f как <abbr title="Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ий, не Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c">Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ий</abbr>.
-Тогда длÑ\8f `Query` Ñ\83кажиÑ\82е паÑ\80амеÑ\82Ñ\80 `deprecated=True`:
+Тогда пеÑ\80едайÑ\82е паÑ\80амеÑ\82Ñ\80 `deprecated=True` в `Query`:
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
-Ð\92 докÑ\83менÑ\82аÑ\86ии Ñ\8dÑ\82о бÑ\83деÑ\82 оÑ\82обÑ\80ажено Ñ\81ледÑ\83Ñ\8eÑ\89им обÑ\80азом:
+Ð\92 докÑ\83менÑ\82аÑ\86ии Ñ\8dÑ\82о бÑ\83деÑ\82 показано Ñ\82ак:
<img src="/img/tutorial/query-params-str-validations/image01.png">
-## Ð\98Ñ\81клÑ\8eÑ\87иÑ\82Ñ\8c из OpenAPI
+## Ð\98Ñ\81клÑ\8eÑ\87иÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80Ñ\8b из OpenAPI { #exclude-parameters-from-openapi }
-Чтобы исключить query-параметр из генерируемой OpenAPI схемы (а также из системы автоматической генерации документации), укажите в `Query` параметр `include_in_schema=False`:
+Чтобы исключить query-параметр из генерируемой OpenAPI-схемы (и, следовательно, из систем автоматической документации), укажите у `Query` параметр `include_in_schema=False`:
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
-## Резюме
+## Кастомная валидация { #custom-validation }
+
+Бывают случаи, когда нужна **кастомная валидация**, которую нельзя выразить параметрами выше.
+
+В таких случаях можно использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки, что значение — это `str`).
+
+Этого можно добиться, используя <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` Pydantic</a> внутри `Annotated`.
+
+/// tip | Совет
+
+В Pydantic также есть <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> и другие. 🤓
+
+///
+
+Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number – Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) — веб‑сайт с информацией о фильмах">IMDB</abbr>:
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
+
+/// info | Дополнительная информация
+
+Это доступно в Pydantic версии 2 и выше. 😎
+
+///
+
+/// tip | Совет
+
+Если вам нужна валидация, требующая общения с каким‑либо **внешним компонентом** — базой данных или другим API — вместо этого используйте **Зависимости FastAPI** (FastAPI Dependencies), вы познакомитесь с ними позже.
+
+Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в запросе.
+
+///
+
+### Понимание этого кода { #understand-that-code }
+
+Важный момент — это использовать **`AfterValidator` с функцией внутри `Annotated`**. Смело пропускайте эту часть. 🤸
+
+---
+
+Но если вам любопытен именно этот пример и всё ещё интересно, вот немного подробностей.
+
+#### Строка и `value.startswith()` { #string-with-value-startswith }
-Ð\92Ñ\8b можеÑ\82е обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c дополниÑ\82елÑ\8cнÑ\8bе пÑ\80авила валидаÑ\86ии и меÑ\82аданнÑ\8bе длÑ\8f ваÑ\88иÑ\85 паÑ\80амеÑ\82Ñ\80ов запÑ\80оÑ\81а.
+Ð\97амеÑ\82или? Ð\9cеÑ\82од Ñ\81Ñ\82Ñ\80оки `value.startswith()` можеÑ\82 пÑ\80инимаÑ\82Ñ\8c коÑ\80Ñ\82еж â\80\94 Ñ\82огда бÑ\83деÑ\82 пÑ\80овеÑ\80ено каждое знаÑ\87ение из коÑ\80Ñ\82ежа:
-Общие метаданные:
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
+
+#### Случайный элемент { #a-random-item }
+
+С помощью `data.items()` мы получаем <abbr title="Объект, по которому можно итерироваться циклом for, например список, множество и т. п.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
+
+Мы превращаем этот итерируемый объект в обычный `list` через `list(data.items())`.
+
+Затем с `random.choice()` можно получить **случайное значение** из списка — то есть кортеж вида `(id, name)`. Это будет что‑то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
+
+После этого мы **распаковываем** эти два значения кортежа в переменные `id` и `name`.
+
+Так что, если пользователь не передал ID элемента, он всё равно получит случайную рекомендацию.
+
+...и всё это в **одной простой строке**. 🤯 Разве не прекрасен Python? 🐍
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
+
+## Резюме { #recap }
+
+Вы можете объявлять дополнительные проверки и метаданные для параметров.
+
+Общие метаданные и настройки:
* `alias`
* `title`
* `description`
* `deprecated`
-* `include_in_schema`
-СпеÑ\86иÑ\84иÑ\87нÑ\8bе пÑ\80авила валидаÑ\86ии для строк:
+Ð\9fÑ\80овеÑ\80ки, Ñ\81пеÑ\86иÑ\84иÑ\87нÑ\8bе для строк:
* `min_length`
* `max_length`
-* `regex`
+* `pattern`
+
+Кастомные проверки с использованием `AfterValidator`.
-Ð\92 Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80еннÑ\8bÑ\85 пÑ\80имеÑ\80аÑ\85 показано обÑ\8aÑ\8fвление пÑ\80авил валидаÑ\86ии длÑ\8f Ñ\81Ñ\82Ñ\80оковÑ\8bÑ\85 знаÑ\87ений `str`.
+Ð\92 Ñ\8dÑ\82иÑ\85 пÑ\80имеÑ\80аÑ\85 вÑ\8b видели, как обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c пÑ\80овеÑ\80ки длÑ\8f знаÑ\87ений Ñ\82ипа `str`.
-Ð\92 Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 главаÑ\85 вÑ\8b Ñ\83видеÑ\82е, как обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c пÑ\80авила валидаÑ\86ии длÑ\8f дÑ\80Ñ\83гиÑ\85 Ñ\82ипов (напÑ\80имеÑ\80, Ñ\87иÑ\81ел).
+СмоÑ\82Ñ\80иÑ\82е Ñ\81ледÑ\83Ñ\8eÑ\89ие главÑ\8b, Ñ\87Ñ\82обÑ\8b Ñ\83знаÑ\82Ñ\8c, как обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c пÑ\80овеÑ\80ки длÑ\8f дÑ\80Ñ\83гиÑ\85 Ñ\82ипов, напÑ\80имеÑ\80 Ñ\87иÑ\81ел.
-# Query-параметры
+# Query-параметры { #query-parameters }
-Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
+Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
{* ../../docs_src/query_params/tutorial001.py hl[9] *}
Будучи частью URL-адреса, они "по умолчанию" являются строками.
-Но когда вы объявляете их с использованием аннотаций (в примере выше, как `int`), они конвертируются в указанный тип данных и проходят проверку на соответствие ему.
+Но когда вы объявляете их с использованием типов Python (в примере выше, как `int`), они конвертируются в указанный тип данных и проходят проверку на соответствие ему.
Все те же правила, которые применяются к path-параметрам, также применяются и query-параметрам:
* Проверка на соответствие данных (Валидация)
* Автоматическая документация
-## Значения по умолчанию
+## Значения по умолчанию { #defaults }
Поскольку query-параметры не являются фиксированной частью пути, они могут быть не обязательными и иметь значения по умолчанию.
* `skip=20`: потому что вы установили это в URL-адресе
* `limit=10`: т.к это было значение по умолчанию
-## Необязательные параметры
+## Необязательные параметры { #optional-parameters }
Аналогично, вы можете объявлять необязательные query-параметры, установив их значение по умолчанию, равное `None`:
///
-## Преобразование типа параметра запроса
+## Преобразование типа параметра запроса { #query-parameter-type-conversion }
Вы также можете объявлять параметры с типом `bool`, которые будут преобразованы соответственно:
или в любом другом варианте написания (в верхнем регистре, с заглавной буквой, и т.п), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool` . В противном случае - `False`.
+## Смешивание query-параметров и path-параметров { #multiple-path-and-query-parameters }
-## Смешивание query-параметров и path-параметров
-
-Вы можете объявлять несколько query-параметров и path-параметров одновременно,**FastAPI** сам разберётся, что чем является.
+Вы можете объявлять несколько query-параметров и path-параметров одновременно, **FastAPI** сам разберётся, что чем является.
И вы не обязаны объявлять их в каком-либо определенном порядке.
{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
-## Обязательные query-параметры
+## Обязательные query-параметры { #required-query-parameters }
-Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе, мы пока что познакомились только с path-параметрами), то это значение не является обязательным.
+Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе, мы пока что познакомились только с path-параметрами), то он не является обязательным.
Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.
```JSON
{
- "detail": [
- {
- "loc": [
- "query",
- "needy"
- ],
- "msg": "field required",
- "type": "value_error.missing"
- }
- ]
+ "detail": [
+ {
+ "type": "missing",
+ "loc": [
+ "query",
+ "needy"
+ ],
+ "msg": "Field required",
+ "input": null
+ }
+ ]
}
```
}
```
-Конечно, вы можете определить некоторые параметры как обязательные, некоторые - со значением по умполчанию, а некоторые - полностью необязательные:
+Конечно, вы можете определить некоторые параметры как обязательные, некоторые — со значением по умолчанию, а некоторые — полностью необязательные:
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
/// tip | Подсказка
-Вы можете использовать класс `Enum` также, как ранее применяли его с [Path-параметрами](path-params.md#_7){.internal-link target=_blank}.
+Вы можете использовать класс `Enum` также, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values){.internal-link target=_blank}.
///
-# Загрузка файлов
+# Загрузка файлов { #request-files }
Используя класс `File`, мы можем позволить клиентам загружать файлы.
Чтобы получать загруженные файлы, сначала установите <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>.
-Ð\9dапÑ\80имеÑ\80: `pip install python-multipart`.
+УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b Ñ\81оздали [виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение](../virtual-environments.md){.internal-link target=_blank}, акÑ\82ивиÑ\80овали его, а заÑ\82ем Ñ\83Ñ\81Ñ\82ановили пакеÑ\82, напÑ\80имеÑ\80:
-Это связано с тем, что загружаемые файлы передаются как данные формы.
+```console
+$ pip install python-multipart
+```
+
+Это связано с тем, что загружаемые файлы передаются как "данные формы".
///
-## Импорт `File`
+## Импорт `File` { #import-file }
Импортируйте `File` и `UploadFile` из модуля `fastapi`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
-## Определите параметры `File`
+## Определите параметры `File` { #define-file-parameters }
Создайте параметры `File` так же, как вы это делаете для `Body` или `Form`:
Однако возможны случаи, когда использование `UploadFile` может оказаться полезным.
-## Ð\97агÑ\80Ñ\83зка Ñ\84айла Ñ\81 помоÑ\89Ñ\8cÑ\8e `UploadFile`
+## Ð\9fаÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\84айла Ñ\81 `UploadFile` { #file-parameters-with-uploadfile }
Определите параметр файла с типом `UploadFile`:
* Он реализует <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> `async` интерфейс.
* Он предоставляет реальный объект Python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> который вы можете передать непосредственно другим библиотекам, которые ожидают файл в качестве объекта.
-### `UploadFile`
+### `UploadFile` { #uploadfile }
`UploadFile` имеет следующие атрибуты:
* `content_type`: Строка `str` с типом содержимого (MIME type / media type) (например, `image/jpeg`).
* `file`: <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим файл в качестве объекта.
-`UploadFile` имеет следующие методы `async`. Все они вызывают соответствующие файловые методы (используя внутренний SpooledTemporaryFile).
+`UploadFile` имеет следующие методы `async`. Все они вызывают соответствующие файловые методы (используя внутренний `SpooledTemporaryFile`).
* `write(data)`: Записать данные `data` (`str` или `bytes`) в файл.
* `read(size)`: Прочитать количество `size` (`int`) байт/символов из файла.
* `seek(offset)`: Перейти к байту на позиции `offset` (`int`) в файле.
- * Наример, `await myfile.seek(0)` перейдет к началу файла.
+ * Например, `await myfile.seek(0)` перейдет к началу файла.
* Это особенно удобно, если вы один раз выполнили команду `await myfile.read()`, а затем вам нужно прочитать содержимое файла еще раз.
* `close()`: Закрыть файл.
contents = myfile.file.read()
```
+
/// note | Технические детали `async`
При использовании методов `async` **FastAPI** запускает файловые методы в пуле потоков и ожидает их.
///
-## Ð\9fÑ\80о даннÑ\8bе Ñ\84оÑ\80мÑ\8b ("Form Data")
+## ЧÑ\82о Ñ\82акое «даннÑ\8bе Ñ\84оÑ\80мÑ\8b» { #what-is-form-data }
Способ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, обычно использует "специальную" кодировку для этих данных, отличную от JSON.
Но когда форма включает файлы, она кодируется как multipart/form-data. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела.
-Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
+Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network – Сеть разработчиков Mozilla">MDN</abbr> web docs for <code>POST</code></a>.
///
///
-## Необязательная загрузка файлов
+## Необязательная загрузка файлов { #optional-file-upload }
Вы можете сделать загрузку файла необязательной, используя стандартные аннотации типов и установив значение по умолчанию `None`:
{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
-## `UploadFile` с дополнительными метаданными
+## `UploadFile` с дополнительными метаданными { #uploadfile-with-additional-metadata }
Вы также можете использовать `File()` вместе с `UploadFile`, например, для установки дополнительных метаданных:
{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
-## Загрузка нескольких файлов
+## Загрузка нескольких файлов { #multiple-file-uploads }
Можно одновременно загружать несколько файлов.
Вы получите, как и было объявлено, список `list` из `bytes` или `UploadFile`.
-/// note | Technical Details
+/// note | Технические детали
Можно также использовать `from starlette.responses import HTMLResponse`.
///
-### Загрузка нескольких файлов с дополнительными метаданными
+### Загрузка нескольких файлов с дополнительными метаданными { #multiple-file-uploads-with-additional-metadata }
Так же, как и раньше, вы можете использовать `File()` для задания дополнительных параметров, даже для `UploadFile`:
{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
-## Резюме
+## Резюме { #recap }
Используйте `File`, `bytes` и `UploadFile` для работы с файлами, которые будут загружаться и передаваться в виде данных формы.
-# Модели форм
+# Модели форм { #form-models }
-Вы можете использовать **Pydantic-модели** для объявления **полей форм** в FastAPI.
+Вы можете использовать **Pydantic-модели** для объявления **полей формы** в FastAPI.
/// info | Дополнительная информация
/// note | Заметка
-Этот функционал доступен с версии `0.113.0`. 🤓
+Этот функционал доступен начиная с версии FastAPI `0.113.0`. 🤓
///
-## Pydantic-модель для формы
+## Pydantic-модели для форм { #pydantic-models-for-forms }
Вам просто нужно объявить **Pydantic-модель** с полями, которые вы хотите получить как **поля формы**, а затем объявить параметр как `Form`:
**FastAPI** **извлечёт** данные для **каждого поля** из **данных формы** в запросе и выдаст вам объявленную Pydantic-модель.
-## Проверка сгенерированной документации
+## Проверьте документацию { #check-the-docs }
-Вы можете посмотреть поля формы в графическом интерфейсе Документации по пути `/docs`:
+Вы можете проверить это в интерфейсе документации по адресу `/docs`:
<div class="screenshot">
<img src="/img/tutorial/request-form-models/image01.png">
</div>
-## Запрет дополнительных полей формы
+## Запрет дополнительных полей формы { #forbid-extra-form-fields }
В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** поля формы только теми, которые объявлены в Pydantic-модели. И **запретить** любые **дополнительные** поля.
/// note | Заметка
-Этот функционал доступен с версии `0.114.0`. 🤓
+Этот функционал доступен начиная с версии FastAPI `0.114.0`. 🤓
///
}
```
-## Ð\97аклÑ\8eÑ\87ение
+## Ð\98Ñ\82оги { #summary }
Вы можете использовать Pydantic-модели для объявления полей форм в FastAPI. 😎
-# Файлы и формы в запросе
+# Файлы и формы в запросе { #request-forms-and-files }
Вы можете определять файлы и поля формы одновременно, используя `File` и `Form`.
-/// info | Ð\94ополниÑ\82елÑ\8cнаÑ\8f информация
+/// info | Ð\98нформация
Чтобы получать загруженные файлы и/или данные форм, сначала установите <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>.
-Например: `pip install python-multipart`.
+Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили пакет, например:
+
+```console
+$ pip install python-multipart
+```
///
-## Импортируйте `File` и `Form`
+## Импортируйте `File` и `Form` { #import-file-and-form }
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
-## Определите параметры `File` и `Form`
+## Определите параметры `File` и `Form` { #define-file-and-form-parameters }
Создайте параметры файла и формы таким же образом, как для `Body` или `Query`:
Файлы и поля формы будут загружены в виде данных формы, и вы получите файлы и поля формы.
-Вы можете объявить некоторые файлы как `bytes`, а некоторые - как `UploadFile`.
+Вы можете объявить некоторые файлы как `bytes`, а некоторые — как `UploadFile`.
/// warning | Внимание
-Вы можете объявить несколько параметров `File` и `Form` в операции *path*, но вы не можете также объявить поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с помощью `multipart/form-data` вместо `application/json`.
+Вы можете объявить несколько параметров `File` и `Form` в операции пути, но вы не можете также объявить поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с помощью `multipart/form-data` вместо `application/json`.
-Это не ограничение **Fast API**, это часть протокола HTTP.
+Это не ограничение **FastAPI**, это часть протокола HTTP.
///
-## Резюме
+## Резюме { #recap }
Используйте `File` и `Form` вместе, когда необходимо получить данные и файлы в одном запросе.
-# Данные формы
+# Данные формы { #form-data }
Когда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`.
Чтобы использовать формы, сначала установите <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>.
-Например, выполните команду `pip install python-multipart`.
+Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили пакет, например:
+
+```console
+$ pip install python-multipart
+```
///
-## Импорт `Form`
+## Импорт `Form` { #import-form }
Импортируйте `Form` из `fastapi`:
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
-## Определение параметров `Form`
+## Определение параметров `Form` { #define-form-parameters }
Создайте параметры формы так же, как это делается для `Body` или `Query`:
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
-Например, в одном из способов использования спецификации OAuth2 (называемом "потоком пароля") требуется отправить `username` и `password` в виде полей формы.
+Например, в одном из способов использования спецификации OAuth2 (называемом «потоком пароля») требуется отправить `username` и `password` в виде полей формы.
-Данный способ требует отправку данных для авторизации посредством формы (а не JSON) и обязательного наличия в форме строго именованных полей `username` и `password`.
+<abbr title="specification – спецификация">spec</abbr> требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON.
-Ð\92Ñ\8b можеÑ\82е наÑ\81Ñ\82Ñ\80оиÑ\82Ñ\8c `Form` Ñ\82оÑ\87но Ñ\82ак же, как наÑ\81Ñ\82Ñ\80аиваеÑ\82е и `Body` ( `Query`, `Path`, `Cookie`), вклÑ\8eÑ\87аÑ\8f валидаÑ\86ии, пÑ\80имеÑ\80Ñ\8b, пÑ\81евдонимÑ\8b (например, `user-name` вместо `username`) и т.д.
+С помоÑ\89Ñ\8cÑ\8e `Form` вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c Ñ\82е же наÑ\81Ñ\82Ñ\80ойки, Ñ\87Ñ\82о и Ñ\81 `Body` (и `Query`, `Path`, `Cookie`), вклÑ\8eÑ\87аÑ\8f валидаÑ\86иÑ\8e, пÑ\80имеÑ\80Ñ\8b, пÑ\81евдоним (например, `user-name` вместо `username`) и т.д.
/// info | Дополнительная информация
-`Form` - это класс, который наследуется непосредственно от `Body`.
+`Form` — это класс, который наследуется непосредственно от `Body`.
///
/// tip | Подсказка
-Ð\92ам необÑ\85одимо Ñ\8fвно Ñ\83казÑ\8bваÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `Form` пÑ\80и обÑ\8aÑ\8fвлении каждого полÑ\8f, инаÑ\87е полÑ\8f бÑ\83дÑ\83Ñ\82 инÑ\82еÑ\80пÑ\80еÑ\82иÑ\80оваÑ\82Ñ\8cÑ\81Ñ\8f как параметры запроса или параметры тела (JSON).
+ЧÑ\82обÑ\8b обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c даннÑ\8bе Ñ\84оÑ\80мÑ\8b, вам нÑ\83жно Ñ\8fвно иÑ\81полÑ\8cзоваÑ\82Ñ\8c `Form`, инаÑ\87е паÑ\80амеÑ\82Ñ\80Ñ\8b бÑ\83дÑ\83Ñ\82 инÑ\82еÑ\80пÑ\80еÑ\82иÑ\80ованÑ\8b как параметры запроса или параметры тела (JSON).
///
-## О "полях формы"
+## О «полях формы» { #about-form-fields }
-Обычно способ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, использует "специальное" кодирование для этих данных, отличное от JSON.
+Обычно способ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, использует «специальное» кодирование для этих данных, отличное от JSON.
-**FastAPI** гарантирует правильное чтение этих данных из соответствующего места, а не из JSON.
+**FastAPI** гарантирует, что эти данные будут прочитаны из нужного места, а не из JSON.
/// note | Технические детали
-Данные из форм обычно кодируются с использованием "типа медиа" `application/x-www-form-urlencoded`.
+Данные из форм обычно кодируются с использованием «типа содержимого» `application/x-www-form-urlencoded`.
-Ð\9dо когда Ñ\84оÑ\80ма Ñ\81одеÑ\80жиÑ\82 Ñ\84айлÑ\8b, она кодиÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f как `multipart/form-data`. Ð\92Ñ\8b Ñ\83знаеÑ\82е о Ñ\80абоÑ\82е Ñ\81 Ñ\84айлами в следующей главе.
+Ð\9dо когда Ñ\84оÑ\80ма Ñ\81одеÑ\80жиÑ\82 Ñ\84айлÑ\8b, она кодиÑ\80Ñ\83еÑ\82Ñ\81Ñ\8f как `multipart/form-data`. Ð\9e Ñ\80абоÑ\82е Ñ\81 Ñ\84айлами вÑ\8b пÑ\80оÑ\87Ñ\82Ñ\91Ñ\82е в следующей главе.
-Если вы хотите узнать больше про кодировки и поля формы, ознакомьтесь с <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank">документацией <abbr title="Mozilla Developer Network">MDN</abbr> для `POST` на веб-сайте</a>.
+Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network – Сеть разработчиков Mozilla">MDN</abbr> веб-документации для `POST`</a>.
///
/// warning | Предупреждение
-Вы можете объявлять несколько параметров `Form` в *операции пути*, но вы не можете одновременно с этим объявлять поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с использованием `application/x-www-form-urlencoded`, а не `application/json`.
+Вы можете объявлять несколько параметров `Form` в *операции пути*, но вы не можете одновременно объявлять поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с использованием `application/x-www-form-urlencoded`, а не `application/json`.
Это не ограничение **FastAPI**, это часть протокола HTTP.
///
-## Резюме
+## Резюме { #recap }
Используйте `Form` для объявления входных параметров данных формы.
-# Модель ответа - Возвращаемый тип
+# Модель ответа — Возвращаемый тип { #response-model-return-type }
-Вы можете объявить тип ответа, указав аннотацию **возвращаемого значения** для *функции операции пути*.
+Вы можете объявить тип, используемый для ответа, указав аннотацию **возвращаемого значения** для *функции-обработчика пути*.
-FastAPI позволяет использовать **аннотации типов** таким же способом, как и для ввода данных в **параметры** функции, вы можете использовать модели Pydantic, списки, словари, скалярные типы (такие, как int, bool и т.д.).
+Вы можете использовать **аннотации типов** так же, как и для входных данных в **параметрах** функции: Pydantic-модели, списки, словари, скалярные значения (целые числа, булевы и т.д.).
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
-FastAPI будет использовать этот возвращаемый тип для:
+FastAPI будет использовать этот тип ответа для:
-* **Ð\92алидаÑ\86ии** оÑ\82веÑ\82а.
- * Если данные невалидны (например, отсутствует одно из полей), это означает, что код *вашего* приложения работает некорректно и функция возвращает не то, что вы ожидаете. В таком случае приложение вернет server error вместо того, чтобы отправить неправильные данные. Таким образом, вы и ваши пользователи можете быть уверены, что получите корректные данные в том виде, в котором они ожидаются.
-* Добавьте **JSON схему** для ответа внутри *операции пути* OpenAPI.
- * Она будет использована для **автоматически генерируемой документации**.
- * А также - для автоматической кодогенерации пользователями.
+* **Ð\92алидаÑ\86ии** возвÑ\80аÑ\89аемÑ\8bÑ\85 даннÑ\8bÑ\85.
+ * Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру.
+* Добавления **JSON Schema** для ответа в OpenAPI *операции пути*.
+ * Это будет использовано **автоматической документацией**.
+ * Это также будет использовано инструментами автоматической генерации клиентского кода.
-Ð\9dо Ñ\81амое важное:
+Ð\9dо Ñ\81амое главное:
-* Ð\9eÑ\82веÑ\82 бÑ\83деÑ\82 **огÑ\80аниÑ\87ен и оÑ\82Ñ\84илÑ\8cÑ\82Ñ\80ован** - Ñ\82.е. в нем оÑ\81Ñ\82анÑ\83Ñ\82Ñ\81Ñ\8f Ñ\82олÑ\8cко Ñ\82е даннÑ\8bе, коÑ\82оÑ\80Ñ\8bе опÑ\80еделенÑ\8b в возвращаемом типе.
- * Это особенно важно для **безопасности**, далее мы рассмотрим эту тему подробнее.
+* Ð\92Ñ\8bÑ\85однÑ\8bе даннÑ\8bе бÑ\83дÑ\83Ñ\82 **огÑ\80аниÑ\87енÑ\8b и оÑ\82Ñ\84илÑ\8cÑ\82Ñ\80ованÑ\8b** в Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вии Ñ\81 Ñ\82ем, Ñ\87Ñ\82о опÑ\80еделено в возвращаемом типе.
+ * Это особенно важно для **безопасности**, ниже мы рассмотрим это подробнее.
-## Параметр `response_model`
+## Параметр `response_model` { #response-model-parameter }
-Бывают случаи, когда вам необходимо (или просто хочется) возвращать данные, которые не полностью соответствуют объявленному типу.
+Бывают случаи, когда вам нужно или хочется возвращать данные, которые не в точности соответствуют объявленному типу.
-Ð\94опÑ\83Ñ\81Ñ\82им, вÑ\8b Ñ\85оÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b ваÑ\88а Ñ\84Ñ\83нкÑ\86иÑ\8f **возвÑ\80аÑ\89ала Ñ\81ловаÑ\80Ñ\8c (dict)** или обÑ\8aекÑ\82 из базÑ\8b даннÑ\8bÑ\85, но пÑ\80и Ñ\8dÑ\82ом **обÑ\8aÑ\8fвлÑ\8fеÑ\82е вÑ\8bÑ\85одной Ñ\82ип как моделÑ\8c Pydantic**. Тогда именно Ñ\83казаннаÑ\8f моделÑ\8c бÑ\83деÑ\82 иÑ\81полÑ\8cзована длÑ\8f авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ии, валидаÑ\86ии и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
+Ð\9dапÑ\80имеÑ\80, вÑ\8b можеÑ\82е Ñ\85оÑ\82еÑ\82Ñ\8c **возвÑ\80аÑ\89аÑ\82Ñ\8c Ñ\81ловаÑ\80Ñ\8c (dict)** или обÑ\8aекÑ\82 из базÑ\8b даннÑ\8bÑ\85, но **обÑ\8aÑ\8fвиÑ\82Ñ\8c его как Pydantic-моделÑ\8c**. Тогда Pydantic-моделÑ\8c вÑ\8bполниÑ\82 докÑ\83менÑ\82иÑ\80ование даннÑ\8bÑ\85, валидаÑ\86иÑ\8e и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
-Ð\9dо еÑ\81ли Ñ\83казаÑ\82Ñ\8c анноÑ\82аÑ\86иÑ\8e возвÑ\80аÑ\89аемого Ñ\82ипа, Ñ\81Ñ\82аÑ\82иÑ\87еÑ\81каÑ\8f пÑ\80овеÑ\80ка Ñ\82ипов бÑ\83деÑ\82 вÑ\8bдаваÑ\82Ñ\8c оÑ\88ибкÑ\83 (абÑ\81олÑ\8eÑ\82но коÑ\80Ñ\80екÑ\82нÑ\83Ñ\8e в данном Ñ\81лÑ\83Ñ\87ае). Ð\9eна бÑ\83деÑ\82 говоÑ\80иÑ\82Ñ\8c о Ñ\82ом, Ñ\87Ñ\82о ваÑ\88а Ñ\84Ñ\83нкÑ\86иÑ\8f должна возвÑ\80аÑ\89аÑ\82Ñ\8c даннÑ\8bе одного Ñ\82ипа (напÑ\80имеÑ\80, dict), а в анноÑ\82аÑ\86ии вÑ\8b обÑ\8aÑ\8fвили дÑ\80Ñ\83гой Ñ\82ип (напÑ\80имеÑ\80, моделÑ\8c Pydantic).
+Ð\95Ñ\81ли вÑ\8b добавиÑ\82е анноÑ\82аÑ\86иÑ\8e возвÑ\80аÑ\89аемого Ñ\82ипа, инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b и Ñ\80едакÑ\82оÑ\80Ñ\8b кода наÑ\87нÑ\83Ñ\82 жаловаÑ\82Ñ\8cÑ\81Ñ\8f (и бÑ\83дÑ\83Ñ\82 пÑ\80авÑ\8b), Ñ\87Ñ\82о Ñ\84Ñ\83нкÑ\86иÑ\8f возвÑ\80аÑ\89аеÑ\82 Ñ\82ип (напÑ\80имеÑ\80, dict), оÑ\82лиÑ\87нÑ\8bй оÑ\82 обÑ\8aÑ\8fвленного (напÑ\80имеÑ\80, Pydantic-моделÑ\8c).
-Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `response_model` внÑ\83Ñ\82Ñ\80и *декоÑ\80аÑ\82оÑ\80а опеÑ\80аÑ\86ии пÑ\83Ñ\82и* вмеÑ\81Ñ\82о анноÑ\82аÑ\86ии возвÑ\80аÑ\89аемого знаÑ\87ениÑ\8f Ñ\84Ñ\83нкÑ\86ии.
+Ð\92 Ñ\82акиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 вмеÑ\81Ñ\82о анноÑ\82аÑ\86ии возвÑ\80аÑ\89аемого Ñ\82ипа можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `response_model` Ñ\83 *декоÑ\80аÑ\82оÑ\80а опеÑ\80аÑ\86ии пÑ\83Ñ\82и*.
-Ð\9fаÑ\80амеÑ\82Ñ\80 `response_model` можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\83казан длÑ\8f любой *операции пути*:
+Ð\9fаÑ\80амеÑ\82Ñ\80 `response_model` можно Ñ\83казаÑ\82Ñ\8c Ñ\83 любой *операции пути*:
* `@app.get()`
* `@app.post()`
* `@app.put()`
* `@app.delete()`
-* и др.
+* и т.д.
{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
-/// note | ТеÑ\85ниÑ\87еÑ\81кие деÑ\82али
+/// note | Ð\9fÑ\80имеÑ\87ание
-Ð\9fомниÑ\82е, Ñ\87Ñ\82о паÑ\80амеÑ\82Ñ\80 `response_model` Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f паÑ\80амеÑ\82Ñ\80ом именно декоÑ\80аÑ\82оÑ\80а http-меÑ\82одов (`get`, `post`, и Ñ\82.п.). Ð\9dе Ñ\81ледÑ\83еÑ\82 его Ñ\83казÑ\8bваÑ\82Ñ\8c длÑ\8f *Ñ\84Ñ\83нкÑ\86ий опеÑ\80аÑ\86ий пÑ\83Ñ\82и*, как вÑ\8b бÑ\8b поÑ\81Ñ\82Ñ\83пили Ñ\81 дÑ\80Ñ\83гими паÑ\80амеÑ\82Ñ\80ами или Ñ\81 Ñ\82елом запроса.
+Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о `response_model` â\80\94 Ñ\8dÑ\82о паÑ\80амеÑ\82Ñ\80 меÑ\82ода «декоÑ\80аÑ\82оÑ\80а» (`get`, `post` и Ñ\82.д.), а не ваÑ\88ей *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87ика пÑ\83Ñ\82и*, в коÑ\82оÑ\80ой Ñ\83казÑ\8bваÑ\8eÑ\82Ñ\81Ñ\8f паÑ\80амеÑ\82Ñ\80Ñ\8b и Ñ\82ело запроса.
///
-`response_model` пÑ\80инимаеÑ\82 Ñ\82е же Ñ\82ипÑ\8b, коÑ\82оÑ\80Ñ\8bе можно Ñ\83казаÑ\82Ñ\8c длÑ\8f какого-либо полÑ\8f в модели Pydantic. Таким обÑ\80азом, Ñ\8dÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c как одиноÑ\87наÑ\8f моделÑ\8c Pydantic, Ñ\82ак и `Ñ\81пиÑ\81ок (list)` моделей Pydantic. Ð\9dапÑ\80имеÑ\80, `List[Item]`.
+`response_model` пÑ\80инимаеÑ\82 Ñ\82оÑ\82 же Ñ\82ип, Ñ\87Ñ\82о вÑ\8b бÑ\8b обÑ\8aÑ\8fвили длÑ\8f полÑ\8f Pydantic-модели, Ñ\82о еÑ\81Ñ\82Ñ\8c Ñ\8dÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c одна Pydantic-моделÑ\8c, а можеÑ\82 бÑ\8bÑ\82Ñ\8c, напÑ\80имеÑ\80, `list` Pydantic-моделей, как `List[Item]`.
-FastAPI будет использовать значение `response_model` для того, чтобы автоматически генерировать документацию, производить валидацию и т.п. А также для **конвертации и фильтрации выходных данных** в объявленный тип.
+FastAPI будет использовать `response_model` для документации, валидации и т. п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
-/// tip | Ð\9fодÑ\81казка
+/// tip | СовеÑ\82
-Если вы используете анализаторы типов со строгой проверкой (например, mypy), можно указать `Any` в качестве типа возвращаемого значения функции.
+Если у вас в редакторе кода, mypy и т. п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
-Таким образом вы информируете ваш редактор кода, что намеренно возвращаете данные неопределенного типа. Но возможности FastAPI, такие как автоматическая генерация документации, валидация, фильтрация и т.д. все так же будут работать, просто используя параметр `response_model`.
+Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документацию данных, валидацию, фильтрацию и т.д. с помощью `response_model`.
///
-### Приоритет `response_model`
+### Приоритет `response_model` { #response-model-priority }
-Ð\95Ñ\81ли одновÑ\80еменно Ñ\83казаÑ\82Ñ\8c анноÑ\82аÑ\86иÑ\8e Ñ\82ипа длÑ\8f оÑ\82веÑ\82а Ñ\84Ñ\83нкÑ\86ии и паÑ\80амеÑ\82Ñ\80 `response_model` - поÑ\81ледний бÑ\83деÑ\82 имеÑ\82Ñ\8c болÑ\8cÑ\88ий пÑ\80иоÑ\80иÑ\82еÑ\82 и FastAPI бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c именно его.
+Ð\95Ñ\81ли вÑ\8b обÑ\8aÑ\8fвиÑ\82е и возвÑ\80аÑ\89аемÑ\8bй Ñ\82ип, и `response_model`, пÑ\80иоÑ\80иÑ\82еÑ\82 бÑ\83деÑ\82 Ñ\83 `response_model`, именно его иÑ\81полÑ\8cзÑ\83еÑ\82 FastAPI.
-Таким образом вы можете объявить корректные аннотации типов к вашим функциям, даже если они возвращают тип, отличающийся от указанного в `response_model`. Они будут считаны во время статической проверки типов вашими помощниками, например, mypy. При этом вы все так же используете возможности FastAPI для автоматической документации, валидации и т.д. благодаря `response_model`.
+Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
-Вы можете указать значение `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для данных, не являющихся валидными полями Pydantic. Мы увидим пример кода для такого случая в одном из разделов ниже.
+Вы также можете указать `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для вещей, не являющихся валидными полями Pydantic. Пример вы увидите ниже.
-## Ð\9fолÑ\83Ñ\87иÑ\82Ñ\8c и веÑ\80нÑ\83Ñ\82Ñ\8c один и Ñ\82оÑ\82 же Ñ\82ип даннÑ\8bÑ\85
+## Ð\92еÑ\80нÑ\83Ñ\82Ñ\8c Ñ\82е же вÑ\85однÑ\8bе даннÑ\8bе { #return-the-same-input-data }
-Ð\97деÑ\81Ñ\8c мÑ\8b обÑ\8aÑ\8fвили моделÑ\8c `UserIn`, коÑ\82оÑ\80аÑ\8f Ñ\85Ñ\80аниÑ\82 полÑ\8cзоваÑ\82елÑ\8cÑ\81кий пароль в открытом виде:
+Ð\97деÑ\81Ñ\8c мÑ\8b обÑ\8aÑ\8fвлÑ\8fем моделÑ\8c `UserIn`, она бÑ\83деÑ\82 Ñ\81одеÑ\80жаÑ\82Ñ\8c пароль в открытом виде:
{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
/// info | Информация
-Чтобы использовать `EmailStr`, прежде необходимо установить <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.
-Используйте `pip install email-validator`
-или `pip install pydantic[email]`.
+Чтобы использовать `EmailStr`, сначала установите <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.
+
+Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите пакет, например:
+
+```console
+$ pip install email-validator
+```
+
+или так:
+
+```console
+$ pip install "pydantic[email]"
+```
///
-Ð\94алее мÑ\8b иÑ\81полÑ\8cзÑ\83ем наÑ\88Ñ\83 моделÑ\8c в анноÑ\82аÑ\86иÑ\8fÑ\85 Ñ\82ипа как длÑ\8f аÑ\80гÑ\83менÑ\82а Ñ\84Ñ\83нкÑ\86ии, Ñ\82ак и длÑ\8f вÑ\8bÑ\85одного знаÑ\87ениÑ\8f:
+Ð\98 мÑ\8b иÑ\81полÑ\8cзÑ\83ем Ñ\8dÑ\82Ñ\83 моделÑ\8c длÑ\8f обÑ\8aÑ\8fвлениÑ\8f вÑ\85однÑ\8bÑ\85 даннÑ\8bÑ\85, и Ñ\82Ñ\83 же моделÑ\8c â\80\94 длÑ\8f обÑ\8aÑ\8fвлениÑ\8f вÑ\8bÑ\85однÑ\8bÑ\85 даннÑ\8bÑ\85:
{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
-Теперь всякий раз, когда клиент создает пользователя с паролем, API будет возвращать его пароль в ответе.
+Теперь, когда браузер создаёт пользователя с паролем, API вернёт тот же пароль в ответе.
-В данном случае это не такая уж большая проблема, поскольку ответ получит тот же самый пользователь, который и создал пароль.
+В этом случае это может быть не проблемой, так как пароль отправляет тот же пользователь.
-Но что если мы захотим использовать эту модель для какой-либо другой *операции пути*? Мы можем, сами того не желая, отправить пароль любому другому пользователю.
+Но если мы используем ту же модель в другой *операции пути*, мы можем начать отправлять пароли пользователей каждому клиенту.
/// danger | Осторожно
-Никогда не храните пароли пользователей в открытом виде, а также никогда не возвращайте их в ответе, как в примере выше. В противном случае - убедитесь, что вы хорошо продумали и учли все возможные риски такого подхода и вам известно, что вы делаете.
+Никогда не храните пароль пользователя в открытом виде и не отправляйте его в ответе подобным образом, если только вы не понимаете всех рисков и точно знаете, что делаете.
///
-## Создание модели длÑ\8f оÑ\82веÑ\82а
+## Ð\94обавиÑ\82Ñ\8c моделÑ\8c длÑ\8f оÑ\82веÑ\82а { #add-an-output-model }
-Вместо этого мы можем создать входную модель, хранящую пароль в открытом виде и выходную модель без пароля:
+Вместо этого мы можем создать входную модель с паролем в открытом виде и выходную модель без него:
{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
-Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае, даже неÑ\81моÑ\82Ñ\80Ñ\8f на Ñ\82о, Ñ\87Ñ\82о наÑ\88а *Ñ\84Ñ\83нкÑ\86иÑ\8f опеÑ\80аÑ\86ии пÑ\83Ñ\82и* возвÑ\80аÑ\89аеÑ\82 Ñ\82оÑ\82 же Ñ\81амÑ\8bй обÑ\8aекÑ\82 полÑ\8cзоваÑ\82елÑ\8f Ñ\81 паÑ\80олем, полÑ\83Ñ\87еннÑ\8bм на вÑ\85од:
+Ð\97деÑ\81Ñ\8c, Ñ\85оÑ\82Ñ\8f *Ñ\84Ñ\83нкÑ\86иÑ\8f-обÑ\80абоÑ\82Ñ\87ик пÑ\83Ñ\82и* возвÑ\80аÑ\89аеÑ\82 Ñ\82оÑ\82 же вÑ\85одной обÑ\8aекÑ\82 полÑ\8cзоваÑ\82елÑ\8f, Ñ\81одеÑ\80жаÑ\89ий паÑ\80олÑ\8c:
{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
-...мы указали в `response_model` модель `UserOut`, в которой отсутствует поле, содержащее пароль - и он будет исключен из ответа:
+...мы объявили `response_model` как модель `UserOut`, в которой нет пароля:
{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
-Таким образом **FastAPI** позаботится о фильтрации ответа и исключит из него всё, что не указано в выходной модели (при помощи Pydantic).
+Таким образом, **FastAPI** позаботится о том, чтобы отфильтровать все данные, не объявленные в выходной модели (используя Pydantic).
-### `response_model` или возвращаемый тип данных
+### `response_model` или возвращаемый тип { #response-model-or-return-type }
-В нашем примере модели входных данных и выходных данных различаются. И если мы укажем аннотацию типа выходного значения функции как `UserOut` - проверка типов выдаст ошибку из-за того, что мы возвращаем некорректный тип. Поскольку это 2 разных класса.
+В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
-Поэтому в нашем примере мы можем объявить тип ответа только в параметре `response_model`.
+Поэтому в этом примере мы должны объявить тип ответа в параметре `response_model`.
-...но продолжайте читать дальше, чтобы узнать как можно это обойти.
+...но читайте дальше, чтобы узнать, как это обойти.
-## Возвращаемый тип и Фильтрация данных
+## Возвращаемый тип и фильтрация данных { #return-type-and-data-filtering }
-Продолжим рассматривать предыдущий пример. Мы хотели **аннотировать входные данные одним типом**, а выходное значение - **другим типом**.
+Продолжим предыдущий пример. Мы хотели **аннотировать функцию одним типом**, но при этом иметь возможность вернуть из функции что-то, что фактически включает **больше данных**.
-Мы хотим, чтобы FastAPI продолжал **фильтровать** данные, используя `response_model`.
+Мы хотим, чтобы FastAPI продолжал **фильтровать** данные с помощью модели ответа. Так что, даже если функция возвращает больше данных, в ответ будут включены только поля, объявленные в модели ответа.
-Ð\92 пÑ\80оÑ\88лом пÑ\80имеÑ\80е, Ñ\82.к. вÑ\85одной и вÑ\8bÑ\85одной Ñ\82ипÑ\8b Ñ\8fвлÑ\8fлиÑ\81Ñ\8c Ñ\80азнÑ\8bми клаÑ\81Ñ\81ами, мÑ\8b бÑ\8bли вÑ\8bнÑ\83жденÑ\8b иÑ\81полÑ\8cзоваÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `response_model`. Ð\98 как Ñ\81ледÑ\81Ñ\82вие, мÑ\8b лиÑ\88алиÑ\81Ñ\8c помоÑ\89и Ñ\81Ñ\82аÑ\82иÑ\87еÑ\81киÑ\85 анализаÑ\82оÑ\80ов длÑ\8f пÑ\80овеÑ\80ки оÑ\82веÑ\82а функции.
+Ð\92 пÑ\80едÑ\8bдÑ\83Ñ\89ем пÑ\80имеÑ\80е, поÑ\81колÑ\8cкÑ\83 клаÑ\81Ñ\81Ñ\8b бÑ\8bли Ñ\80азнÑ\8bми, нам пÑ\80иÑ\88лоÑ\81Ñ\8c иÑ\81полÑ\8cзоваÑ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 `response_model`. Ð\9dо Ñ\8dÑ\82о Ñ\82акже ознаÑ\87аеÑ\82, Ñ\87Ñ\82о мÑ\8b Ñ\82еÑ\80Ñ\8fем поддеÑ\80жкÑ\83 оÑ\82 Ñ\80едакÑ\82оÑ\80а и инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов, пÑ\80овеÑ\80Ñ\8fÑ\8eÑ\89иÑ\85 возвÑ\80аÑ\89аемÑ\8bй Ñ\82ип функции.
-Ð\9dо в подавлÑ\8fÑ\8eÑ\89ем болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\81лÑ\83Ñ\87аев мÑ\8b бÑ\83дем Ñ\85оÑ\82еÑ\82Ñ\8c, Ñ\87Ñ\82обÑ\8b моделÑ\8c оÑ\82веÑ\82а лиÑ\88Ñ\8c **Ñ\84илÑ\8cÑ\82Ñ\80овала/Ñ\83далÑ\8fла** некоÑ\82оÑ\80Ñ\8bе даннÑ\8bе из оÑ\82веÑ\82а, как в наÑ\88ем примере.
+Ð\9eднако в болÑ\8cÑ\88инÑ\81Ñ\82ве Ñ\82акиÑ\85 Ñ\81лÑ\83Ñ\87аев нам нÑ\83жно лиÑ\88Ñ\8c **оÑ\82Ñ\84илÑ\8cÑ\82Ñ\80оваÑ\82Ñ\8c/Ñ\83бÑ\80аÑ\82Ñ\8c** некоÑ\82оÑ\80Ñ\8bе даннÑ\8bе, как в Ñ\8dÑ\82ом примере.
-Ð\98 в Ñ\82акиÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 мÑ\8b можем иÑ\81полÑ\8cзоваÑ\82Ñ\8c клаÑ\81Ñ\81Ñ\8b и наÑ\81ледование, Ñ\87Ñ\82обÑ\8b полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82вами **анноÑ\82аÑ\86ий Ñ\82ипов** и полÑ\83Ñ\87аÑ\82Ñ\8c более полнÑ\83Ñ\8e Ñ\81Ñ\82аÑ\82иÑ\87еÑ\81кÑ\83Ñ\8e пÑ\80овеÑ\80кÑ\83 Ñ\82ипов. Ð\9dо пÑ\80и Ñ\8dÑ\82ом вÑ\81е Ñ\82ак же полÑ\83Ñ\87аÑ\82Ñ\8c **Ñ\84илÑ\8cÑ\82Ñ\80аÑ\86иÑ\8e оÑ\82веÑ\82а** от FastAPI.
+Ð\98 в Ñ\8dÑ\82иÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85 мÑ\8b можем иÑ\81полÑ\8cзоваÑ\82Ñ\8c клаÑ\81Ñ\81Ñ\8b и наÑ\81ледование, Ñ\87Ñ\82обÑ\8b воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f **анноÑ\82аÑ\86иÑ\8fми Ñ\82ипов** Ñ\84Ñ\83нкÑ\86ий длÑ\8f лÑ\83Ñ\87Ñ\88ей поддеÑ\80жки в Ñ\80едакÑ\82оÑ\80е и инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82аÑ\85 и пÑ\80и Ñ\8dÑ\82ом полÑ\83Ñ\87иÑ\82Ñ\8c **Ñ\84илÑ\8cÑ\82Ñ\80аÑ\86иÑ\8e даннÑ\8bÑ\85** от FastAPI.
{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
-Таким образом, мы получаем поддержку редактора кода и mypy в части типов, сохраняя при этом фильтрацию данных от FastAPI.
+Так мы получаем поддержку инструментов (редакторы, mypy) — код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
-Как это возможно? Давайте разберемся. 🤓
+Как это работает? Давайте разберёмся. 🤓
-### Аннотации типов и инструменты для их проверки
+### Аннотации типов и инструменты { #type-annotations-and-tooling }
-Ð\94лÑ\8f наÑ\87ала давайÑ\82е Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им как наÑ\88 Ñ\80едакÑ\82оÑ\80 кода, mypy и дÑ\80Ñ\83гие помоÑ\89ники Ñ\80азÑ\80абоÑ\82Ñ\87ика видÑ\8fÑ\82 анноÑ\82аÑ\86ии Ñ\82ипов.
+СнаÑ\87ала поÑ\81моÑ\82Ñ\80им, как Ñ\8dÑ\82о Ñ\83видÑ\8fÑ\82 Ñ\80едакÑ\82оÑ\80Ñ\8b, mypy и дÑ\80Ñ\83гие инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b.
-У модели `BaseUser` есть некоторые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет новое поле `password`. Таким образом модель будет включать в себя все поля из первой модели (родителя), а также свои собственные.
+`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он включает все поля обеих моделей.
-Ð\9cÑ\8b анноÑ\82иÑ\80Ñ\83ем возвÑ\80аÑ\89аемÑ\8bй Ñ\82ип Ñ\84Ñ\83нкÑ\86ии как `BaseUser`, но Ñ\84акÑ\82иÑ\87еÑ\81ки мÑ\8b бÑ\83дем возвÑ\80аÑ\89аÑ\82Ñ\8c обÑ\8aекÑ\82 Ñ\82ипа `UserIn`.
+Ð\9cÑ\8b анноÑ\82иÑ\80Ñ\83ем возвÑ\80аÑ\89аемÑ\8bй Ñ\82ип Ñ\84Ñ\83нкÑ\86ии как `BaseUser`, но Ñ\84акÑ\82иÑ\87еÑ\81ки возвÑ\80аÑ\89аем Ñ\8dкземплÑ\8fÑ\80 `UserIn`.
-Редакторы, mypy и другие инструменты не будут иметь возражений против такого подхода, поскольку `UserIn` является подклассом `BaseUser`. Это означает, что такой тип будет *корректным*, т.к. ответ может быть чем угодно, если это будет `BaseUser`.
+Редактор, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
-### ФилÑ\8cÑ\82Ñ\80аÑ\86иÑ\8f Ð\94аннÑ\8bÑ\85 FastAPI
+### ФилÑ\8cÑ\82Ñ\80аÑ\86иÑ\8f даннÑ\8bÑ\85 FastAPI { #fastapi-data-filtering }
-FastAPI знает тип ответа функции, так что вы можете быть уверены, что на выходе будут **только** те поля, которые вы указали.
+Теперь, для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
-FastAPI совместно с Pydantic выполнит некоторую магию "под капотом", чтобы убедиться, что те же самые правила наследования классов не используются для фильтрации возвращаемых данных, в противном случае вы могли бы в конечном итоге вернуть гораздо больше данных, чем ожидали.
+FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы вернуть гораздо больше данных, чем ожидали.
-Таким образом, вы можете получить все самое лучшее из обоих миров: аннотации типов с **поддержкой инструментов для разработки** и **фильтрацию данных**.
+Таким образом вы получаете лучшее из обоих миров: аннотации типов с **поддержкой инструментов** и **фильтрацию данных**.
-## Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81каÑ\8f докÑ\83менÑ\82аÑ\86иÑ\8f
+## Ð\9fоÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c в докÑ\83менÑ\82аÑ\86ии { #see-it-in-the-docs }
-Ð\95Ñ\81ли поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c на Ñ\81генеÑ\80иÑ\80ованнÑ\83Ñ\8e докÑ\83менÑ\82аÑ\86иÑ\8e, вÑ\8b можеÑ\82е Ñ\83бедиÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о в ней пÑ\80иÑ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\82 обе JSON Ñ\81Ñ\85емÑ\8b - как длÑ\8f вÑ\85одной модели, Ñ\82ак и длÑ\8f вÑ\8bÑ\85одной:
+Ð\92 авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ии вÑ\8b Ñ\83видиÑ\82е, Ñ\87Ñ\82о Ñ\83 вÑ\85одной и вÑ\8bÑ\85одной моделей еÑ\81Ñ\82Ñ\8c Ñ\81вои JSON Schema:
<img src="/img/tutorial/response-model/image01.png">
-И также обе модели будут использованы в интерактивной документации API:
+И обе модели используются в интерактивной документации API:
<img src="/img/tutorial/response-model/image02.png">
-## Другие аннотации типов
+## Другие аннотации возвращаемых типов { #other-return-type-annotations }
-Бывают случаи, когда вы возвращаете что-то, что не является валидным типом для Pydantic и вы указываете аннотацию ответа функции только для того, чтобы работала поддержка различных инструментов (редактор кода, mypy и др.).
+Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор, mypy и т. д.).
-### Ð\92озвÑ\80аÑ\89аем Response
+### Ð\92озвÑ\80аÑ\82 Response напÑ\80Ñ\8fмÑ\83Ñ\8e { #return-a-response-directly }
-СамÑ\8bй Ñ\87аÑ\81Ñ\82Ñ\8bй Ñ\81Ñ\86енаÑ\80ий иÑ\81полÑ\8cзованиÑ\8f - Ñ\8dÑ\82о [возвÑ\80аÑ\89аÑ\82Ñ\8c Response напÑ\80Ñ\8fмÑ\83Ñ\8e, как опиÑ\81ано в Ñ\80аÑ\81Ñ\88иÑ\80енной докÑ\83менÑ\82аÑ\86ии](../advanced/response-directly.md){.internal-link target=_blank}.
+СамÑ\8bй Ñ\80аÑ\81пÑ\80оÑ\81Ñ\82Ñ\80анÑ\91ннÑ\8bй Ñ\81лÑ\83Ñ\87ай â\80\94 [возвÑ\80аÑ\89аÑ\82Ñ\8c Response напÑ\80Ñ\8fмÑ\83Ñ\8e, как опиÑ\81ано далее в Ñ\80азделаÑ\85 длÑ\8f пÑ\80одвинÑ\83Ñ\82Ñ\8bÑ\85](../advanced/response-directly.md){.internal-link target=_blank}.
{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *}
-Это поддерживается FastAPI по-умолчанию, т.к. аннотация проставлена в классе (или подклассе) `Response`.
+Этот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`.
-Ð\98 ваÑ\88и помоÑ\89ники Ñ\80азÑ\80абоÑ\82ки Ñ\82акже бÑ\83дÑ\83Ñ\82 Ñ\81Ñ\87аÑ\81Ñ\82ливÑ\8b, Ñ\82.к. оба клаÑ\81Ñ\81а `RedirectResponse` и `JSONResponse` Ñ\8fвлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f подклаÑ\81Ñ\81ами `Response`. Таким обÑ\80азом мÑ\8b полÑ\83Ñ\87аем коÑ\80Ñ\80екÑ\82нÑ\83Ñ\8e анноÑ\82аÑ\86иÑ\8e Ñ\82ипа.
+Ð\98 инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b Ñ\82оже бÑ\83дÑ\83Ñ\82 доволÑ\8cнÑ\8b, поÑ\82омÑ\83 Ñ\87Ñ\82о и `RedirectResponse`, и `JSONResponse` Ñ\8fвлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f подклаÑ\81Ñ\81ами `Response`, Ñ\82ак Ñ\87Ñ\82о анноÑ\82аÑ\86иÑ\8f Ñ\82ипа коÑ\80Ñ\80екÑ\82на.
-### Ð\9fодклаÑ\81Ñ\81 Response в анноÑ\82аÑ\86ии Ñ\82ипа
+### Ð\90нноÑ\82иÑ\80оваÑ\82Ñ\8c подклаÑ\81Ñ\81 Response { #annotate-a-response-subclass }
-Вы также можете указать подкласс `Response` в аннотации типа:
+Вы также можете использовать подкласс `Response` в аннотации типа:
{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *}
-ÐÑ\82о Ñ\81Ñ\80абоÑ\82аеÑ\82, поÑ\82омÑ\83 Ñ\87Ñ\82о `RedirectResponse` Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f подклаÑ\81Ñ\81ом `Response` и FastAPI авÑ\82омаÑ\82иÑ\87еÑ\81ки обÑ\80абоÑ\82аеÑ\82 Ñ\8dÑ\82оÑ\82 пÑ\80оÑ\81Ñ\82ейÑ\88ий случай.
+ÐÑ\82о Ñ\82оже Ñ\81Ñ\80абоÑ\82аеÑ\82, Ñ\82ак как `RedirectResponse` â\80\94 подклаÑ\81Ñ\81 `Response`, и FastAPI авÑ\82омаÑ\82иÑ\87еÑ\81ки обÑ\80абоÑ\82аеÑ\82 Ñ\8dÑ\82оÑ\82 случай.
-### Некорректные аннотации типов
+### Некорректные аннотации возвращаемых типов { #invalid-return-type-annotations }
-Ð\9dо когда вÑ\8b возвÑ\80аÑ\89аеÑ\82е какой-либо дÑ\80Ñ\83гой пÑ\80оизволÑ\8cнÑ\8bй обÑ\8aекÑ\82, коÑ\82оÑ\80Ñ\8bй не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f допÑ\83Ñ\81Ñ\82имÑ\8bм Ñ\82ипом Pydantic (напÑ\80имеÑ\80, обÑ\8aекÑ\82 из базÑ\8b даннÑ\8bÑ\85), и вÑ\8b анноÑ\82иÑ\80Ñ\83еÑ\82е его подобнÑ\8bм обÑ\80азом длÑ\8f Ñ\84Ñ\83нкÑ\86ии, FastAPI попÑ\8bÑ\82аеÑ\82Ñ\81Ñ\8f Ñ\81оздаÑ\82Ñ\8c из Ñ\8dÑ\82ого Ñ\82ипа моделÑ\8c Pydantic и потерпит неудачу.
+Ð\9dо когда вÑ\8b возвÑ\80аÑ\89аеÑ\82е пÑ\80оизволÑ\8cнÑ\8bй обÑ\8aекÑ\82, не Ñ\8fвлÑ\8fÑ\8eÑ\89ийÑ\81Ñ\8f валиднÑ\8bм Ñ\82ипом Pydantic (напÑ\80имеÑ\80, обÑ\8aекÑ\82 базÑ\8b даннÑ\8bÑ\85), и анноÑ\82иÑ\80Ñ\83еÑ\82е его Ñ\82аким обÑ\80азом в Ñ\84Ñ\83нкÑ\86ии, FastAPI попÑ\8bÑ\82аеÑ\82Ñ\81Ñ\8f Ñ\81оздаÑ\82Ñ\8c моделÑ\8c оÑ\82веÑ\82а Pydantic из Ñ\8dÑ\82ой анноÑ\82аÑ\86ии Ñ\82ипа и потерпит неудачу.
-То же самое произошло бы, если бы у вас было что-то вроде <abbr title='Union разных типов буквально означает "любой из перечисленных типов".'>Union</abbr> различных типов и один или несколько из них не являлись бы допустимыми типами для Pydantic. Например, такой вариант приведет к ошибке 💥:
+То же произойдёт, если у вас будет что-то вроде <abbr title='Объединение нескольких типов означает «любой из этих типов».'>union</abbr> разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
-...Ñ\82акой код вÑ\8bзовеÑ\82 оÑ\88ибкÑ\83, поÑ\82омÑ\83 Ñ\87Ñ\82о в анноÑ\82аÑ\86ии Ñ\83казан неподдеÑ\80живаемÑ\8bй Pydantic Ñ\82ип. Ð\90 Ñ\82акже Ñ\8dÑ\82оÑ\82 Ñ\82ип не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f клаÑ\81Ñ\81ом или подклаÑ\81Ñ\81ом `Response`.
+...Ñ\8dÑ\82о не Ñ\81Ñ\80абоÑ\82аеÑ\82, поÑ\82омÑ\83 Ñ\87Ñ\82о анноÑ\82аÑ\86иÑ\8f Ñ\82ипа не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\82ипом Pydantic и Ñ\8dÑ\82о не единÑ\81Ñ\82веннÑ\8bй клаÑ\81Ñ\81 `Response` или его подклаÑ\81Ñ\81, а обÑ\8aединение (`union`) из `Response` и `dict`.
-### Ð\92озможно ли оÑ\82клÑ\8eÑ\87иÑ\82Ñ\8c генеÑ\80аÑ\86иÑ\8e модели оÑ\82веÑ\82а?
+### Ð\9eÑ\82клÑ\8eÑ\87иÑ\82Ñ\8c моделÑ\8c оÑ\82веÑ\82а { #disable-response-model }
-Ð\9fÑ\80одолжим Ñ\80аÑ\81Ñ\81маÑ\82Ñ\80иваÑ\82Ñ\8c пÑ\80едÑ\8bдÑ\83Ñ\89ий пÑ\80имеÑ\80. Ð\94опÑ\83Ñ\81Ñ\82им, Ñ\87Ñ\82о вÑ\8b Ñ\85оÑ\82иÑ\82е оÑ\82казаÑ\82Ñ\8cÑ\81Ñ\8f оÑ\82 авÑ\82омаÑ\82иÑ\87еÑ\81кой валидаÑ\86ии оÑ\82веÑ\82а, докÑ\83менÑ\82аÑ\86ии, Ñ\84илÑ\8cÑ\82Ñ\80аÑ\86ии и Ñ\82.д.
+Ð\9fÑ\80одолжаÑ\8f пÑ\80имеÑ\80 вÑ\8bÑ\88е, вÑ\8b можеÑ\82е не Ñ\85оÑ\82еÑ\82Ñ\8c иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\83Ñ\8e валидаÑ\86иÑ\8e даннÑ\8bÑ\85, докÑ\83менÑ\82аÑ\86иÑ\8e, Ñ\84илÑ\8cÑ\82Ñ\80аÑ\86иÑ\8e и Ñ\82.д., вÑ\8bполнÑ\8fемÑ\8bе FastAPI.
-Ð\9dо в Ñ\82о же вÑ\80емÑ\8f, Ñ\85оÑ\82иÑ\82е Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c анноÑ\82аÑ\86иÑ\8e возвÑ\80аÑ\89аемого Ñ\82ипа длÑ\8f Ñ\84Ñ\83нкÑ\86ии, Ñ\87Ñ\82обÑ\8b обеÑ\81пеÑ\87иÑ\82Ñ\8c Ñ\80абоÑ\82Ñ\83 помоÑ\89ников и анализаÑ\82оÑ\80ов Ñ\82ипов (напÑ\80имеÑ\80, mypy).
+Ð\9dо пÑ\80и Ñ\8dÑ\82ом вÑ\8b можеÑ\82е Ñ\85оÑ\82еÑ\82Ñ\8c Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c анноÑ\82аÑ\86иÑ\8e возвÑ\80аÑ\89аемого Ñ\82ипа в Ñ\84Ñ\83нкÑ\86ии, Ñ\87Ñ\82обÑ\8b полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f поддеÑ\80жкой инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ов (Ñ\80едакÑ\82оÑ\80Ñ\8b, пÑ\80овеÑ\80ки Ñ\82ипов вÑ\80оде mypy).
-Ð\92 Ñ\82аком Ñ\81лÑ\83Ñ\87ае, вÑ\8b можеÑ\82е оÑ\82клÑ\8eÑ\87иÑ\82Ñ\8c генеÑ\80аÑ\86иÑ\8e модели оÑ\82веÑ\82а, Ñ\83казав `response_model=None`:
+Ð\92 Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае вÑ\8b можеÑ\82е оÑ\82клÑ\8eÑ\87иÑ\82Ñ\8c генеÑ\80аÑ\86иÑ\8e модели оÑ\82веÑ\82а, Ñ\83Ñ\81Ñ\82ановив `response_model=None`:
{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
-Тогда FastAPI не Ñ\81Ñ\82анеÑ\82 генеÑ\80иÑ\80оваÑ\82Ñ\8c моделÑ\8c оÑ\82веÑ\82а и вÑ\8b Ñ\81можеÑ\82е Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c Ñ\82акÑ\83Ñ\8e анноÑ\82аÑ\86иÑ\8e Ñ\82ипа, коÑ\82оÑ\80аÑ\8f вам Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f, никак не влиÑ\8fÑ\8f на Ñ\80абоÑ\82Ñ\83 FastAPI. 🤓
+Так FastAPI пÑ\80опÑ\83Ñ\81Ñ\82иÑ\82 генеÑ\80аÑ\86иÑ\8e модели оÑ\82веÑ\82а, и вÑ\8b Ñ\81можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c лÑ\8eбÑ\8bе анноÑ\82аÑ\86ии возвÑ\80аÑ\89аемÑ\8bÑ\85 Ñ\82ипов, не влиÑ\8fÑ\8f на ваÑ\88е пÑ\80иложение FastAPI. 🤓
-## Ð\9fаÑ\80амеÑ\82Ñ\80Ñ\8b модели оÑ\82веÑ\82а
+## Ð\9fаÑ\80амеÑ\82Ñ\80Ñ\8b кодиÑ\80ованиÑ\8f модели оÑ\82веÑ\82а { #response-model-encoding-parameters }
-Ð\9cоделÑ\8c оÑ\82веÑ\82а можеÑ\82 иметь значения по умолчанию, например:
+У ваÑ\88ей модели оÑ\82веÑ\82а могÑ\83Ñ\82 бÑ\8bть значения по умолчанию, например:
{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
-* `description: Union[str, None] = None` (или `str | None = None` в Python 3.10), где `None` является значением по умолчанию.
-* `tax: float = 10.5`, где `10.5` является значением по умолчанию.
-* `tags: List[str] = []`, где пустой список `[]` является значением по умолчанию.
+* `description: Union[str, None] = None` (или `str | None = None` в Python 3.10) имеет значение по умолчанию `None`.
+* `tax: float = 10.5` имеет значение по умолчанию `10.5`.
+* `tags: List[str] = []` имеет значение по умолчанию пустого списка: `[]`.
-но вы, возможно, хотели бы исключить их из ответа, если данные поля не были заданы явно.
+но вы можете захотеть опустить их в результате, если они фактически не были сохранены.
-Например, у вас есть модель с множеством необязательных полей в NoSQL базе данных, но вы не хотите отправлять в качестве ответа очень длинный JSON с множеством значений по умолчанию.
+Например, если у вас есть модели с множеством необязательных атрибутов в NoSQL-базе данных, но вы не хотите отправлять очень длинные JSON-ответы, заполненные значениями по умолчанию.
-### Используйте параметр `response_model_exclude_unset`
+### Используйте параметр `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }
-УÑ\81Ñ\82ановиÑ\82е длÑ\8f *декоратора операции пути* параметр `response_model_exclude_unset=True`:
+Ð\92Ñ\8b можеÑ\82е Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c Ñ\83 *декоратора операции пути* параметр `response_model_exclude_unset=True`:
{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
-и Ñ\82огда знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e не бÑ\83дÑ\83Ñ\82 вклÑ\8eÑ\87енÑ\8b в оÑ\82веÑ\82. Ð\92 нем бÑ\83дÑ\83Ñ\82 Ñ\82олÑ\8cко Ñ\82е полÑ\8f, знаÑ\87ениÑ\8f коÑ\82оÑ\80Ñ\8bÑ\85 Ñ\84акÑ\82иÑ\87еÑ\81ки были установлены.
+и Ñ\8dÑ\82и знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e не бÑ\83дÑ\83Ñ\82 вклÑ\8eÑ\87енÑ\8b в оÑ\82веÑ\82 â\80\94 Ñ\82олÑ\8cко Ñ\82е знаÑ\87ениÑ\8f, коÑ\82оÑ\80Ñ\8bе дейÑ\81Ñ\82виÑ\82елÑ\8cно были установлены.
-Ð\98Ñ\82ак, еÑ\81ли вÑ\8b оÑ\82пÑ\80авиÑ\82е запÑ\80оÑ\81 на даннÑ\83Ñ\8e *опеÑ\80аÑ\86иÑ\8e пÑ\83Ñ\82и* длÑ\8f Ñ\8dлеменÑ\82а, Ñ\81 ID = `Foo` - оÑ\82веÑ\82 (Ñ\81 иÑ\81клÑ\8eÑ\87еннÑ\8bми знаÑ\87ениÑ\8fми по-умолчанию) будет таким:
+Ð\98Ñ\82ак, еÑ\81ли вÑ\8b оÑ\82пÑ\80авиÑ\82е запÑ\80оÑ\81 к Ñ\8dÑ\82ой *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* длÑ\8f Ñ\8dлеменÑ\82а Ñ\81 ID `foo`, оÑ\82веÑ\82 (без знаÑ\87ений по умолчанию) будет таким:
```JSON
{
/// info | Информация
-"Под капотом" FastAPI использует метод `.dict()` у объектов моделей Pydantic <a href="https://docs.pydantic.dev/latest/concepts/serialization/#modeldict" class="external-link" target="_blank">с параметром `exclude_unset`</a>, чтобы достичь такого эффекта.
+В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
+
+Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, применяйте `.model_dump()`.
+
+///
+
+/// info | Информация
+
+FastAPI использует метод `.dict()` у Pydantic-моделей с <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">параметром `exclude_unset`</a>, чтобы добиться такого поведения.
///
* `response_model_exclude_defaults=True`
* `response_model_exclude_none=True`
-как описано в <a href="https://docs.pydantic.dev/latest/concepts/serialization/#modeldict" class="external-link" target="_blank">документации Pydantic</a> для параметров `exclude_defaults` и `exclude_none`.
+как описано в <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">документации Pydantic</a> для `exclude_defaults` и `exclude_none`.
///
-#### Ð\95Ñ\81ли знаÑ\87ение полÑ\8f оÑ\82лиÑ\87аеÑ\82Ñ\81Ñ\8f оÑ\82 знаÑ\87ениÑ\8f по-Ñ\83молÑ\87аниÑ\8e
+#### Ð\94аннÑ\8bе Ñ\81о знаÑ\87ениÑ\8fми длÑ\8f полей, имеÑ\8eÑ\89иÑ\85 знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e { #data-with-values-for-fields-with-defaults }
-Ð\95Ñ\81ли длÑ\8f некоÑ\82оÑ\80Ñ\8bÑ\85 полей модели, имеÑ\8eÑ\89иÑ\85 знаÑ\87ениÑ\8f по-Ñ\83молÑ\87аниÑ\8e, знаÑ\87ениÑ\8f бÑ\8bли Ñ\8fвно Ñ\83Ñ\81Ñ\82ановленÑ\8b - как длÑ\8f Ñ\8dлеменÑ\82а Ñ\81 ID = `Bar`, оÑ\82веÑ\82 бÑ\83деÑ\82 Ñ\82аким:
+Ð\9dо еÑ\81ли в ваÑ\88иÑ\85 даннÑ\8bÑ\85 еÑ\81Ñ\82Ñ\8c знаÑ\87ениÑ\8f длÑ\8f полей модели, длÑ\8f коÑ\82оÑ\80Ñ\8bÑ\85 Ñ\83казанÑ\8b знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e, как Ñ\83 Ñ\8dлеменÑ\82а Ñ\81 ID `bar`:
```Python hl_lines="3 5"
{
}
```
-они не бÑ\83дÑ\83Ñ\82 иÑ\81клÑ\8eÑ\87енÑ\8b из оÑ\82веÑ\82а.
+они бÑ\83дÑ\83Ñ\82 вклÑ\8eÑ\87енÑ\8b в оÑ\82веÑ\82.
-#### Ð\95Ñ\81ли знаÑ\87ение полÑ\8f Ñ\81овпадаеÑ\82 Ñ\81 его знаÑ\87ением по Ñ\83молÑ\87аниÑ\8e
+#### Ð\94аннÑ\8bе Ñ\81 Ñ\82акими же знаÑ\87ениÑ\8fми, как знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e { #data-with-the-same-values-as-the-defaults }
-Если данные содержат те же значения, которые являются для этих полей по умолчанию, но были установлены явно - как для элемента с ID = `baz`, ответ будет таким:
+Если данные имеют те же значения, что и значения по умолчанию, как у элемента с ID `baz`:
```Python hl_lines="3 5-6"
{
}
```
-FastAPI достаточно умен (на самом деле, это заслуга Pydantic), чтобы понять, что, хотя `description`, `tax` и `tags` хранят такие же данные, какие должны быть по умолчанию - для них эти значения были установлены явно (а не получены из значений по умолчанию).
+FastAPI достаточно умен (на самом деле, это Pydantic), чтобы понять, что хотя `description`, `tax` и `tags` совпадают со значениями по умолчанию, они были установлены явно (а не взяты из значений по умолчанию).
-Ð\98 поÑ\8dÑ\82омÑ\83, они Ñ\82акже бÑ\83дÑ\83Ñ\82 вклÑ\8eÑ\87енÑ\8b в JSON оÑ\82веÑ\82а.
+Ð\9fоÑ\8dÑ\82омÑ\83 они Ñ\82оже бÑ\83дÑ\83Ñ\82 вклÑ\8eÑ\87енÑ\8b в JSON-оÑ\82веÑ\82.
-/// tip | Ð\9fодÑ\81казка
+/// tip | СовеÑ\82
-Ð\97наÑ\87ением по Ñ\83молÑ\87аниÑ\8e можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\87Ñ\82о Ñ\83годно, не только `None`.
+Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о знаÑ\87ениÑ\8f по Ñ\83молÑ\87аниÑ\8e могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c лÑ\8eбÑ\8bми, не только `None`.
-Ð\98м можеÑ\82 бÑ\8bÑ\82Ñ\8c и Ñ\81пиÑ\81ок (`[]`), знаÑ\87ение 10.5 Ñ\82ипа `float`, и Ñ\82.п.
+ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c Ñ\81пиÑ\81ок (`[]`), Ñ\87иÑ\81ло Ñ\81 плаваÑ\8eÑ\89ей Ñ\82оÑ\87кой `10.5` и Ñ\82. д.
///
-### `response_model_include` и `response_model_exclude`
+### `response_model_include` и `response_model_exclude` { #response-model-include-and-response-model-exclude }
-Вы также можете использовать параметры *декоратора операции пути*, такие, как `response_model_include` и `response_model_exclude`.
+Вы также можете использовать параметры *декоратора операции пути* `response_model_include` и `response_model_exclude`.
-Они принимают аргументы типа `set`, состоящий из строк (`str`) с названиями атрибутов, которые либо требуется включить в ответ (при этом исключив все остальные), либо наоборот исключить (оставив в ответе все остальные поля).
+Они принимают `set` из `str` с именами атрибутов, которые нужно включить (исключив остальные) или исключить (оставив остальные).
-Это можно использовать как быстрый способ исключить данные из ответа, не создавая отдельную модель Pydantic.
+Это можно использовать как быстрый способ, если у вас только одна Pydantic-модель и вы хотите убрать часть данных из ответа.
-/// tip | Ð\9fодÑ\81казка
+/// tip | СовеÑ\82
-Ð\9dо по-пÑ\80ежнемÑ\83 Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f Ñ\81ледоваÑ\82Ñ\8c изложеннÑ\8bм вÑ\8bÑ\88е Ñ\81овеÑ\82ам и иÑ\81полÑ\8cзоваÑ\82Ñ\8c неÑ\81колÑ\8cко моделей вмеÑ\81Ñ\82о даннÑ\8bх параметров.
+Ð\9dо вÑ\81Ñ\91 же Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c подÑ\85одÑ\8b вÑ\8bÑ\88е â\80\94 неÑ\81колÑ\8cко клаÑ\81Ñ\81ов â\80\94 вмеÑ\81Ñ\82о Ñ\8dÑ\82их параметров.
-Потому как JSON схема OpenAPI, генерируемая вашим приложением (а также документация) все еще будет содержать все поля, даже если вы использовали `response_model_include` или `response_model_exclude` и исключили некоторые атрибуты.
+Потому что JSON Schema, генерируемая в OpenAPI вашего приложения (и документации), всё равно будет соответствовать полной модели, даже если вы используете `response_model_include` или `response_model_exclude`, чтобы опустить некоторые атрибуты.
-То же самое применимо к параметру `response_model_by_alias`.
+То же относится к `response_model_by_alias`, который работает аналогично.
///
{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
-/// tip | Ð\9fодÑ\81казка
+/// tip | СовеÑ\82
-Ð\9fÑ\80и помоÑ\89и кода `{"name","description"}` Ñ\81оздаеÑ\82Ñ\81Ñ\8f обÑ\8aекÑ\82 множеÑ\81Ñ\82ва (`set`) Ñ\81 двÑ\83мÑ\8f Ñ\81Ñ\82Ñ\80оковÑ\8bми значениями.
+СинÑ\82акÑ\81иÑ\81 `{"name", "description"}` Ñ\81оздаÑ\91Ñ\82 `set` Ñ\81 Ñ\8dÑ\82ими двÑ\83мÑ\8f значениями.
-Того же Ñ\81амого можно доÑ\81Ñ\82иÑ\87Ñ\8c иÑ\81полÑ\8cзÑ\83Ñ\8f `set(["name", "description"])`.
+ÐÑ\82о Ñ\8dквиваленÑ\82но `set(["name", "description"])`.
///
-#### ЧÑ\82о еÑ\81ли иÑ\81полÑ\8cзоваÑ\82Ñ\8c `list` вмеÑ\81Ñ\82о `set`?
+#### Ð\98Ñ\81полÑ\8cзование `list` вмеÑ\81Ñ\82о `set` { #using-lists-instead-of-sets }
-Ð\95Ñ\81ли вÑ\8b забÑ\8bли пÑ\80о `set` и иÑ\81полÑ\8cзовали Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80Ñ\83 `list` или `tuple`, FastAPI авÑ\82омаÑ\82иÑ\87еÑ\81ки пÑ\80еобÑ\80азÑ\83еÑ\82 Ñ\8dÑ\82оÑ\82 обÑ\8aекÑ\82 в `set`, Ñ\87Ñ\82обÑ\8b обеÑ\81пеÑ\87иÑ\82Ñ\8c коÑ\80Ñ\80екÑ\82нÑ\83Ñ\8e Ñ\80абоÑ\82Ñ\83:
+Ð\95Ñ\81ли вÑ\8b забÑ\8bли иÑ\81полÑ\8cзоваÑ\82Ñ\8c `set` и пÑ\80именили `list` или `tuple`, FastAPI вÑ\81Ñ\91 Ñ\80авно пÑ\80еобÑ\80азÑ\83еÑ\82 Ñ\8dÑ\82о в `set`, и вÑ\81Ñ\91 бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c коÑ\80Ñ\80екÑ\82но:
{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
-## Резюме
+## Резюме { #recap }
-Используйте параметр `response_model` у *декоратора операции пути* для того, чтобы задать модель ответа и в большей степени для того, чтобы быть уверенным, что приватная информация будет отфильтрована.
+Используйте параметр `response_model` у *декоратора операции пути*, чтобы задавать модели ответа, и особенно — чтобы приватные данные отфильтровывались.
-Ð\90 Ñ\82акже иÑ\81полÑ\8cзÑ\83йÑ\82е `response_model_exclude_unset`, Ñ\87Ñ\82обÑ\8b возвÑ\80аÑ\89аÑ\82Ñ\8c Ñ\82олÑ\8cко Ñ\82е знаÑ\87ениÑ\8f, коÑ\82оÑ\80Ñ\8bе бÑ\8bли заданы явно.
+Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е `response_model_exclude_unset`, Ñ\87Ñ\82обÑ\8b возвÑ\80аÑ\89аÑ\82Ñ\8c Ñ\82олÑ\8cко Ñ\82е знаÑ\87ениÑ\8f, коÑ\82оÑ\80Ñ\8bе бÑ\8bли Ñ\83Ñ\81Ñ\82ановлены явно.
-# HTTP коды статуса ответа
+# Статус-код ответа { #response-status-code }
-Ð\92Ñ\8b можеÑ\82е задаÑ\82Ñ\8c HTTP код Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81а оÑ\82веÑ\82а Ñ\81 помоÑ\89Ñ\8cÑ\8e паÑ\80амеÑ\82Ñ\80а `status_code` подобно Ñ\82омÑ\83, как вÑ\8b опÑ\80еделÑ\8fеÑ\82е Ñ\81Ñ\85емÑ\83 оÑ\82веÑ\82а в любой из *операций пути*:
+Ð\9fодобно Ñ\82омÑ\83, как вÑ\8b можеÑ\82е задаÑ\82Ñ\8c моделÑ\8c/Ñ\81Ñ\85емÑ\83 оÑ\82веÑ\82а, вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c HTTP Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-код, иÑ\81полÑ\8cзÑ\83емÑ\8bй длÑ\8f оÑ\82веÑ\82а, Ñ\81 помоÑ\89Ñ\8cÑ\8e паÑ\80амеÑ\82Ñ\80а `status_code` в любой из *операций пути*:
* `@app.get()`
* `@app.post()`
/// note | Примечание
-Обратите внимание, что `status_code` является атрибутом метода-декоратора (`get`, `post` и т.д.), а не *функции-обработчика пути* в отличие от всех остальных параметров и тела запроса.
+Обратите внимание, что `status_code` — это параметр метода-декоратора (`get`, `post` и т.д.), а не вашей *функции-обработчика пути*, в отличие от всех остальных параметров и тела запроса.
///
-Параметр `status_code` принимает число, обозначающее HTTP код статуса ответа.
+Параметр `status_code` принимает число, обозначающее HTTP статус-код.
/// info | Информация
Это позволит:
* Возвращать указанный код статуса в ответе.
-* Ð\94окÑ\83менÑ\82иÑ\80оваÑ\82Ñ\8c его как код Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81а оÑ\82веÑ\82а в OpenAPI Ñ\81Ñ\85еме (а знаÑ\87иÑ\82, и в полÑ\8cзоваÑ\82елÑ\8cÑ\81ком инÑ\82еÑ\80Ñ\84ейÑ\81е):
+* Ð\94окÑ\83менÑ\82иÑ\80оваÑ\82Ñ\8c его как код Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81а оÑ\82веÑ\82а в OpenAPI Ñ\81Ñ\85еме (а знаÑ\87иÑ\82, и в полÑ\8cзоваÑ\82елÑ\8cÑ\81киÑ\85 инÑ\82еÑ\80Ñ\84ейÑ\81аÑ\85):
<img src="/img/tutorial/response-status-code/image01.png">
///
-## Об HTTP кодах статуса ответа
+## Об HTTP статус-кодах { #about-http-status-codes }
/// note | Примечание
-Если вы уже знаете, что представляют собой HTTP коды статуса ответа, можете перейти к следующему разделу.
+Если вы уже знаете, что представляют собой HTTP статус-коды, можете перейти к следующему разделу.
///
У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
-Кратко о значениях кодов:
+Кратко:
-* `1XX` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
-* **`2XX`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
+* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
+* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
* `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
* Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
- * Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
-* **`3XX`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
-* **`4XX`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
+ * Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
+* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
+* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
* Пример – код `404` для статуса "Not Found".
* Для общих ошибок со стороны клиента можно просто использовать код `400`.
-* `5XX` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов.
+* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из этих кодов статуса.
/// tip | Подсказка
-Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank">документацией <abbr title="Mozilla Developer Network">MDN</abbr> об HTTP кодах статуса ответа</a>.
+Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network – Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах</a>.
///
-## Краткие обозначения для запоминания названий кодов
+## Краткие обозначения для запоминания названий кодов { #shortcut-to-remember-the-names }
Рассмотрим предыдущий пример еще раз:
{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
-Ð\9eни Ñ\81одеÑ\80жаÑ\82 Ñ\82е же Ñ\87иÑ\81ловÑ\8bе знаÑ\87ениÑ\8f, но позволÑ\8fÑ\8eÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c подÑ\81казки Ñ\80едакÑ\82оÑ\80а для выбора кода статуса:
+Ð\9eни Ñ\81одеÑ\80жаÑ\82 Ñ\82е же Ñ\87иÑ\81ловÑ\8bе знаÑ\87ениÑ\8f, но позволÑ\8fÑ\8eÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c авÑ\82озавеÑ\80Ñ\88ение Ñ\80едакÑ\82оÑ\80а кода для выбора кода статуса:
<img src="/img/tutorial/response-status-code/image02.png">
///
-## Изменение кода статуса по умолчанию
+## Изменение кода статуса по умолчанию { #changing-the-default }
-Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP коды статуса, отличные от используемого здесь кода статуса по умолчанию.
+Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP статус-код, отличный от значения по умолчанию, которое вы объявляете здесь.
-# Ð\9eбÑ\8aÑ\8fвление пÑ\80имеÑ\80а запÑ\80оÑ\81а даннÑ\8bÑ\85
+# Ð\9eбÑ\8aÑ\8fвление пÑ\80имеÑ\80ов даннÑ\8bÑ\85 запÑ\80оÑ\81а { #declare-request-example-data }
Вы можете объявлять примеры данных, которые ваше приложение может получать.
-Вот несколько способов, как это можно сделать.
+Вот несколько способов, как это сделать.
-## Pydantic `schema_extra`
+## Дополнительные данные JSON Schema в моделях Pydantic { #extra-json-schema-data-in-pydantic-models }
-Вы можете объявить ключ `example` для модели Pydantic, используя класс `Config` и переменную `schema_extra`, как описано в <a href="https://docs.pydantic.dev/latest/concepts/json_schema/#schema-customization" class="external-link" target="_blank">Pydantic документации: Настройка схемы</a>:
+Вы можете объявить `examples` для модели Pydantic, которые будут добавлены в сгенерированную JSON Schema.
-{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:21] *}
+//// tab | Pydantic v2
-Эта дополнительная информация будет включена в **JSON Schema** выходных данных для этой модели, и она будет использоваться в документации к API.
+{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
+
+////
+
+Эта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.
+
+//// tab | Pydantic v2
+
+В Pydantic версии 2 вы будете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
+
+Вы можете задать `"json_schema_extra"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
+
+////
+
+//// tab | Pydantic v1
+
+В Pydantic версии 1 вы будете использовать внутренний класс `Config` и `schema_extra`, как описано в <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Документации Pydantic: Настройка схемы</a>.
+
+Вы можете задать `schema_extra` со `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
+
+////
/// tip | Подсказка
-Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82оÑ\82 же меÑ\82од длÑ\8f Ñ\80аÑ\81Ñ\88иÑ\80ениÑ\8f JSON-Ñ\81Ñ\85емÑ\8b и добавлениÑ\8f Ñ\81воей Ñ\81обÑ\81Ñ\82венной дополниÑ\82елÑ\8cной инÑ\84оÑ\80маÑ\86ии.
+Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82оÑ\82 же пÑ\80иÑ\91м, Ñ\87Ñ\82обÑ\8b Ñ\80аÑ\81Ñ\88иÑ\80иÑ\82Ñ\8c JSON Schema и добавиÑ\82Ñ\8c Ñ\81воÑ\8e Ñ\81обÑ\81Ñ\82веннÑ\83Ñ\8e дополниÑ\82елÑ\8cнÑ\83Ñ\8e инÑ\84оÑ\80маÑ\86иÑ\8e.
-Например, вы можете использовать это для добавления дополнительной информации для пользовательского интерфейса в вашем веб-приложении и т.д.
+Например, вы можете использовать это, чтобы добавить метаданные для фронтенд‑пользовательского интерфейса и т.д.
///
-## Дополнительные аргументы поля `Field`
+/// info | Информация
-При использовании `Field()` с моделями Pydantic, вы также можете объявлять дополнительную информацию для **JSON Schema**, передавая любые другие произвольные аргументы в функцию.
+OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) добавил поддержку `examples`, который является частью стандарта **JSON Schema**.
-Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82о, Ñ\87Ñ\82обÑ\8b добавиÑ\82Ñ\8c аÑ\80гÑ\83менÑ\82 `example` длÑ\8f каждого полÑ\8f:
+Ð\94о Ñ\8dÑ\82ого поддеÑ\80живалоÑ\81Ñ\8c Ñ\82олÑ\8cко клÑ\8eÑ\87евое Ñ\81лово `example` Ñ\81 одним пÑ\80имеÑ\80ом. Ð\9eно вÑ\81Ñ\91 еÑ\89Ñ\91 поддеÑ\80живаеÑ\82Ñ\81Ñ\8f в OpenAPI 3.1.0, но помеÑ\87ено как Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ее и не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e Ñ\81Ñ\82андаÑ\80Ñ\82а JSON Schema. Ð\9fоÑ\8dÑ\82омÑ\83 Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f мигÑ\80иÑ\80оваÑ\82Ñ\8c `example` на `examples`. ð\9f¤\93
-{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
+Подробнее — в конце этой страницы.
-/// warning | Внимание
+///
-Имейте в виду, что эти дополнительные переданные аргументы не добавляют никакой валидации, только дополнительную информацию для документации.
+## Дополнительные аргументы `Field` { #field-additional-arguments }
-///
+При использовании `Field()` с моделями Pydantic вы также можете объявлять дополнительные `examples`:
-## Использование `example` и `examples` в OpenAPI
+{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
+
+## `examples` в JSON Schema — OpenAPI { #examples-in-json-schema-openapi }
-Ð\9fÑ\80и иÑ\81полÑ\8cзовании лÑ\8eбой из Ñ\8dÑ\82иÑ\85 Ñ\84Ñ\83нкÑ\86ий:
+При использовании любой из функций:
* `Path()`
* `Query()`
* `Form()`
* `File()`
-вÑ\8b Ñ\82акже можеÑ\82е добавиÑ\82Ñ\8c аÑ\80гÑ\83менÑ\82, Ñ\81одеÑ\80жаÑ\89ий `example` или гÑ\80Ñ\83ппÑ\83 `examples` Ñ\81 дополниÑ\82елÑ\8cной инÑ\84оÑ\80маÑ\86ией, коÑ\82оÑ\80аÑ\8f бÑ\83деÑ\82 добавлена в **OpenAPI**.
+вÑ\8b Ñ\82акже можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c набоÑ\80 `examples` Ñ\81 дополниÑ\82елÑ\8cной инÑ\84оÑ\80маÑ\86ией, коÑ\82оÑ\80аÑ\8f бÑ\83деÑ\82 добавлена в иÑ\85 **JSON Schema** внÑ\83Ñ\82Ñ\80и **OpenAPI**.
-### Параметр `Body` с аргументом `example`
+### `Body` с `examples` { #body-with-examples }
-Здесь мы передаём аргумент `example`, как пример данных ожидаемых в параметре `Body()`:
+Здесь мы передаём `examples`, содержащий один пример данных, ожидаемых в `Body()`:
-{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:27] *}
+{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
-### Ð\90Ñ\80гÑ\83менÑ\82 "example" в UI докÑ\83менÑ\82аÑ\86ии
+### Ð\9fÑ\80имеÑ\80 в UI докÑ\83менÑ\82аÑ\86ии { #example-in-the-docs-ui }
-С лÑ\8eбÑ\8bм из вÑ\8bÑ\88еÑ\83казаннÑ\8bÑ\85 методов это будет выглядеть так в `/docs`:
+С лÑ\8eбÑ\8bм из пеÑ\80еÑ\87иÑ\81леннÑ\8bÑ\85 вÑ\8bÑ\88е методов это будет выглядеть так в `/docs`:
<img src="/img/tutorial/body-fields/image01.png">
-### `Body` с аргументом `examples`
+### `Body` с несколькими `examples` { #body-with-multiple-examples }
+
+Конечно, вы можете передать и несколько `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
+
+Когда вы делаете это, примеры становятся частью внутренней **JSON Schema** для данных тела запроса.
+
+Тем не менее, на <abbr title="2023-08-26">момент написания этого</abbr> Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь.
+
+### Специфические для OpenAPI `examples` { #openapi-specific-examples }
+
+Ещё до того как **JSON Schema** поддержала `examples`, в OpenAPI была поддержка другого поля, также называемого `examples`.
+
+Эти **специфические для OpenAPI** `examples` находятся в другой секции спецификации OpenAPI. Они находятся в **подробностях для каждой операции пути (обработчика пути)**, а не внутри каждого объекта Schema.
+
+И Swagger UI уже какое‑то время поддерживает именно это поле `examples`. Поэтому вы можете использовать его, чтобы **отобразить** разные **примеры в UI документации**.
+
+Структура этого специфичного для OpenAPI поля `examples` — это `dict` с **несколькими примерами** (вместо `list`), каждый с дополнительной информацией, которая также будет добавлена в **OpenAPI**.
+
+Это не помещается внутрь каждого объекта Schema в OpenAPI, это находится снаружи, непосредственно на уровне самой *операции пути*.
+
+### Использование параметра `openapi_examples` { #using-the-openapi-examples-parameter }
+
+Вы можете объявлять специфические для OpenAPI `examples` в FastAPI с помощью параметра `openapi_examples` для:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
-Ð\92 каÑ\87еÑ\81Ñ\82ве алÑ\8cÑ\82еÑ\80наÑ\82ивÑ\8b одномÑ\83 аÑ\80гÑ\83менÑ\82Ñ\83 `example`, вÑ\8b можеÑ\82е пеÑ\80едаваÑ\82Ñ\8c `examples` иÑ\81полÑ\8cзÑ\83Ñ\8f Ñ\82ип даннÑ\8bÑ\85 `dict` Ñ\81 **неÑ\81колÑ\8cкими пÑ\80имеÑ\80ами**, каждÑ\8bй из коÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81одеÑ\80жиÑ\82 дополниÑ\82елÑ\8cнÑ\83Ñ\8e инÑ\84оÑ\80маÑ\86иÑ\8e, коÑ\82оÑ\80аÑ\8f Ñ\82акже бÑ\83деÑ\82 добавлена в **OpenAPI**.
+Ð\9aлÑ\8eÑ\87и `dict` иденÑ\82иÑ\84иÑ\86иÑ\80Ñ\83Ñ\8eÑ\82 каждÑ\8bй пÑ\80имеÑ\80, а каждое знаÑ\87ение â\80\94 Ñ\8dÑ\82о еÑ\89Ñ\91 один `dict`.
-Ð\9aлÑ\8eÑ\87и `dict` Ñ\83казÑ\8bваÑ\8eÑ\82 на каждÑ\8bй пÑ\80имеÑ\80, а знаÑ\87ениÑ\8f длÑ\8f каждого из ниÑ\85 - на еÑ\89е один Ñ\82ип `dict` Ñ\81 дополниÑ\82елÑ\8cной инÑ\84оÑ\80маÑ\86ией.
+Ð\9aаждÑ\8bй конкÑ\80еÑ\82нÑ\8bй пÑ\80имеÑ\80â\80\91`dict` в `examples` можеÑ\82 Ñ\81одеÑ\80жаÑ\82Ñ\8c:
-Каждый конкретный пример типа `dict` в аргументе `examples` может содержать:
+* `summary`: Краткое описание примера.
+* `description`: Подробное описание, которое может содержать текст в Markdown.
+* `value`: Это фактический пример, который отображается, например, `dict`.
+* `externalValue`: альтернатива `value`, URL, указывающий на пример. Хотя это может поддерживаться не так многими инструментами, как `value`.
-* `summary`: Краткое описание для примера.
-* `description`: Полное описание, которое может содержать текст в формате Markdown.
-* `value`: Это конкретный пример, который отображается, например, в виде типа `dict`.
-* `externalValue`: альтернатива параметру `value`, URL-адрес, указывающий на пример. Хотя это может не поддерживаться таким же количеством инструментов разработки и тестирования API, как параметр `value`.
+Использовать это можно так:
-{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:49] *}
+{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
-### Аргумент "examples" в UI документации
+### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
-С аргументом `examples`, добавленным в `Body()`, страница документации `/docs` будет выглядеть так:
+С `openapi_examples`, добавленным в `Body()`, страница `/docs` будет выглядеть так:
<img src="/img/tutorial/body-fields/image02.png">
-## Технические Детали
+## Технические детали { #technical-details }
+
+/// tip | Подсказка
+
+Если вы уже используете **FastAPI** версии **0.99.0 или выше**, вы, вероятно, можете **пропустить** эти подробности.
+
+Они более актуальны для старых версий, до того как стала доступна OpenAPI 3.1.0.
+
+Считайте это кратким **уроком истории** про OpenAPI и JSON Schema. 🤓
+
+///
/// warning | Внимание
-ÐÑ\82и Ñ\82еÑ\85ниÑ\87еÑ\81кие деÑ\82али оÑ\82ноÑ\81Ñ\8fÑ\82Ñ\81Ñ\8f к Ñ\81Ñ\82андаÑ\80Ñ\82ам **JSON Schema** и **OpenAPI**.
+Ð\94алее идÑ\83Ñ\82 оÑ\87енÑ\8c Ñ\82еÑ\85ниÑ\87еÑ\81кие подÑ\80обноÑ\81Ñ\82и о Ñ\81Ñ\82андаÑ\80Ñ\82аÑ\85 **JSON Schema** и **OpenAPI**.
-Ð\95Ñ\81ли пÑ\80едложеннÑ\8bе вÑ\8bÑ\88е идеи Ñ\83же Ñ\80абоÑ\82аÑ\8eÑ\82 длÑ\8f ваÑ\81, возможно Ñ\8dÑ\82ого бÑ\83деÑ\82 доÑ\81Ñ\82аÑ\82оÑ\87но и Ñ\8dÑ\82и деÑ\82али вам не поÑ\82Ñ\80ебÑ\83Ñ\8eÑ\82Ñ\81Ñ\8f, можеÑ\82е Ñ\81покойно иÑ\85 пÑ\80опÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c.
+Ð\95Ñ\81ли идеи вÑ\8bÑ\88е Ñ\83же Ñ\80абоÑ\82аÑ\8eÑ\82 длÑ\8f ваÑ\81, Ñ\8dÑ\82ого можеÑ\82 бÑ\8bÑ\82Ñ\8c доÑ\81Ñ\82аÑ\82оÑ\87но, и, веÑ\80оÑ\8fÑ\82но, вам не нÑ\83жнÑ\8b Ñ\8dÑ\82и деÑ\82али â\80\94 Ñ\81мело пÑ\80опÑ\83Ñ\81кайÑ\82е иÑ\85.
///
-Когда вы добавляете пример внутрь модели Pydantic, используя `schema_extra` или `Field(example="something")`, этот пример добавляется в **JSON Schema** для данной модели Pydantic.
+До OpenAPI 3.1.0 OpenAPI использовала более старую и модифицированную версию **JSON Schema**.
+
+В JSON Schema не было `examples`, поэтому OpenAPI добавила собственное поле `example` в свою модифицированную версию.
+
+OpenAPI также добавила поля `example` и `examples` в другие части спецификации:
+
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (в спецификации)</a>, которое использовалось в FastAPI:
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, в поле `content`, в `Media Type Object` (в спецификации)</a>, которое использовалось в FastAPI:
+ * `Body()`
+ * `File()`
+ * `Form()`
+
+/// info | Информация
+
+Этот старый специфичный для OpenAPI параметр `examples` теперь называется `openapi_examples`, начиная с FastAPI `0.103.0`.
+
+///
+
+### Поле `examples` в JSON Schema { #json-schemas-examples-field }
+
+Позже в новой версии спецификации JSON Schema было добавлено поле <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>.
+
+А затем новый OpenAPI 3.1.0 был основан на последней версии (JSON Schema 2020-12), которая включала это новое поле `examples`.
+
+И теперь это новое поле `examples` имеет приоритет над старым одиночным (и кастомным) полем `example`, которое теперь устарело.
+
+Это новое поле `examples` в JSON Schema — это **просто `list`** примеров, а не dict с дополнительными метаданными, как в других местах OpenAPI (описанных выше).
+
+/// info | Информация
+
+Даже после того как OpenAPI 3.1.0 была выпущена с этой новой, более простой интеграцией с JSON Schema, какое‑то время Swagger UI, инструмент, предоставляющий автоматическую документацию, не поддерживал OpenAPI 3.1.0 (поддержка появилась начиная с версии 5.0.0 🎉).
+
+Из‑за этого версии FastAPI до 0.99.0 всё ещё использовали версии OpenAPI ниже 3.1.0.
+
+///
+
+### `examples` в Pydantic и FastAPI { #pydantic-and-fastapi-examples }
+
+Когда вы добавляете `examples` внутри модели Pydantic, используя `schema_extra` или `Field(examples=["something"])`, этот пример добавляется в **JSON Schema** для этой модели Pydantic.
И эта **JSON Schema** модели Pydantic включается в **OpenAPI** вашего API, а затем используется в UI документации.
-Поля `example` как такового не существует в стандартах **JSON Schema**. В последних версиях JSON-схемы определено поле <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>, но OpenAPI 3.0.3 основан на более старой версии JSON-схемы, которая не имела поля `examples`.
+В версиях FastAPI до 0.99.0 (0.99.0 и выше используют новый OpenAPI 3.1.0), когда вы использовали `example` или `examples` с любыми другими утилитами (`Query()`, `Body()`, и т.д.), эти примеры не добавлялись в JSON Schema, описывающую эти данные (даже в собственную версию JSON Schema OpenAPI), они добавлялись непосредственно в объявление *операции пути* в OpenAPI (вне частей OpenAPI, использующих JSON Schema).
+
+Но теперь, когда FastAPI 0.99.0 и выше используют OpenAPI 3.1.0, который использует JSON Schema 2020-12, а также Swagger UI 5.0.0 и выше, всё стало более последовательным, и примеры включаются в JSON Schema.
-Таким образом, OpenAPI 3.0.3 определяет своё собственное поле <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-20" class="external-link" target="_blank">`example`</a> для модифицированной версии **JSON Schema**, которую он использует чтобы достичь той же цели (однако это именно поле `example`, а не `examples`), и именно это используется API в UI документации (с интеграцией Swagger UI).
+### Swagger UI и специфичные для OpenAPI `examples` { #swagger-ui-and-openapi-specific-examples }
-Ð\98Ñ\82ак, Ñ\85оÑ\82Ñ\8f поле `example` не Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e JSON-Ñ\81Ñ\85емÑ\8b, оно Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e наÑ\81Ñ\82Ñ\80аиваемой веÑ\80Ñ\81ии JSON-Ñ\81Ñ\85емÑ\8b в OpenAPI, и именно Ñ\8dÑ\82о поле бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f в UI документации.
+РанÑ\8cÑ\88е, поÑ\81колÑ\8cкÑ\83 Swagger UI не поддеÑ\80живал неÑ\81колÑ\8cко пÑ\80имеÑ\80ов JSON Schema (по Ñ\81оÑ\81Ñ\82оÑ\8fниÑ\8e на 2023-08-26), Ñ\83 полÑ\8cзоваÑ\82елей не бÑ\8bло Ñ\81поÑ\81оба показаÑ\82Ñ\8c неÑ\81колÑ\8cко пÑ\80имеÑ\80ов в документации.
-Ð\9eднако, когда вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е поле `example` или `examples` Ñ\81 лÑ\8eбой дÑ\80Ñ\83гой Ñ\84Ñ\83нкÑ\86ией (`Query()`, `Body()`, и Ñ\82.д.), Ñ\8dÑ\82и пÑ\80имеÑ\80Ñ\8b не добавлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f в JSON-Ñ\81Ñ\85емÑ\83, коÑ\82оÑ\80аÑ\8f опиÑ\81Ñ\8bваеÑ\82 Ñ\8dÑ\82и даннÑ\8bе (даже в Ñ\81обÑ\81Ñ\82веннÑ\83Ñ\8e веÑ\80Ñ\81иÑ\8e JSON-Ñ\81Ñ\85емÑ\8b OpenAPI), они добавлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f непоÑ\81Ñ\80едÑ\81Ñ\82венно в обÑ\8aÑ\8fвление *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* в OpenAPI (вне Ñ\87аÑ\81Ñ\82ей OpenAPI, коÑ\82оÑ\80Ñ\8bе иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 JSON-Ñ\81Ñ\85емÑ\83).
+ЧÑ\82обÑ\8b Ñ\80еÑ\88иÑ\82Ñ\8c Ñ\8dÑ\82о, FastAPI `0.103.0` **добавил поддеÑ\80жкÑ\83** обÑ\8aÑ\8fвлениÑ\8f Ñ\82ого же Ñ\81Ñ\82аÑ\80ого, **Ñ\81пеÑ\86иÑ\84иÑ\87ного длÑ\8f OpenAPI**, полÑ\8f `examples` Ñ\81 новÑ\8bм паÑ\80амеÑ\82Ñ\80ом `openapi_examples`. ð\9f¤\93
-Для функций `Path()`, `Query()`, `Header()`, и `Cookie()`, аргументы `example` или `examples` добавляются в <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameter-object" class="external-link" target="_blank">определение OpenAPI, к объекту `Parameter Object` (в спецификации)</a>.
+### Итог { #summary }
-Ð\98 длÑ\8f Ñ\84Ñ\83нкÑ\86ий `Body()`, `File()` и `Form()` аÑ\80гÑ\83менÑ\82Ñ\8b `example` или `examples` аналогиÑ\87но добавлÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f в <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#mediaTypeObject" class="external-link" target="_blank"> опÑ\80еделение OpenAPI, к обÑ\8aекÑ\82Ñ\83 `Request Body Object`, в поле `content` в обÑ\8aекÑ\82е `Media Type Object` (в Ñ\81пеÑ\86иÑ\84икаÑ\86ии)</a>.
+РанÑ\8cÑ\88е Ñ\8f говоÑ\80ил, Ñ\87Ñ\82о не оÑ\87енÑ\8c лÑ\8eблÑ\8e иÑ\81Ñ\82оÑ\80иÑ\8e... а Ñ\82епеÑ\80Ñ\8c воÑ\82 Ñ\80аÑ\81Ñ\81казÑ\8bваÑ\8e «Ñ\83Ñ\80оки Ñ\82еÑ\85ниÑ\87еÑ\81кой иÑ\81Ñ\82оÑ\80ии». ð\9f\98\85
-С дÑ\80Ñ\83гой Ñ\81Ñ\82оÑ\80онÑ\8b, Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 более новаÑ\8f веÑ\80Ñ\81иÑ\8f OpenAPI: **3.1.0**, недавно вÑ\8bпÑ\83Ñ\89еннаÑ\8f. Ð\9eна оÑ\81нована на поÑ\81ледней веÑ\80Ñ\81ии JSON-Ñ\81Ñ\85емÑ\8b и болÑ\8cÑ\88инÑ\81Ñ\82во модиÑ\84икаÑ\86ий из OpenAPI JSON-Ñ\81Ñ\85емÑ\8b Ñ\83даленÑ\8b в обмен на новÑ\8bе возможноÑ\81Ñ\82и из поÑ\81ледней веÑ\80Ñ\81ии JSON-Ñ\81Ñ\85емÑ\8b, Ñ\82ак Ñ\87Ñ\82о вÑ\81е Ñ\8dÑ\82и мелкие оÑ\82лиÑ\87иÑ\8f Ñ\83Ñ\81Ñ\82Ñ\80аненÑ\8b. Тем не менее, Swagger UI в наÑ\81Ñ\82оÑ\8fÑ\89ее вÑ\80емÑ\8f не поддеÑ\80живаеÑ\82 OpenAPI 3.1.0, поÑ\8dÑ\82омÑ\83 пока лÑ\83Ñ\87Ñ\88е пÑ\80одолжаÑ\82Ñ\8c иÑ\81полÑ\8cзоваÑ\82Ñ\8c вÑ\8bÑ\88еÑ\83помÑ\8fнÑ\83Ñ\82Ñ\8bе меÑ\82одÑ\8b.
+Ð\9aоÑ\80оÑ\82ко: **обновиÑ\82еÑ\81Ñ\8c до FastAPI 0.99.0 или вÑ\8bÑ\88е** â\80\94 Ñ\82ак вÑ\81Ñ\91 бÑ\83деÑ\82 знаÑ\87иÑ\82елÑ\8cно **пÑ\80оÑ\89е, поÑ\81ледоваÑ\82елÑ\8cнее и инÑ\82Ñ\83иÑ\82ивнее**, и вам не пÑ\80идÑ\91Ñ\82Ñ\81Ñ\8f знаÑ\82Ñ\8c вÑ\81е Ñ\8dÑ\82и иÑ\81Ñ\82оÑ\80иÑ\87еÑ\81кие подÑ\80обноÑ\81Ñ\82и. ð\9f\98\8e
-# Безопасность - первые шаги
+# Безопасность — первые шаги { #security-first-steps }
-Представим, что у вас есть свой **бэкенд** API на некотором домене.
+Представим, что у вас есть **бэкенд** API на некотором домене.
И у вас есть **фронтенд** на другом домене или на другом пути того же домена (или в мобильном приложении).
-И вы хотите иметь возможность аутентификации фронтенда с бэкендом, используя **имя пользователя** и **пароль**.
+И вы хотите, чтобы фронтенд мог аутентифицироваться на бэкенде, используя **имя пользователя** и **пароль**.
-Мы можем использовать **OAuth2** для создания такой системы с помощью **FastAPI**.
+Мы можем использовать **OAuth2**, чтобы построить это с **FastAPI**.
-Но давайте избавим вас от необходимости читать всю длинную спецификацию, чтобы найти те небольшие кусочки информации, которые вам нужны.
+Но давайте сэкономим вам время на чтение всей длинной спецификации в поисках тех небольших фрагментов информации, которые вам нужны.
-Ð\94лÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 безопаÑ\81ноÑ\81Ñ\82Ñ\8cÑ\8e воÑ\81полÑ\8cзÑ\83емÑ\81Ñ\8f Ñ\81Ñ\80едÑ\81Ñ\82вами, пÑ\80едоÑ\81Ñ\82авленнÑ\8bми **FastAPI**.
+Ð\92оÑ\81полÑ\8cзÑ\83емÑ\81Ñ\8f инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82ами, пÑ\80едоÑ\81Ñ\82авленнÑ\8bми **FastAPI**, Ñ\87Ñ\82обÑ\8b Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 безопаÑ\81ноÑ\81Ñ\82Ñ\8cÑ\8e.
-## Как это выглядит
+## Как это выглядит { #how-it-looks }
-Ð\94авайÑ\82е Ñ\81наÑ\87ала пÑ\80оÑ\81Ñ\82о воÑ\81полÑ\8cзÑ\83емÑ\81Ñ\8f кодом и поÑ\81моÑ\82Ñ\80им, как он Ñ\80абоÑ\82аеÑ\82, а заÑ\82ем деÑ\82алÑ\8cно Ñ\80азбеÑ\80Ñ\91м, что происходит.
+СнаÑ\87ала пÑ\80оÑ\81Ñ\82о воÑ\81полÑ\8cзÑ\83емÑ\81Ñ\8f кодом и поÑ\81моÑ\82Ñ\80им, как он Ñ\80абоÑ\82аеÑ\82, а заÑ\82ем веÑ\80немÑ\81Ñ\8f и Ñ\80азбеÑ\80емÑ\81Ñ\8f, что происходит.
-## Создание `main.py`
+## Создание `main.py` { #create-main-py }
Скопируйте пример в файл `main.py`:
{* ../../docs_src/security/tutorial001_an_py39.py *}
-## Запуск
+## Запуск { #run-it }
/// info | Дополнительная информация
-Ð\92наÑ\87але, Ñ\83Ñ\81Ñ\82ановиÑ\82е библиоÑ\82екÑ\83 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>.
+Ð\9fакеÑ\82 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a> авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\83Ñ\81Ñ\82анавливаеÑ\82Ñ\81Ñ\8f вмеÑ\81Ñ\82е Ñ\81 **FastAPI**, еÑ\81ли вÑ\8b запÑ\83Ñ\81каеÑ\82е командÑ\83 `pip install "fastapi[standard]"`.
-Ð\90 именно: `pip install python-multipart`.
+Ð\9eднако, еÑ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е командÑ\83 `pip install fastapi`, пакеÑ\82 `python-multipart` по Ñ\83молÑ\87аниÑ\8e не вклÑ\8eÑ\87аеÑ\82Ñ\81Ñ\8f.
-Это связано с тем, что **OAuth2** использует "данные формы" для передачи `имени пользователя` и `пароля`.
+Чтобы установить его вручную, убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md){.internal-link target=_blank}, активировали его и затем установили пакет:
+
+```console
+$ pip install python-multipart
+```
+
+Это связано с тем, что **OAuth2** использует «данные формы» для отправки `username` и `password`.
///
-Ð\97апÑ\83Ñ\81Ñ\82иÑ\82е ваÑ\88 Ñ\81еÑ\80веÑ\80:
+Ð\97апÑ\83Ñ\81Ñ\82иÑ\82е пÑ\80имеÑ\80 командой:
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
-## Проверка
+## Проверка { #check-it }
Перейдите к интерактивной документации по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
/// check | Кнопка авторизации!
-У вас уже появилась новая кнопка "Authorize".
+У вас уже появилась новая кнопка «Authorize».
-А у *операции пути* теперь появился маленький замочек в правом верхнем углу, на который можно нажать.
+А у вашей *операции пути* в правом верхнем углу есть маленький замочек, на который можно нажать.
///
-Ð\9fÑ\80и нажаÑ\82ии на нее поÑ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f неболÑ\8cÑ\88аÑ\8f Ñ\84оÑ\80ма авÑ\82оÑ\80изаÑ\86ии, в коÑ\82оÑ\80Ñ\83Ñ\8e нÑ\83жно ввеÑ\81Ñ\82и `имÑ\8f полÑ\8cзоваÑ\82елÑ\8f` и `паÑ\80олÑ\8c` (и другие необязательные поля):
+Ð\95Ñ\81ли нажаÑ\82Ñ\8c на нее, поÑ\8fвиÑ\82Ñ\81Ñ\8f неболÑ\8cÑ\88аÑ\8f Ñ\84оÑ\80ма авÑ\82оÑ\80изаÑ\86ии, в коÑ\82оÑ\80Ñ\83Ñ\8e нÑ\83жно ввеÑ\81Ñ\82и `username` и `password` (и другие необязательные поля):
<img src="/img/tutorial/security/image02.png">
-/// note | ТеÑ\85ниÑ\87еÑ\81кие деÑ\82али
+/// note | Ð\9fÑ\80имеÑ\87ание
-Неважно, что вы введете в форму, она пока не будет работать. Но мы к этому еще придем.
+Неважно, что вы введете в форму — пока это не будет работать. Но мы скоро до этого дойдем.
///
-Конечно, это не фронтенд для конечных пользователей, но это отличный автоматический инструмент для интерактивного документирования всех ваших API.
+Конечно, это не фронтенд для конечных пользователей, но это отличный автоматический инструмент для интерактивного документирования всего вашего API.
-Ð\9eн можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f командой фронтенда (которой можете быть и вы сами).
+Ð\98м можеÑ\82 полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f команда фронтенда (которой можете быть и вы сами).
-Ð\9eн можеÑ\82 бÑ\8bÑ\82Ñ\8c иÑ\81полÑ\8cзован Ñ\81Ñ\82оÑ\80онними пÑ\80иложениÑ\8fми и Ñ\81иÑ\81Ñ\82емами.
+Ð\98м могÑ\83Ñ\82 полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81Ñ\82оÑ\80онние пÑ\80иложениÑ\8f и Ñ\81иÑ\81Ñ\82емÑ\8b.
-Ð\9aÑ\80оме Ñ\82ого, его можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно длÑ\8f оÑ\82ладки, пÑ\80овеÑ\80ки и Ñ\82еÑ\81Ñ\82иÑ\80ованиÑ\8f одного и Ñ\82ого же пÑ\80иложениÑ\8f.
+Ð\98 им Ñ\82акже можеÑ\82е полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f вÑ\8b Ñ\81ами, Ñ\87Ñ\82обÑ\8b оÑ\82лаживаÑ\82Ñ\8c, пÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c и Ñ\82еÑ\81Ñ\82иÑ\80оваÑ\82Ñ\8c Ñ\82о же Ñ\81амое пÑ\80иложение.
-## Аутентификация по паролю
+## «`password` flow» (аутентификация по паролю) { #the-password-flow }
-ТепеÑ\80Ñ\8c давайÑ\82е веÑ\80немÑ\81Ñ\8f немного назад и Ñ\80азбеÑ\80емÑ\81Ñ\8f, Ñ\87Ñ\82о же Ñ\8dÑ\82о такое.
+ТепеÑ\80Ñ\8c давайÑ\82е немного веÑ\80немÑ\81Ñ\8f и Ñ\80азбеÑ\80емÑ\81Ñ\8f, Ñ\87Ñ\82о Ñ\8dÑ\82о вÑ\81е такое.
-Аутентификация по паролю является одним из способов, определенных в OAuth2, для обеспечения безопасности и аутентификации.
+«`password` flow» — это один из способов («flows»), определенных в OAuth2, для обеспечения безопасности и аутентификации.
-OAuth2 бÑ\8bл Ñ\80азÑ\80абоÑ\82ан длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b бÑ\8dкÑ\8dнд или API были независимы от сервера, который аутентифицирует пользователя.
+OAuth2 бÑ\8bл Ñ\81пÑ\80оекÑ\82иÑ\80ован Ñ\82ак, Ñ\87Ñ\82обÑ\8b бÑ\8dкенд или API были независимы от сервера, который аутентифицирует пользователя.
-Но в нашем случае одно и то же приложение **FastAPI** будет работать с API и аутентификацией.
+Но в нашем случае одно и то же приложение **FastAPI** будет работать и с API, и с аутентификацией.
-Итак, рассмотрим его с этой упрощенной точки зрения:
+Итак, рассмотрим это с упрощенной точки зрения:
-* Пользователь вводит на фронтенде `имя пользователя` и `пароль` и нажимает `Enter`.
-* Фронтенд (работающий в браузере пользователя) отправляет эти `имя пользователя` и `пароль` на определенный URL в нашем API (объявленный с помощью параметра `tokenUrl="token"`).
-* API пÑ\80овеÑ\80Ñ\8fеÑ\82 Ñ\8dÑ\82и `имÑ\8f полÑ\8cзоваÑ\82елÑ\8f` и `паÑ\80олÑ\8c` и вÑ\8bдаеÑ\82 в оÑ\82веÑ\82 "Ñ\82окен" (мÑ\8b еÑ\89е не Ñ\80еализовали ниÑ\87его из Ñ\8dÑ\82ого).
- * "Токен" - это просто строка с некоторым содержимым, которое мы можем использовать позже для верификации пользователя.
- * Ð\9eбÑ\8bÑ\87но Ñ\81Ñ\80ок дейÑ\81Ñ\82виÑ\8f Ñ\82окена истекает через некоторое время.
- * Таким обÑ\80азом, полÑ\8cзоваÑ\82елÑ\8e пÑ\80идеÑ\82Ñ\81Ñ\8f Ñ\81нова войÑ\82и в Ñ\81иÑ\81Ñ\82емÑ\83 в какой-Ñ\82о моменÑ\82 вÑ\80емени.
- * И если токен будет украден, то риск будет меньше, так как он не похож на постоянный ключ, который будет работать вечно (в большинстве случаев).
-* Фронтенд временно хранит этот токен в каком-то месте.
-* Пользователь щелкает мышью на фронтенде, чтобы перейти в другой раздел на фронтенде.
-* Фронтенду необходимо получить дополнительные данные из API.
- * Ð\9dо длÑ\8f Ñ\8dÑ\82ого необÑ\85одима аÑ\83Ñ\82енÑ\82иÑ\84икаÑ\86иÑ\8f длÑ\8f конкÑ\80еÑ\82ной конеÑ\87ной Ñ\82оÑ\87ки.
- * Поэтому для аутентификации в нашем API он посылает заголовок `Authorization` со значением `Bearer` плюс сам токен.
- * Ð\95Ñ\81ли Ñ\82окен Ñ\81одеÑ\80жиÑ\82 `foobar`, Ñ\82о Ñ\81одеÑ\80жание заголовка `Authorization` бÑ\83деÑ\82 Ñ\82аким: `Bearer foobar`.
+* Пользователь вводит на фронтенде `username` и `password` и нажимает `Enter`.
+* Фронтенд (работающий в браузере пользователя) отправляет эти `username` и `password` на конкретный URL в нашем API (объявленный с `tokenUrl="token"`).
+* API пÑ\80овеÑ\80Ñ\8fеÑ\82 Ñ\8dÑ\82оÑ\82 `username` и `password` и оÑ\82веÑ\87аеÑ\82 «Ñ\82океном» (мÑ\8b еÑ\89е ниÑ\87его из Ñ\8dÑ\82ого не Ñ\80еализовали).
+ * «Токен» — это просто строка с некоторым содержимым, которое мы сможем позже использовать для проверки этого пользователя.
+ * Ð\9eбÑ\8bÑ\87но Ñ\83 Ñ\82окена Ñ\83Ñ\81Ñ\82ановлен Ñ\81Ñ\80ок дейÑ\81Ñ\82виÑ\8f: он истекает через некоторое время.
+ * Ð\9fоÑ\8dÑ\82омÑ\83 полÑ\8cзоваÑ\82елÑ\8e пÑ\80идеÑ\82Ñ\81Ñ\8f Ñ\81нова войÑ\82и в Ñ\81иÑ\81Ñ\82емÑ\83 в какойâ\80\91Ñ\82о моменÑ\82.
+ * И если токен украдут, риск меньше: это не постоянный ключ, который будет работать вечно (в большинстве случаев).
+* Фронтенд временно где‑то хранит этот токен.
+* Пользователь кликает во фронтенде, чтобы перейти в другой раздел веб‑приложения.
+* Фронтенду нужно получить дополнительные данные из API.
+ * Ð\9dо длÑ\8f Ñ\8dÑ\82ого длÑ\8f конкÑ\80еÑ\82ной конеÑ\87ной Ñ\82оÑ\87ки нÑ\83жна аÑ\83Ñ\82енÑ\82иÑ\84икаÑ\86иÑ\8f.
+ * Поэтому, чтобы аутентифицироваться в нашем API, он отправляет HTTP-заголовок `Authorization` со значением `Bearer ` плюс сам токен.
+ * Ð\95Ñ\81ли Ñ\82окен Ñ\81одеÑ\80жиÑ\82 `foobar`, Ñ\82о Ñ\81одеÑ\80жимое заголовка `Authorization` бÑ\83деÑ\82: `Bearer foobar`.
-## Класс `OAuth2PasswordBearer` в **FastAPI**
+## Класс `OAuth2PasswordBearer` в **FastAPI** { #fastapis-oauth2passwordbearer }
**FastAPI** предоставляет несколько средств на разных уровнях абстракции для реализации этих функций безопасности.
-В данном примере мы будем использовать **OAuth2**, с аутентификацией по паролю, используя токен **Bearer**. Для этого мы используем класс `OAuth2PasswordBearer`.
+В этом примере мы будем использовать **OAuth2**, с потоком **Password**, используя токен **Bearer**. Для этого мы используем класс `OAuth2PasswordBearer`.
/// info | Дополнительная информация
-Токен "bearer" - не единственный вариант, но для нашего случая он является наилучшим.
+Токен «bearer» — не единственный вариант.
+
+Но для нашего случая он — лучший.
-И это может быть лучшим вариантом для большинства случаев использования, если только вы не являетесь экспертом в области OAuth2 и точно знаете, почему вам лучше подходит какой-то другой вариант.
+И он может быть лучшим для большинства случаев использования, если только вы не являетесь экспертом по OAuth2 и точно знаете, почему другой вариант лучше подходит под ваши нужды.
-В этом случае **FastAPI** также предоставляет инструменты для его реализации.
+В этом случае **FastAPI** также предоставляет инструменты, чтобы его реализовать.
///
-Ð\9fÑ\80и Ñ\81оздании Ñ\8dкземплÑ\8fÑ\80а клаÑ\81Ñ\81а `OAuth2PasswordBearer` мÑ\8b пеÑ\80едаем в него паÑ\80амеÑ\82Ñ\80 `tokenUrl`. ÐÑ\82оÑ\82 паÑ\80амеÑ\82Ñ\80 Ñ\81одеÑ\80жиÑ\82 URL, коÑ\82оÑ\80Ñ\8bй клиенÑ\82 (Ñ\84Ñ\80онÑ\82енд, Ñ\80абоÑ\82аÑ\8eÑ\89ий в бÑ\80аÑ\83зеÑ\80е полÑ\8cзоваÑ\82елÑ\8f) бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c длÑ\8f оÑ\82пÑ\80авки `имени полÑ\8cзоваÑ\82елÑ\8f` и `паÑ\80олÑ\8f` Ñ\81 Ñ\86елÑ\8cÑ\8e полÑ\83Ñ\87ениÑ\8f Ñ\82окена.
+Ð\9fÑ\80и Ñ\81оздании Ñ\8dкземплÑ\8fÑ\80а клаÑ\81Ñ\81а `OAuth2PasswordBearer` мÑ\8b пеÑ\80едаем паÑ\80амеÑ\82Ñ\80 `tokenUrl`. ÐÑ\82оÑ\82 паÑ\80амеÑ\82Ñ\80 Ñ\81одеÑ\80жиÑ\82 URL, коÑ\82оÑ\80Ñ\8bй клиенÑ\82 (Ñ\84Ñ\80онÑ\82енд, Ñ\80абоÑ\82аÑ\8eÑ\89ий в бÑ\80аÑ\83зеÑ\80е полÑ\8cзоваÑ\82елÑ\8f) бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c длÑ\8f оÑ\82пÑ\80авки `username` и `password`, Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87иÑ\82Ñ\8c Ñ\82окен.
{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
Здесь `tokenUrl="token"` ссылается на относительный URL `token`, который мы еще не создали. Поскольку это относительный URL, он эквивалентен `./token`.
-Ð\9fоÑ\81колÑ\8cкÑ\83 мÑ\8b иÑ\81полÑ\8cзÑ\83ем оÑ\82ноÑ\81иÑ\82елÑ\8cнÑ\8bй URL, еÑ\81ли ваÑ\88 API Ñ\80аÑ\81положен по адÑ\80еÑ\81Ñ\83 `https://example.com/`, Ñ\82о он бÑ\83деÑ\82 Ñ\81Ñ\81Ñ\8bлаÑ\82Ñ\8cÑ\81Ñ\8f на `https://example.com/token`. Ð\95Ñ\81ли же ваш API расположен по адресу `https://example.com/api/v1/`, то он будет ссылаться на `https://example.com/api/v1/token`.
+Ð\9fоÑ\81колÑ\8cкÑ\83 мÑ\8b иÑ\81полÑ\8cзÑ\83ем оÑ\82ноÑ\81иÑ\82елÑ\8cнÑ\8bй URL, еÑ\81ли ваÑ\88 API Ñ\80аÑ\81положен по адÑ\80еÑ\81Ñ\83 `https://example.com/`, Ñ\82о он бÑ\83деÑ\82 Ñ\81Ñ\81Ñ\8bлаÑ\82Ñ\8cÑ\81Ñ\8f на `https://example.com/token`. Ð\90 еÑ\81ли ваш API расположен по адресу `https://example.com/api/v1/`, то он будет ссылаться на `https://example.com/api/v1/token`.
-Ð\98Ñ\81полÑ\8cзование оÑ\82ноÑ\81иÑ\82елÑ\8cного URL важно длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b ваÑ\88е пÑ\80иложение пÑ\80одолжало Ñ\80абоÑ\82аÑ\82Ñ\8c даже в Ñ\82акиÑ\85 Ñ\81ложнÑ\8bÑ\85 Ñ\81лÑ\83Ñ\87аÑ\8fÑ\85, как оно наÑ\85одиÑ\82Ñ\81Ñ\8f [за прокси-сервером](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
+Ð\98Ñ\81полÑ\8cзование оÑ\82ноÑ\81иÑ\82елÑ\8cного URL важно длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b ваÑ\88е пÑ\80иложение пÑ\80одолжало Ñ\80абоÑ\82аÑ\82Ñ\8c даже в Ñ\82аком пÑ\80одвинÑ\83Ñ\82ом Ñ\81лÑ\83Ñ\87ае, как [Ð\97а прокси-сервером](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
///
-Этот параметр не создает конечную точку / *операцию пути*, а объявляет, что URL `/token` будет таким, который клиент должен использовать для получения токена. Эта информация используется в OpenAPI, а затем в интерактивных системах документации API.
+Этот параметр не создает конечную точку / *операцию пути*, а объявляет, что URL `/token` — это тот, который клиент должен использовать для получения токена. Эта информация используется в OpenAPI, а затем в интерактивных системах документации по API.
-Ð\92Ñ\81коÑ\80е мÑ\8b создадим и саму операцию пути.
+СкоÑ\80о мÑ\8b Ñ\82акже создадим и саму операцию пути.
/// info | Дополнительная информация
-Если вы очень строгий "питонист", то вам может не понравиться стиль названия параметра `tokenUrl` вместо `token_url`.
+Если вы очень строгий «питонист», вам может не понравиться стиль имени параметра `tokenUrl` вместо `token_url`.
-Это связано с тем, что тут используется то же имя, что и в спецификации OpenAPI. Таким образом, если вам необходимо более подробно изучить какую-либо из этих схем безопасности, вы можете просто использовать копирование/вставку, чтобы найти дополнительную информацию о ней.
+Это потому, что используется то же имя, что и в спецификации OpenAPI. Так, если вам нужно разобраться подробнее в какой‑то из этих схем безопасности, вы можете просто скопировать и вставить это имя, чтобы найти больше информации.
///
-Переменная `oauth2_scheme` является экземпляром `OAuth2PasswordBearer`, но она также является "вызываемой".
+Переменная `oauth2_scheme` — это экземпляр `OAuth2PasswordBearer`, но она также «вызываемая».
-Ð\95е можно вÑ\8bзваÑ\82Ñ\8c Ñ\81ледÑ\83Ñ\8eÑ\89им обÑ\80азом:
+Ð\95е можно вÑ\8bзваÑ\82Ñ\8c Ñ\82ак:
```Python
oauth2_scheme(some, parameters)
Поэтому ее можно использовать вместе с `Depends`.
-### Использование
+### Использование { #use-it }
-Теперь вы можете передать ваш `oauth2_scheme` в зависимость с помощью `Depends`.
+Теперь вы можете передать `oauth2_scheme` как зависимость с `Depends`.
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
-ÐÑ\82а завиÑ\81имоÑ\81Ñ\82Ñ\8c бÑ\83деÑ\82 пÑ\80едоÑ\81Ñ\82авлÑ\8fÑ\82Ñ\8c `Ñ\81Ñ\82Ñ\80окÑ\83`, коÑ\82оÑ\80аÑ\8f пÑ\80иÑ\81ваиваеÑ\82Ñ\81Ñ\8f паÑ\80амеÑ\82Ñ\80Ñ\83 `token` в *Ñ\84Ñ\83нкÑ\86ии опеÑ\80аÑ\86ии пути*.
+ÐÑ\82а завиÑ\81имоÑ\81Ñ\82Ñ\8c пÑ\80едоÑ\81Ñ\82авиÑ\82 `str`, коÑ\82оÑ\80Ñ\8bй бÑ\83деÑ\82 пÑ\80иÑ\81воен паÑ\80амеÑ\82Ñ\80Ñ\83 `token` *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87ика пути*.
-**FastAPI** бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о он можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 завиÑ\81имоÑ\81Ñ\82Ñ\8c длÑ\8f опÑ\80еделениÑ\8f "Ñ\81Ñ\85емÑ\8b безопаÑ\81ноÑ\81Ñ\82и" в Ñ\81Ñ\85еме OpenAPI (и автоматической документации по API).
+**FastAPI** бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 завиÑ\81имоÑ\81Ñ\82Ñ\8c длÑ\8f опÑ\80еделениÑ\8f «Ñ\81Ñ\85емÑ\8b безопаÑ\81ноÑ\81Ñ\82и» в Ñ\81Ñ\85еме OpenAPI (и в автоматической документации по API).
/// info | Технические детали
-**FastAPI** бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о он можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c клаÑ\81Ñ\81 `OAuth2PasswordBearer` (обÑ\8aÑ\8fвленнÑ\8bй в завиÑ\81имоÑ\81Ñ\82и) длÑ\8f опÑ\80еделениÑ\8f Ñ\81Ñ\85емÑ\8b безопаÑ\81ноÑ\81Ñ\82и в OpenAPI, поÑ\81колÑ\8cкÑ\83 он наследуется от `fastapi.security.oauth2.OAuth2`, который, в свою очередь, наследуется от `fastapi.security.base.SecurityBase`.
+**FastAPI** бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c клаÑ\81Ñ\81 `OAuth2PasswordBearer` (обÑ\8aÑ\8fвленнÑ\8bй в завиÑ\81имоÑ\81Ñ\82и) длÑ\8f опÑ\80еделениÑ\8f Ñ\81Ñ\85емÑ\8b безопаÑ\81ноÑ\81Ñ\82и в OpenAPI, поÑ\82омÑ\83 Ñ\87Ñ\82о он наследуется от `fastapi.security.oauth2.OAuth2`, который, в свою очередь, наследуется от `fastapi.security.base.SecurityBase`.
-Все утилиты безопасности, интегрируемые в OpenAPI (и автоматическая документация по API), наследуются от `SecurityBase`, поэтому **FastAPI** может знать, как интегрировать их в OpenAPI.
+Все утилиты безопасности, интегрируемые с OpenAPI (и автоматической документацией по API), наследуются от `SecurityBase`, — так **FastAPI** понимает, как интегрировать их в OpenAPI.
///
-## Что он делает
+## Что он делает { #what-it-does }
-Он будет искать в запросе заголовок `Authorization` и проверять, содержит ли он значение `Bearer` с некоторым токеном, и возвращать токен в виде `строки`.
+Он будет искать в запросе заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.
-Ð\95Ñ\81ли он не видиÑ\82 заголовка `Authorization` или знаÑ\87ение не имееÑ\82 Ñ\82окена `Bearer`, Ñ\82о в оÑ\82веÑ\82 бÑ\83деÑ\82 вÑ\8bдана оÑ\88ибка Ñ\81 кодом Ñ\81оÑ\81Ñ\82оÑ\8fниÑ\8f 401 (`UNAUTHORIZED`).
+Ð\95Ñ\81ли заголовок `Authorization` оÑ\82Ñ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83еÑ\82 или его знаÑ\87ение не Ñ\81одеÑ\80жиÑ\82 Ñ\82окен `Bearer `, он Ñ\81Ñ\80азÑ\83 оÑ\82веÑ\82иÑ\82 оÑ\88ибкой Ñ\81о Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-кодом 401 (`UNAUTHORIZED`).
-Ð\94лÑ\8f возвÑ\80аÑ\82а оÑ\88ибки даже не нÑ\83жно пÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c, Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 ли Ñ\82окен. Ð\92Ñ\8b можеÑ\82е бÑ\8bÑ\82Ñ\8c Ñ\83веÑ\80енÑ\8b, Ñ\87Ñ\82о еÑ\81ли ваÑ\88а Ñ\84Ñ\83нкÑ\86иÑ\8f бÑ\8bла вÑ\8bполнена, Ñ\82о в Ñ\8dÑ\82ом Ñ\82окене еÑ\81Ñ\82Ñ\8c `Ñ\81Ñ\82Ñ\80ока`.
+Ð\92ам даже не нÑ\83жно пÑ\80овеÑ\80Ñ\8fÑ\82Ñ\8c налиÑ\87ие Ñ\82окена, Ñ\87Ñ\82обÑ\8b веÑ\80нÑ\83Ñ\82Ñ\8c оÑ\88ибкÑ\83. Ð\92Ñ\8b можеÑ\82е бÑ\8bÑ\82Ñ\8c Ñ\83веÑ\80енÑ\8b: еÑ\81ли ваÑ\88а Ñ\84Ñ\83нкÑ\86иÑ\8f бÑ\8bла вÑ\8bполнена, в Ñ\8dÑ\82ом Ñ\82окене бÑ\83деÑ\82 `str`.
-Ð\9fÑ\80овеÑ\80иÑ\82Ñ\8c Ñ\8dÑ\82о можно Ñ\83же Ñ\81ейÑ\87аÑ\81 в интерактивной документации:
+ÐÑ\82о Ñ\83же можно попÑ\80обоваÑ\82Ñ\8c в интерактивной документации:
<img src="/img/tutorial/security/image03.png">
-Мы пока не проверяем валидность токена, но для начала неплохо.
+Мы пока не проверяем валидность токена, но для начала это уже неплохо.
-## Резюме
+## Резюме { #recap }
-Таким образом, всего за 3-4 дополнительные строки вы получаете некую примитивную форму защиты.
+Таким образом, всего за 3–4 дополнительные строки у вас уже есть некая примитивная форма защиты.
-# Ð\94аннÑ\8bе Ñ\82екÑ\83Ñ\89его полÑ\8cзоваÑ\82елÑ\8f
+# Ð\9fолÑ\83Ñ\87иÑ\82Ñ\8c Ñ\82екÑ\83Ñ\89его полÑ\8cзоваÑ\82елÑ\8f { #get-current-user }
-В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции, обрабатывающей эндпоинт,* `токен` в виде `строки`:
+В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции-обработчику пути* `token` типа `str`:
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
-ÐÑ\82о пока Ñ\87Ñ\82о не Ñ\81лиÑ\88ком нам полезно. Ð\94авайÑ\82е изменим код Ñ\82ак, Ñ\87Ñ\82обÑ\8b он возвÑ\80аÑ\89ал нам даннÑ\8bе полÑ\8cзоваÑ\82елÑ\8f, оÑ\82пÑ\80авивÑ\88его запÑ\80оÑ\81.
+Ð\9dо Ñ\8dÑ\82о вÑ\81Ñ\91 еÑ\89Ñ\91 не Ñ\81лиÑ\88ком полезно.
-## Создание модели пользователя
+Сделаем так, чтобы она возвращала текущего пользователя.
+
+## Создать модель пользователя { #create-a-user-model }
Сначала создадим Pydantic-модель пользователя.
-Точно так же, как мы использовали Pydantic для объявления тел запросов, мы можем использовать его где угодно:
+Точно так же, как мы используем Pydantic для объявления тел запросов, мы можем использовать его где угодно:
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
-## Создание зависимости `get_current_user`
+## Создать зависимость `get_current_user` { #create-a-get-current-user-dependency }
Давайте создадим зависимость `get_current_user`.
Помните, что у зависимостей могут быть подзависимости?
-`get_current_user` как Ñ\80аз бÑ\83деÑ\82 имеÑ\82Ñ\8c подзавиÑ\81имоÑ\81Ñ\82Ñ\8c `oauth2_scheme`, коÑ\82оÑ\80Ñ\83Ñ\8e мы создали ранее.
+`get_current_user` бÑ\83деÑ\82 имеÑ\82Ñ\8c завиÑ\81имоÑ\81Ñ\82Ñ\8c оÑ\82 Ñ\82ого же `oauth2_scheme`, коÑ\82оÑ\80Ñ\8bй мы создали ранее.
-Ð\90налогиÑ\87но Ñ\82омÑ\83, как мÑ\8b делали Ñ\8dÑ\82о Ñ\80анее в *обÑ\80абоÑ\82Ñ\87ике Ñ\8dндпоинÑ\82а* наÑ\88а новаÑ\8f завиÑ\81имоÑ\81Ñ\82Ñ\8c `get_current_user` бÑ\83деÑ\82 полÑ\83Ñ\87аÑ\82Ñ\8c `token` в виде `Ñ\81Ñ\82Ñ\80оки` от подзависимости `oauth2_scheme`:
+Ð\90налогиÑ\87но Ñ\82омÑ\83, как мÑ\8b делали Ñ\80анее пÑ\80Ñ\8fмо в *опеÑ\80аÑ\86ии пÑ\83Ñ\82и*, новаÑ\8f завиÑ\81имоÑ\81Ñ\82Ñ\8c `get_current_user` полÑ\83Ñ\87иÑ\82 `token` Ñ\82ипа `str` от подзависимости `oauth2_scheme`:
{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
-## Ð\9fолÑ\83Ñ\87ение даннÑ\8bÑ\85 полÑ\8cзоваÑ\82елÑ\8f
+## Ð\9fолÑ\83Ñ\87иÑ\82Ñ\8c полÑ\8cзоваÑ\82елÑ\8f { #get-the-user }
-`get_current_user` будет использовать созданную нами (ненастоящую) служебную функцию, которая принимает токен в виде `строки` и возвращает нашу Pydantic-модель `User`:
+`get_current_user` будет использовать созданную нами (ненастоящую) служебную функцию, которая принимает токен типа `str` и возвращает нашу Pydantic-модель `User`:
{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
-## Ð\92недÑ\80ение завиÑ\81имоÑ\81Ñ\82и Ñ\82екÑ\83Ñ\89его полÑ\8cзоваÑ\82елÑ\8f
+## Ð\92недÑ\80иÑ\82Ñ\8c Ñ\82екÑ\83Ñ\89его полÑ\8cзоваÑ\82елÑ\8f { #inject-the-current-user }
-Теперь мы можем использовать тот же `Depends` с нашей зависимостью `get_current_user` в *функции обрабатывающей эндпоинт*:
+Теперь мы можем использовать тот же `Depends` с нашей `get_current_user` в *операции пути*:
{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
-Обратите внимание, что мы объявляем тип переменной `current_user` как Pydantic-модель `User`.
+Обратите внимание, что мы объявляем тип `current_user` как Pydantic-модель `User`.
-Это поможет выполнить внутри функции все проверки автозаполнения и типа.
+Это поможет внутри функции с автозавершением и проверками типов.
/// tip | Подсказка
-Возможно, вы помните, что тело запроса также объявляется с помощью Pydantic-моделей.
-В этом месте у **FastAPI** не возникнет проблем, потому что вы используете `Depends`.
+Возможно, вы помните, что тела запросов также объявляются с помощью Pydantic-моделей.
+
+Здесь **FastAPI** не запутается, потому что вы используете `Depends`.
+
///
/// check | Заметка
-То, как устроена эта система зависимостей, позволяет нам иметь различные зависимости, которые возвращают модель `User`.
-Мы не ограничены наличием только одной зависимости, которая может возвращать данные такого типа.
+То, как устроена эта система зависимостей, позволяет иметь разные зависимости, которые возвращают модель `User`.
+
+Мы не ограничены наличием только одной зависимости, которая может возвращать такой тип данных.
+
///
-## Другие модели
+## Другие модели { #other-models }
-Теперь вы можете получать информацию о текущем пользователе непосредственно в *функции обрабатывающей эндпоинт* и работать с механизмами безопасности на уровне **Внедрения Зависимостей**, используя `Depends`.
+Теперь вы можете получать текущего пользователя напрямую в *функциях-обработчиках пути* и работать с механизмами безопасности на уровне **внедрения зависимостей**, используя `Depends`.
-Ð\9fÑ\80иÑ\87ем длÑ\8f обеÑ\81пеÑ\87ениÑ\8f Ñ\82Ñ\80ебований безопаÑ\81ноÑ\81Ñ\82и можно иÑ\81полÑ\8cзоваÑ\82Ñ\8c лÑ\8eбÑ\83Ñ\8e моделÑ\8c или даннÑ\8bе (в данном Ñ\81лÑ\83Ñ\87ае - Pydantic-модель `User`).
+Ð\98 вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c лÑ\8eбÑ\83Ñ\8e моделÑ\8c или даннÑ\8bе длÑ\8f Ñ\82Ñ\80ебований безопаÑ\81ноÑ\81Ñ\82и (в данном Ñ\81лÑ\83Ñ\87ае Pydantic-модель `User`).
-Но вы не ограничены использованием какой-то конкретной моделью данных, классом или типом.
+Но вы не ограничены использованием какой-то конкретной модели данных, класса или типа.
-Ð\92Ñ\8b Ñ\85оÑ\82иÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c в модели `id` и `email`, а `username` вам не нÑ\83жен? Ð\9dÑ\83 Ñ\80азÑ\83мееÑ\82Ñ\81Ñ\8f. Ð\92оÑ\81полÑ\8cзÑ\83йÑ\82еÑ\81Ñ\8c Ñ\82ем же инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82аÑ\80ием.
+ХоÑ\82иÑ\82е, Ñ\87Ñ\82обÑ\8b в модели бÑ\8bли `id` и `email`, но не бÑ\8bло `username`? Ð\9fожалÑ\83йÑ\81Ñ\82а. Ð\9cожно иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\82е же инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b.
-Ð\92ам нÑ\83жнÑ\8b Ñ\82олÑ\8cко `Ñ\81Ñ\82Ñ\80оки`? Ð\98ли Ñ\82олÑ\8cко `Ñ\81ловаÑ\80и`? Ð\98ли непоÑ\81Ñ\80едÑ\81Ñ\82венно Ñ\8dкземплÑ\8fÑ\80 модели клаÑ\81Ñ\81а базÑ\8b даннÑ\8bÑ\85? Ð\92Ñ\81е Ñ\8dÑ\82о Ñ\80абоÑ\82аеÑ\82 Ñ\82оÑ\87но Ñ\82акже.
+ХоÑ\82иÑ\82е пÑ\80оÑ\81Ñ\82о `str`? Ð\98ли пÑ\80оÑ\81Ñ\82о `dict`? Ð\98ли напÑ\80Ñ\8fмÑ\83Ñ\8e Ñ\8dкземплÑ\8fÑ\80 клаÑ\81Ñ\81а модели базÑ\8b даннÑ\8bÑ\85? Ð\92Ñ\81Ñ\91 Ñ\80абоÑ\82аеÑ\82 одинаково.
-У ваÑ\81 неÑ\82 полÑ\8cзоваÑ\82елей, коÑ\82оÑ\80Ñ\8bе вÑ\85одÑ\8fÑ\82 в ваÑ\88е пÑ\80иложение, а Ñ\82олÑ\8cко Ñ\80обоÑ\82Ñ\8b, боÑ\82Ñ\8b или дÑ\80Ñ\83гие Ñ\81иÑ\81Ñ\82емÑ\8b, Ñ\83 коÑ\82оÑ\80Ñ\8bÑ\85 еÑ\81Ñ\82Ñ\8c Ñ\82олÑ\8cко Ñ\82окен доÑ\81Ñ\82Ñ\83па? Ð\9eпÑ\8fÑ\82Ñ\8c же, вÑ\81е Ñ\80абоÑ\82аеÑ\82 одинаково.
+У ваÑ\81 вообÑ\89е неÑ\82 полÑ\8cзоваÑ\82елей, коÑ\82оÑ\80Ñ\8bе вÑ\85одÑ\8fÑ\82 в пÑ\80иложение, а еÑ\81Ñ\82Ñ\8c Ñ\80обоÑ\82Ñ\8b, боÑ\82Ñ\8b или дÑ\80Ñ\83гие Ñ\81иÑ\81Ñ\82емÑ\8b, Ñ\83 коÑ\82оÑ\80Ñ\8bÑ\85 еÑ\81Ñ\82Ñ\8c Ñ\82олÑ\8cко Ñ\82окен доÑ\81Ñ\82Ñ\83па? Снова â\80\94 вÑ\81Ñ\91 Ñ\80абоÑ\82аеÑ\82 Ñ\82ак же.
-Ð\9fÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83йÑ\82е лÑ\8eбÑ\83Ñ\8e моделÑ\8c, лÑ\8eбой клаÑ\81Ñ\81, лÑ\8eбÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85, коÑ\82оÑ\80Ñ\8bе нÑ\83жнÑ\8b длÑ\8f ваÑ\88его пÑ\80иложениÑ\8f. Система внедрения зависимостей **FastAPI** поможет вам в этом.
+Ð\9fÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83йÑ\82е лÑ\8eбÑ\83Ñ\8e моделÑ\8c, лÑ\8eбой клаÑ\81Ñ\81, лÑ\8eбÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85, коÑ\82оÑ\80Ñ\8bе нÑ\83жнÑ\8b ваÑ\88емÑ\83 пÑ\80иложениÑ\8e. Система внедрения зависимостей **FastAPI** поможет вам в этом.
-## Размер кода
+## Размер кода { #code-size }
-ÐÑ\82оÑ\82 пÑ\80имеÑ\80 можеÑ\82 показаÑ\82Ñ\8cÑ\81Ñ\8f многоÑ\81ловнÑ\8bм. СледÑ\83еÑ\82 имеÑ\82Ñ\8c в видÑ\83, Ñ\87Ñ\82о в одном Ñ\84айле мÑ\8b Ñ\81меÑ\88иваем безопаÑ\81ноÑ\81Ñ\82Ñ\8c, модели даннÑ\8bÑ\85, Ñ\81лÑ\83жебнÑ\8bе Ñ\84Ñ\83нкÑ\86ии и *Ñ\8dндпоинÑ\82Ñ\8b*.
+ÐÑ\82оÑ\82 пÑ\80имеÑ\80 можеÑ\82 показаÑ\82Ñ\8cÑ\81Ñ\8f многоÑ\81ловнÑ\8bм. Ð\98мейÑ\82е в видÑ\83, Ñ\87Ñ\82о в одном Ñ\84айле мÑ\8b Ñ\81меÑ\88иваем безопаÑ\81ноÑ\81Ñ\82Ñ\8c, модели даннÑ\8bÑ\85, Ñ\81лÑ\83жебнÑ\8bе Ñ\84Ñ\83нкÑ\86ии и *опеÑ\80аÑ\86ии пÑ\83Ñ\82и*.
-Но вот ключевой момент:
+Но вот ключевой момент.
-Все, что касается безопасности и внедрения зависимостей, пишется один раз.
+Всё, что касается безопасности и внедрения зависимостей, пишется один раз.
-И вы можете сделать его настолько сложным, насколько захотите. И все это будет написано только один раз, в одном месте, со всей своей гибкостью.
+И вы можете сделать это настолько сложным, насколько захотите. И всё равно это будет написано только один раз, в одном месте. Со всей гибкостью.
-Ð\98 Ñ\83 ваÑ\81 могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c Ñ\82Ñ\8bÑ\81Ñ\8fÑ\87и конеÑ\87нÑ\8bÑ\85 Ñ\82оÑ\87ек (*Ñ\8dндпоинÑ\82ов*), использующих одну и ту же систему безопасности.
+Ð\9fÑ\80и Ñ\8dÑ\82ом Ñ\83 ваÑ\81 могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8c Ñ\82Ñ\8bÑ\81Ñ\8fÑ\87и Ñ\8dндпоинÑ\82ов (*опеÑ\80аÑ\86ий пÑ\83Ñ\82и*), использующих одну и ту же систему безопасности.
И все они (или любая их часть по вашему желанию) могут воспользоваться преимуществами повторного использования этих зависимостей или любых других зависимостей, которые вы создадите.
-И все эти тысячи *эндпоинтов* могут составлять всего 3 строки:
+И все эти тысячи *операций пути* могут состоять всего из 3 строк:
{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
-## Резюме
+## Резюме { #recap }
-Теперь вы можете получать данные о текущем пользователе непосредственно в своей *функции обработчике эндпоинта*.
+Теперь вы можете получать текущего пользователя прямо в своей *функции-обработчике пути*.
-Мы уже на полпути к этому.
+Мы уже на полпути.
-Ð\9eÑ\81Ñ\82алоÑ\81Ñ\8c лиÑ\88Ñ\8c добавиÑ\82Ñ\8c *Ñ\8dндпоинÑ\82* длÑ\8f оÑ\82пÑ\80авки полÑ\8cзоваÑ\82елем/клиенÑ\82ом Ñ\81воиÑ\85 `имени полÑ\8cзоваÑ\82елÑ\8f` и `паÑ\80олÑ\8f`.
+Ð\9dÑ\83жно лиÑ\88Ñ\8c добавиÑ\82Ñ\8c *опеÑ\80аÑ\86иÑ\8e пÑ\83Ñ\82и*, Ñ\87Ñ\82обÑ\8b полÑ\8cзоваÑ\82елÑ\8c/клиенÑ\82 мог оÑ\82пÑ\80авиÑ\82Ñ\8c `username` и `password`.
-Это будет рассмотрено в следующем разделе.
+Это будет дальше.
-# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами
+# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
-Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены <abbr title="JSON Web Tokens">JWT</abbr> и безопасное хеширование паролей.
+Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены <abbr title="JSON Web Tokens – веб‑токены JSON">JWT</abbr> и безопасное хеширование паролей.
Этот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д.
Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе.
-## Про JWT
+## Про JWT { #about-jwt }
JWT означает "JSON Web Tokens".
Если вы хотите поиграть с JWT-токенами и посмотреть, как они работают, посмотрите <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>.
-## Установка `PyJWT`
+## Установка `PyJWT` { #install-pyjwt }
Нам необходимо установить `pyjwt` для генерации и проверки JWT-токенов на языке Python.
/// info | Дополнительная информация
Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.
-Подробнее об этом можно прочитать в <a href=«https://pyjwt.readthedocs.io/en/latest/installation.html» class=«external-link» target=«_blank»>документации по установке PyJWT</a>.
+Подробнее об этом можно прочитать в <a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">документации по установке PyJWT</a>.
///
-## Хеширование паролей
+## Хеширование паролей { #password-hashing }
"Хеширование" означает преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина.
Но преобразовать тарабарщину обратно в пароль невозможно.
-### Для чего нужно хеширование паролей
+### Для чего нужно хеширование паролей { #why-use-password-hashing }
Если ваша база данных будет украдена, то вор не получит пароли пользователей в открытом виде, а только их хэши.
Таким образом, вор не сможет использовать этот пароль в другой системе (поскольку многие пользователи везде используют один и тот же пароль, это было бы опасно).
-## Установка `passlib`
+## Установка `pwdlib` { #install-pwdlib }
-PassLib - это отличный пакет Python для работы с хэшами паролей.
+pwdlib — это отличный пакет Python для работы с хэшами паролей.
Он поддерживает множество безопасных алгоритмов хеширования и утилит для работы с ними.
-Рекомендуемый алгоритм - "Bcrypt".
+Рекомендуемый алгоритм — "Argon2".
-Убедитесь, что вы создали и активировали виртуальное окружение, и затем установите PassLib вместе с Bcrypt:
+Убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md){.internal-link target=_blank}, активируйте его, и затем установите pwdlib вместе с Argon2:
<div class="termy">
```console
-$ pip install "passlib[bcrypt]"
+$ pip install "pwdlib[argon2]"
---> 100%
```
</div>
/// tip | Подсказка
-С помощью `passlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками.
+С помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками.
Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных.
При этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**.
///
-## Хеширование и проверка паролей
+## Хеширование и проверка паролей { #hash-and-verify-the-passwords }
-Импортируйте необходимые инструменты из `passlib`.
+Импортируйте необходимые инструменты из `pwdlib`.
-Создайте "контекст" PassLib. Именно он будет использоваться для хэширования и проверки паролей.
+Создайте экземпляр PasswordHash с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей.
/// tip | Подсказка
-Контекст PassLib также имеет функциональность для использования различных алгоритмов хеширования, в том числе и устаревших, только для возможности их проверки и т.д.
+pwdlib также поддерживает алгоритм хеширования bcrypt, но не включает устаревшие алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib.
-Ð\9dапÑ\80имеÑ\80, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c его длÑ\8f Ñ\87Ñ\82ениÑ\8f и пÑ\80овеÑ\80ки паÑ\80олей, Ñ\81генеÑ\80иÑ\80ованнÑ\8bÑ\85 дÑ\80Ñ\83гой Ñ\81иÑ\81Ñ\82емой (напÑ\80имеÑ\80, Django), но Ñ\85Ñ\8dÑ\88иÑ\80оваÑ\82Ñ\8c вÑ\81е новÑ\8bе паÑ\80оли дÑ\80Ñ\83гим алгоÑ\80иÑ\82мом, напÑ\80имеÑ\80 Bcrypt.
+Ð\9dапÑ\80имеÑ\80, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c ее длÑ\8f Ñ\87Ñ\82ениÑ\8f и пÑ\80овеÑ\80ки паÑ\80олей, Ñ\81генеÑ\80иÑ\80ованнÑ\8bÑ\85 дÑ\80Ñ\83гой Ñ\81иÑ\81Ñ\82емой (напÑ\80имеÑ\80, Django), но Ñ\85Ñ\8dÑ\88иÑ\80оваÑ\82Ñ\8c вÑ\81е новÑ\8bе паÑ\80оли дÑ\80Ñ\83гим алгоÑ\80иÑ\82мом, напÑ\80имеÑ\80 Argon2 или Bcrypt.
И при этом быть совместимым со всеми этими системами.
///
Создайте служебную функцию для хэширования пароля, поступающего от пользователя.
-А затем создайте другую - для проверки соответствия полученного пароля и хранимого хэша.
+А затем создайте другую — для проверки соответствия полученного пароля и хранимого хэша.
-И еще одну - для аутентификации и возврата пользователя.
+И еще одну — для аутентификации и возврата пользователя.
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
/// note | Технические детали
-Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
+Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
///
-## Работа с JWT токенами
+## Работа с JWT токенами { #handle-jwt-tokens }
Импортируйте установленные модули.
Создайте переменную для срока действия токена.
-Определите Pydantic Model, которая будет использоваться для формирования ответа на запрос на получение токена.
+Определите Pydantic-модель, которая будет использоваться для формирования ответа на запрос на получение токена.
Создайте служебную функцию для генерации нового токена доступа.
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
-## Обновление зависимостей
+## Обновление зависимостей { #update-the-dependencies }
Обновите `get_current_user` для получения того же токена, что и раньше, но на этот раз с использованием JWT-токенов.
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
-## Обновление *операции пути* `/token`
+## Обновление *операции пути* `/token` { #update-the-token-path-operation }
Создайте `timedelta` со временем истечения срока действия токена.
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
-### Технические подробности о JWT ключе `sub`
+### Технические подробности о JWT ключе `sub` { #technical-details-about-the-jwt-subject-sub }
В спецификации JWT говорится, что существует ключ `sub`, содержащий субъект токена.
Важно помнить, что ключ `sub` должен иметь уникальный идентификатор для всего приложения и представлять собой строку.
-## Проверка в действии
+## Проверка в действии { #check-it }
Запустите сервер и перейдите к документации: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Username: `johndoe`
Password: `secret`
-/// check | Ð\97амеÑ\82ка
+/// check | Ð\9fÑ\80овеÑ\80ка
Обратите внимание, что нигде в коде не используется открытый текст пароля "`secret`", мы используем только его хэшированную версию.
///
<img src="/img/tutorial/security/image10.png">
/// note | Техническая информация
-Обратите внимание на заголовок `Authorization`, значение которого начинается с `Bearer`.
+Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `.
///
-## Продвинутое использование `scopes`
+## Продвинутое использование `scopes` { #advanced-usage-with-scopes }
В OAuth2 существует понятие "диапазоны" ("`scopes`").
Затем вы можете передать этот токен непосредственно пользователю или третьей стороне для взаимодействия с вашим API с определенным набором ограничений.
-О том, как их использовать и как они интегрированы в **FastAPI**, читайте далее в **Руководстве пользователя**.
+О том, как их использовать и как они интегрированы в **FastAPI**, читайте далее в **Расширенном руководстве пользователя**.
-## Резюме
+## Резюме { #recap }
С учетом того, что вы видели до сих пор, вы можете создать безопасное приложение **FastAPI**, используя такие стандарты, как OAuth2 и JWT.
Он предоставляет вам полную свободу действий, позволяя выбирать то, что лучше всего подходит для вашего проекта.
-Вы можете напрямую использовать многие хорошо поддерживаемые и широко распространенные пакеты, такие как `passlib` и `PyJWT`, поскольку **FastAPI** не требует сложных механизмов для интеграции внешних пакетов.
+Вы можете напрямую использовать многие хорошо поддерживаемые и широко распространенные пакеты, такие как `pwdlib` и `PyJWT`, поскольку **FastAPI** не требует сложных механизмов для интеграции внешних пакетов.
Напротив, он предоставляет инструменты, позволяющие максимально упростить этот процесс без ущерба для гибкости, надежности и безопасности.
При этом вы можете использовать и реализовывать безопасные стандартные протоколы, такие как OAuth2, относительно простым способом.
-В **Руководстве пользователя** вы можете узнать больше о том, как использовать "диапазоны" ("`scopes`") OAuth2 для создания более точно настроенной системы разрешений в соответствии с теми же стандартами. OAuth2 с диапазонами - это механизм, используемый многими крупными провайдерами сервиса аутентификации, такими как Facebook, Google, GitHub, Microsoft, X (Twitter) и др., для авторизации сторонних приложений на взаимодействие с их API от имени их пользователей.
+В **Расширенном руководстве пользователя** вы можете узнать больше о том, как использовать "диапазоны" ("`scopes`") OAuth2 для создания более точно настроенной системы разрешений в соответствии с теми же стандартами. OAuth2 с диапазонами — это механизм, используемый многими крупными провайдерами сервиса аутентификации, такими как Facebook, Google, GitHub, Microsoft, X (Twitter) и др., для авторизации сторонних приложений на взаимодействие с их API от имени их пользователей.
-# Простая авторизация по протоколу OAuth2 с токеном типа Bearer
+# Простая авторизация OAuth2 с паролем и «Bearer» { #simple-oauth2-with-password-and-bearer }
-ТепеÑ\80Ñ\8c, оÑ\82Ñ\82алкиваÑ\8fÑ\81Ñ\8c оÑ\82 пÑ\80едÑ\8bдÑ\83Ñ\89ей главÑ\8b, добавим недоÑ\81Ñ\82аÑ\8eÑ\89ие Ñ\87аÑ\81Ñ\82и, Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87иÑ\82Ñ\8c безопаÑ\81нÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83.
+ТепеÑ\80Ñ\8c, оÑ\82Ñ\82алкиваÑ\8fÑ\81Ñ\8c оÑ\82 пÑ\80едÑ\8bдÑ\83Ñ\89ей главÑ\8b, добавим недоÑ\81Ñ\82аÑ\8eÑ\89ие Ñ\87аÑ\81Ñ\82и, Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87иÑ\82Ñ\8c полнÑ\8bй поÑ\82ок безопаÑ\81ноÑ\81Ñ\82и.
-## Получение `имени пользователя` и `пароля`
+## Получение `username` и `password` { #get-the-username-and-password }
-Для получения `имени пользователя` и `пароля` мы будем использовать утилиты безопасности **FastAPI**.
+Для получения `username` и `password` мы будем использовать утилиты безопасности **FastAPI**.
-Протокол OAuth2 определяет, что при использовании "аутентификации по паролю" (которую мы и используем) клиент/пользователь должен передавать поля `username` и `password` в полях формы.
+OAuth2 определяет, что при использовании "password flow" (аутентификация по паролю - именно его мы используем) клиент/пользователь должен передавать поля `username` и `password` в полях формы.
В спецификации сказано, что поля должны быть названы именно так. Поэтому `user-name` или `email` работать не будут.
-Но не волнуйтесь, вы можете показать его конечным пользователям во фронтенде в том виде, в котором хотите.
+Но не волнуйтесь, вы можете показать это конечным пользователям во фронтенде в том виде, в котором хотите.
А ваши модели баз данных могут использовать любые другие имена.
-Ð\9dо пÑ\80и авÑ\82оÑ\80изаÑ\86ии Ñ\81оглаÑ\81но Ñ\81пеÑ\86иÑ\84икаÑ\86ии, Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c именно Ñ\8dÑ\82и имена, Ñ\87Ñ\82о даÑ\81Ñ\82 нам возможноÑ\81Ñ\82Ñ\8c воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f вÑ\81Ñ\82Ñ\80оенной Ñ\81иÑ\81Ñ\82емой докÑ\83менÑ\82аÑ\86ии API.
+Ð\9dо длÑ\8f логин-опеÑ\80аÑ\86ии пÑ\83Ñ\82и нам нÑ\83жно иÑ\81полÑ\8cзоваÑ\82Ñ\8c именно Ñ\8dÑ\82и имена, Ñ\87Ñ\82обÑ\8b бÑ\8bÑ\82Ñ\8c Ñ\81овмеÑ\81Ñ\82имÑ\8bми Ñ\81о Ñ\81пеÑ\86иÑ\84икаÑ\86ией (и имеÑ\82Ñ\8c возможноÑ\81Ñ\82Ñ\8c, напÑ\80имеÑ\80, иÑ\81полÑ\8cзоваÑ\82Ñ\8c вÑ\81Ñ\82Ñ\80оеннÑ\83Ñ\8e Ñ\81иÑ\81Ñ\82емÑ\83 докÑ\83менÑ\82аÑ\86ии API).
В спецификации также указано, что `username` и `password` должны передаваться в виде данных формы (так что никакого JSON здесь нет).
-### Oбласть видимости (scope)
+### `scope` { #scope }
-В спецификации также говорится, что клиент может передать еще одно поле формы "`scope`".
+В спецификации также говорится, что клиент может передать еще одно поле формы — `scope`.
-Имя поля формы - `scope` (в единственном числе), но на самом деле это длинная строка, состоящая из отдельных областей видимости (scopes), разделенных пробелами.
+Имя поля формы — `scope` (в единственном числе), но на самом деле это длинная строка, состоящая из отдельных "scopes", разделенных пробелами.
-Каждая "область видимости" (scope) - это просто строка (без пробелов).
+Каждый "scope" — это просто строка (без пробелов).
Обычно они используются для указания уровней доступа, например:
-* `users:read` или `users:write` являются распространенными примерами.
+* `users:read` или `users:write` — распространенные примеры.
* `instagram_basic` используется Facebook / Instagram.
-* `https://www.googleapis.com/auth/drive` используется компанией Google.
+* `https://www.googleapis.com/auth/drive` используется Google.
-/// info | Дополнительнаяя информация
-В OAuth2 "scope" - это просто строка, которая уточняет уровень доступа.
+/// info | Дополнительная информация
+В OAuth2 "scope" — это просто строка, которая указывает требуемое конкретное разрешение.
-Не имеет значения, содержит ли он другие символы, например `:`, или является ли он URL.
+Не имеет значения, содержит ли она другие символы, например `:`, или является ли это URL.
-Эти детали зависят от конкретной реализации.
+Эти детали зависят от реализации.
Для OAuth2 это просто строки.
///
-## Код получения `имени пользователя` и `пароля`
-
-Для решения задачи давайте воспользуемся утилитами, предоставляемыми **FastAPI**.
+## Код для получения `username` и `password` { #code-to-get-the-username-and-password }
-### `OAuth2PasswordRequestForm`
+Теперь воспользуемся утилитами, предоставляемыми **FastAPI**, чтобы обработать это.
-Сначала импортируйте `OAuth2PasswordRequestForm` и затем используйте ее как зависимость с `Depends` в *эндпоинте* `/token`:
+### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }
+Сначала импортируйте `OAuth2PasswordRequestForm` и затем используйте её как зависимость с `Depends` в операции пути для `/token`:
{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
-`OAuth2PasswordRequestForm` - это класс для использования в качестве зависимости для *функции обрабатывающей эндпоинт*, который определяет тело формы со следующими полями:
+`OAuth2PasswordRequestForm` — это зависимость-класс, которая объявляет тело формы со следующими полями:
* `username`.
* `password`.
* Необязательное поле `grant_type`.
/// tip | Подсказка
-По спецификации OAuth2 поле `grant_type` является обязательным и содержит фиксированное значение `password`, но `OAuth2PasswordRequestForm` не обеспечивает этого.
+По спецификации OAuth2 поле `grant_type` обязательно и содержит фиксированное значение `password`, но `OAuth2PasswordRequestForm` это не проверяет строго.
-Если вам необходимо использовать `grant_type`, воспользуйтесь `OAuth2PasswordRequestFormStrict` вместо `OAuth2PasswordRequestForm`.
+Если вам нужно это строгое требование, используйте `OAuth2PasswordRequestFormStrict` вместо `OAuth2PasswordRequestForm`.
///
-* Необязательное поле `client_id` (в нашем примере он не нужен).
-* Необязательное поле `client_secret` (в нашем примере он не нужен).
+* Необязательное поле `client_id` (в нашем примере оно не нужно).
+* Необязательное поле `client_secret` (в нашем примере оно не нужно).
/// info | Дополнительная информация
-Форма `OAuth2PasswordRequestForm` не является специальным классом для **FastAPI**, как `OAuth2PasswordBearer`.
+`OAuth2PasswordRequestForm` — это не специальный класс для **FastAPI**, как `OAuth2PasswordBearer`.
-`OAuth2PasswordBearer` Ñ\83казÑ\8bваеÑ\82 **FastAPI**, Ñ\87Ñ\82о Ñ\8dÑ\82о Ñ\81Ñ\85ема безопаÑ\81ноÑ\81Ñ\82и. СледоваÑ\82елÑ\8cно, она бÑ\83деÑ\82 добавлена в OpenAPI.
+`OAuth2PasswordBearer` Ñ\81ообÑ\89аеÑ\82 **FastAPI**, Ñ\87Ñ\82о Ñ\8dÑ\82о Ñ\81Ñ\85ема безопаÑ\81ноÑ\81Ñ\82и. Ð\9fоÑ\8dÑ\82омÑ\83 она добавлÑ\8fеÑ\82Ñ\81Ñ\8f в OpenAPI Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89им обÑ\80азом.
-Ð\9dо `OAuth2PasswordRequestForm` - Ñ\8dÑ\82о вÑ\81его лиÑ\88Ñ\8c клаÑ\81Ñ\81 завиÑ\81имоÑ\81Ñ\82и, коÑ\82оÑ\80Ñ\8bй вÑ\8b могли бÑ\8b напиÑ\81аÑ\82Ñ\8c Ñ\81амоÑ\81Ñ\82оÑ\8fÑ\82елÑ\8cно или вы могли бы объявить параметры `Form` напрямую.
+Ð\90 `OAuth2PasswordRequestForm` â\80\94 Ñ\8dÑ\82о пÑ\80оÑ\81Ñ\82о завиÑ\81имоÑ\81Ñ\82Ñ\8c-клаÑ\81Ñ\81, коÑ\82оÑ\80Ñ\83Ñ\8e вÑ\8b могли бÑ\8b напиÑ\81аÑ\82Ñ\8c Ñ\81ами, или вы могли бы объявить параметры `Form` напрямую.
-Но, поскольку это распространённый вариант использования, он предоставляется **FastAPI** напрямую, просто чтобы облегчить задачу.
+Но так как это распространённый вариант использования, он предоставлен **FastAPI** напрямую, чтобы упростить задачу.
///
-### Использование данных формы
+### Использование данных формы { #use-the-form-data }
/// tip | Подсказка
-Ð\92 Ñ\8dкземплÑ\8fÑ\80е завиÑ\81имого клаÑ\81Ñ\81а `OAuth2PasswordRequestForm` аÑ\82Ñ\80ибÑ\83Ñ\82 `scope`, Ñ\81оÑ\81Ñ\82оÑ\8fÑ\89ий из одной длинной Ñ\81Ñ\82Ñ\80оки, Ñ\80азделенной пÑ\80обелами, заменен на аÑ\82Ñ\80ибÑ\83Ñ\82 `scopes`, Ñ\81оÑ\81Ñ\82оÑ\8fÑ\89ий из Ñ\81пиÑ\81ка оÑ\82делÑ\8cнÑ\8bÑ\85 Ñ\81Ñ\82Ñ\80ок, каждаÑ\8f из коÑ\82оÑ\80Ñ\8bÑ\85 Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83еÑ\82 опÑ\80еделенномÑ\83 Ñ\83Ñ\80овнÑ\8e доÑ\81Ñ\82Ñ\83па.
+У Ñ\8dкземплÑ\8fÑ\80а завиÑ\81имоÑ\81Ñ\82и `OAuth2PasswordRequestForm` не бÑ\83деÑ\82 аÑ\82Ñ\80ибÑ\83Ñ\82а `scope` Ñ\81 длинной Ñ\81Ñ\82Ñ\80окой, Ñ\80азделенной пÑ\80обелами. Ð\92меÑ\81Ñ\82о Ñ\8dÑ\82ого бÑ\83деÑ\82 аÑ\82Ñ\80ибÑ\83Ñ\82 `scopes` Ñ\81о Ñ\81пиÑ\81ком оÑ\82делÑ\8cнÑ\8bÑ\85 Ñ\81Ñ\82Ñ\80ок â\80\94 по одной длÑ\8f каждого пеÑ\80еданного scope.
-Ð\92 данном пÑ\80имеÑ\80е мÑ\8b не иÑ\81полÑ\8cзÑ\83ем `scopes`, но еÑ\81ли вам Ñ\8dÑ\82о необÑ\85одимо, Ñ\82о Ñ\82акаÑ\8f Ñ\84Ñ\83нкÑ\86ионалÑ\8cноÑ\81Ñ\82Ñ\8c имееÑ\82Ñ\81Ñ\8f.
+Ð\92 данном пÑ\80имеÑ\80е мÑ\8b не иÑ\81полÑ\8cзÑ\83ем `scopes`, но еÑ\81ли вам Ñ\8dÑ\82о необÑ\85одимо, Ñ\84Ñ\83нкÑ\86ионалÑ\8cноÑ\81Ñ\82Ñ\8c еÑ\81Ñ\82Ñ\8c.
///
Теперь получим данные о пользователе из (ненастоящей) базы данных, используя `username` из поля формы.
-Если такого пользователя нет, то мы возвращаем ошибку "неверное имя пользователя или пароль".
+Если такого пользователя нет, то мы возвращаем ошибку "Incorrect username or password" (неверное имя пользователя или пароль).
-Ð\94лÑ\8f оÑ\88ибки мÑ\8b иÑ\81полÑ\8cзÑ\83ем иÑ\81клÑ\8eÑ\87ение `HTTPException`:
+Для ошибки используем исключение `HTTPException`:
{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
-### Проверка пароля
+### Проверка пароля { #check-the-password }
На данный момент у нас есть данные о пользователе из нашей базы данных, но мы еще не проверили пароль.
-Давайте сначала поместим эти данные в модель Pydantic `UserInDB`.
+Давайте сначала поместим эти данные в Pydantic-модель `UserInDB`.
-Ни в коем случае нельзя сохранять пароли в открытом виде, поэтому мы будем использовать (пока что ненастоящую) систему хеширования паролей.
+Никогда нельзя сохранять пароли в открытом виде, поэтому мы будем использовать (пока что ненастоящую) систему хеширования паролей.
Если пароли не совпадают, мы возвращаем ту же ошибку.
-#### Хеширование паролей
+#### Хеширование паролей { #password-hashing }
"Хеширование" означает: преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина.
Но преобразовать тарабарщину обратно в пароль невозможно.
-##### Зачем использовать хеширование паролей
+##### Зачем использовать хеширование паролей { #why-use-password-hashing }
-Если ваша база данных будет украдена, то у вора не будет паролей пользователей в открытом виде, только хэши.
+Если вашу базу данных украдут, у злоумышленника не будет паролей пользователей в открытом виде, только хэши.
-Таким обÑ\80азом, воÑ\80 не Ñ\81можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82и же паÑ\80оли в дÑ\80Ñ\83гой Ñ\81иÑ\81Ñ\82еме (поÑ\81колÑ\8cкÑ\83 многие полÑ\8cзоваÑ\82ели иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 одни и Ñ\82е же паÑ\80оли повсеместно, это было бы опасно).
+Таким обÑ\80азом, он не Ñ\81можеÑ\82 попÑ\80обоваÑ\82Ñ\8c иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\8dÑ\82и же паÑ\80оли в дÑ\80Ñ\83гой Ñ\81иÑ\81Ñ\82еме (поÑ\81колÑ\8cкÑ\83 многие полÑ\8cзоваÑ\82ели иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 один и Ñ\82оÑ\82 же паÑ\80олÑ\8c повсеместно, это было бы опасно).
{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
-#### Про `**user_dict`
+#### Про `**user_dict` { #about-user-dict }
`UserInDB(**user_dict)` означает:
-*Передавать ключи и значения `user_dict` непосредственно в качестве аргументов ключ-значение, что эквивалентно:*
+*Передать ключи и значения `user_dict` непосредственно как аргументы ключ-значение, эквивалентно:*
```Python
UserInDB(
```
/// info | Дополнительная информация
-Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user_indict){.internal-link target=_blank}.
+Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user-in-dict){.internal-link target=_blank}.
///
-## Возврат токена
+## Возврат токена { #return-the-token }
-Ответ эндпоинта `token` должен представлять собой объект в формате JSON.
+Ответ операции пути `/token` должен быть объектом JSON.
-Ð\9eн должен имеÑ\82Ñ\8c `token_type`. Ð\92 наÑ\88ем Ñ\81лÑ\83Ñ\87ае, поÑ\81колÑ\8cкÑ\83 мÑ\8b иÑ\81полÑ\8cзÑ\83ем Ñ\82окенÑ\8b Ñ\82ипа "Bearer", Ñ\82ип Ñ\82окена должен бÑ\8bÑ\82Ñ\8c "`bearer`".
+Ð\92 нÑ\91м должен бÑ\8bÑ\82Ñ\8c `token_type`. Ð\92 наÑ\88ем Ñ\81лÑ\83Ñ\87ае, поÑ\81колÑ\8cкÑ\83 мÑ\8b иÑ\81полÑ\8cзÑ\83ем Ñ\82окенÑ\8b Ñ\82ипа "Bearer", Ñ\82ип Ñ\82окена должен бÑ\8bÑ\82Ñ\8c `bearer`.
-И в нем должна быть строка `access_token`, содержащая наш токен доступа.
+И в нём должен быть `access_token` — строка, содержащая наш токен доступа.
-В этом простом примере мы нарушим все правила безопасности, и будем считать, что имя пользователя (username) полностью соответствует токену (token)
+В этом простом примере мы намеренно поступим небезопасно и вернём тот же `username` в качестве токена.
/// tip | Подсказка
-Ð\92 Ñ\81ледÑ\83Ñ\8eÑ\89ей главе мÑ\8b Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им Ñ\80еалÑ\8cнÑ\83Ñ\8e заÑ\89иÑ\89еннÑ\83Ñ\8e Ñ\80еализаÑ\86иÑ\8e Ñ\81 Ñ\85еÑ\88иÑ\80ованием паÑ\80олей и Ñ\82окенами <abbr title="JSON Web Tokens">JWT</abbr>.
+Ð\92 Ñ\81ледÑ\83Ñ\8eÑ\89ей главе вÑ\8b Ñ\83видиÑ\82е Ñ\80еалÑ\8cнÑ\83Ñ\8e заÑ\89иÑ\89Ñ\91ннÑ\83Ñ\8e Ñ\80еализаÑ\86иÑ\8e Ñ\81 Ñ\85еÑ\88иÑ\80ованием паÑ\80олей и Ñ\82окенами <abbr title="JSON Web Tokens â\80\93 JSON веб-Ñ\82окенÑ\8b">JWT</abbr>.
-Но пока давайте остановимся на необходимых нам деталях.
+Но пока давайте сосредоточимся на необходимых нам деталях.
///
{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
/// tip | Подсказка
Согласно спецификации, вы должны возвращать JSON с `access_token` и `token_type`, как в данном примере.
-Это то, что вы должны сделать сами в своем коде и убедиться, что вы используете эти JSON-ключи.
+Это то, что вы должны сделать сами в своём коде и убедиться, что вы используете именно эти JSON-ключи.
-Это практически единственное, что нужно не забывать делать самостоятельно, чтобы следовать требованиям спецификации.
+Это практически единственное, о чём нужно не забыть, чтобы соответствовать спецификациям.
-Ð\92Ñ\81е остальное за вас сделает **FastAPI**.
+Ð\9eстальное за вас сделает **FastAPI**.
///
-## Обновление зависимостей
+## Обновление зависимостей { #update-the-dependencies }
Теперь мы обновим наши зависимости.
-Мы хотим получить значение `current_user` *только* если этот пользователь активен.
+Мы хотим получить `current_user` только если этот пользователь активен.
-Поэтому мы создаем дополнительную зависимость `get_current_active_user`, которая, в свою очередь, использует в качестве зависимости `get_current_user`.
+Поэтому мы создаём дополнительную зависимость `get_current_active_user`, которая, в свою очередь, использует в качестве зависимости `get_current_user`.
Обе эти зависимости просто вернут HTTP-ошибку, если пользователь не существует или неактивен.
-Таким обÑ\80азом, в наÑ\88ем Ñ\8dндпоинÑ\82е мÑ\8b полÑ\83Ñ\87им полÑ\8cзоваÑ\82елÑ\8f Ñ\82олÑ\8cко в Ñ\82ом Ñ\81лÑ\83Ñ\87ае, еÑ\81ли он Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82, пÑ\80авилÑ\8cно аутентифицирован и активен:
+Таким обÑ\80азом, в наÑ\88ей опеÑ\80аÑ\86ии пÑ\83Ñ\82и мÑ\8b полÑ\83Ñ\87им полÑ\8cзоваÑ\82елÑ\8f Ñ\82олÑ\8cко в Ñ\82ом Ñ\81лÑ\83Ñ\87ае, еÑ\81ли он Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82, коÑ\80Ñ\80екÑ\82но аутентифицирован и активен:
{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
/// info | Дополнительная информация
-Дополнительный заголовок `WWW-Authenticate` со значением `Bearer`, который мы здесь возвращаем, также является частью спецификации.
+Дополнительный HTTP-заголовок `WWW-Authenticate` со значением `Bearer`, который мы здесь возвращаем, также является частью спецификации.
-Ð\9eÑ\82веÑ\82 Ñ\81еÑ\80веÑ\80а Ñ\81 HTTP-кодом 401 "UNAUTHORIZED" должен также возвращать заголовок `WWW-Authenticate`.
+Ð\9bÑ\8eбой HTTP Ñ\81Ñ\82аÑ\82Ñ\83Ñ\81-код 401 "UNAUTHORIZED" должен также возвращать заголовок `WWW-Authenticate`.
В случае с bearer-токенами (наш случай) значение этого заголовка должно быть `Bearer`.
-Ð\9dа Ñ\81амом деле Ñ\8dÑ\82оÑ\82 дополниÑ\82елÑ\8cнÑ\8bй заголовок можно пÑ\80опÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c и вÑ\81е будет работать.
+ФакÑ\82иÑ\87еÑ\81ки, Ñ\8dÑ\82оÑ\82 дополниÑ\82елÑ\8cнÑ\8bй заголовок можно опÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c, и вÑ\81Ñ\91 будет работать.
-Но он приведён здесь для соответствия спецификации.
+Но он приведён здесь для соответствия спецификациям.
-Кроме того, могут существовать инструменты, которые ожидают его и могут использовать, и это может быть полезно для вас или ваших пользователей сейчас или в будущем.
+Кроме того, могут существовать инструменты, которые ожидают его и могут использовать, и это может быть полезно для вас или ваших пользователей — сейчас или в будущем.
В этом и заключается преимущество стандартов...
///
-## Посмотим как это работает
+## Посмотрим, как это работает { #see-it-in-action }
-Ð\9eÑ\82кÑ\80оем интерактивную документацию: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+Ð\9eÑ\82кÑ\80ойÑ\82е интерактивную документацию: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
-### Аутентификация
+### Аутентификация { #authenticate }
-Нажмите кнопку "Авторизация".
+Нажмите кнопку "Authorize".
Используйте учётные данные:
<img src="/img/tutorial/security/image04.png">
-После авторизации в системе вы увидите следующее:
+После аутентификации вы увидите следующее:
<img src="/img/tutorial/security/image05.png">
-### Получение собственных пользовательских данных
+### Получение собственных пользовательских данных { #get-your-own-user-data }
+
+Теперь используйте операцию `GET` с путём `/users/me`.
-ТепеÑ\80Ñ\8c, иÑ\81полÑ\8cзÑ\83Ñ\8f опеÑ\80аÑ\86иÑ\8e `GET` Ñ\81 пÑ\83Ñ\82ем `/users/me`, вÑ\8b полÑ\83Ñ\87иÑ\82е даннÑ\8bе полÑ\8cзоваÑ\82елÑ\8f, например:
+Ð\92Ñ\8b полÑ\83Ñ\87иÑ\82е Ñ\81вои полÑ\8cзоваÑ\82елÑ\8cÑ\81кие даннÑ\8bе, например:
```JSON
{
<img src="/img/tutorial/security/image06.png">
-Если щелкнуть на значке замка и выйти из системы, а затем попытаться выполнить ту же операцию ещё раз, то будет выдана ошибка HTTP 401:
+Если щёлкнуть на значке замка и выйти из системы, а затем попытаться выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401:
```JSON
{
}
```
-### Неактивный пользователь
+### Неактивный пользователь { #inactive-user }
-Теперь попробуйте пройти аутентификацию с неактивным пользователем:
+Теперь попробуйте с неактивным пользователем, аутентифицируйтесь с:
Пользователь: `alice`
Пароль: `secret2`
-И попробуйте использовать операцию `GET` с путем `/users/me`.
+И попробуйте использовать операцию `GET` с путём `/users/me`.
-Вы получите ошибку "Inactive user", как тут:
+Вы получите ошибку "Inactive user", как здесь:
```JSON
{
}
```
-## Резюме
+## Резюме { #recap }
-Теперь у вас есть инструменты для реализации полноценной системы безопасности на основе `имени пользователя` и `пароля` для вашего API.
+Теперь у вас есть инструменты для реализации полноценной системы безопасности на основе `username` и `password` для вашего API.
-Используя эти средства, можно сделать систему безопасности совместимой с любой базой данных, с любым пользователем или моделью данных.
+Используя эти средства, можно сделать систему безопасности совместимой с любой базой данных и с любой пользовательской или моделью данных.
- Единственным недостатком нашей системы является то, что она всё ещё не защищена.
+Единственная деталь, которой не хватает, — система пока ещё не "защищена" по-настоящему.
-В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title="JSON Web Tokens">JWT</abbr>.
+В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title="JSON Web Tokens – JSON веб-токены">JWT</abbr>.
-# SQL (реляционные) базы данных
+# SQL (реляционные) базы данных { #sql-relational-databases }
-**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которой хотите.
+**FastAPI** не требует использовать SQL (реляционную) базу данных. Но вы можете использовать любую базу данных, которую хотите.
-Ð\92 Ñ\8dÑ\82ом Ñ\80азделе мÑ\8b пÑ\80одемонÑ\81Ñ\82Ñ\80иÑ\80Ñ\83ем, как Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>.
+Ð\97деÑ\81Ñ\8c мÑ\8b Ñ\80аÑ\81Ñ\81моÑ\82Ñ\80им пÑ\80имеÑ\80 Ñ\81 иÑ\81полÑ\8cзованием <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>.
-Библиотека **SQLModel** построена на основе <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a> и Pydantic. Она была разработана автором **FastAPI** специально для приложений на основе FastAPI, которые используют **реляционные базы данных**.
+**SQLModel** построен поверх <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a> и Pydantic. Его создал тот же автор, что и **FastAPI**, чтобы он идеально подходил для приложений FastAPI, которым нужны **SQL базы данных**.
/// tip | Подсказка
-Ð\92Ñ\8b можеÑ\82е воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f лÑ\8eбой библиоÑ\82екой длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 Ñ\80елÑ\8fÑ\86ионнÑ\8bми (SQL) или неÑ\80елÑ\8fÑ\86ионнÑ\8bми (NoSQL) базами даннÑ\8bÑ\85. (Ð\98Ñ\85 еÑ\89Ñ\91 назÑ\8bваÑ\8eÑ\82 <abbr title="ORM = Object Relational Mapper, Ñ\8dÑ\82оÑ\82 Ñ\82еÑ\80мин длÑ\8f библиоÑ\82еки, в коÑ\82оÑ\80ой клаÑ\81Ñ\81Ñ\8b пÑ\80едÑ\81Ñ\82авлÑ\8fÑ\8eÑ\82 SQL-Ñ\82аблиÑ\86Ñ\8b, а Ñ\8dкземплÑ\8fÑ\80Ñ\8b клаÑ\81Ñ\81ов пÑ\80едÑ\81Ñ\82авлÑ\8fÑ\8eÑ\82 Ñ\81Ñ\82Ñ\80оки в Ñ\8dÑ\82иÑ\85 Ñ\82аблиÑ\86аÑ\85.">**ORM**</abbr> библиоÑ\82еками). FastAPI не пÑ\80инÑ\83ждаеÑ\82 ваÑ\81 к иÑ\81полÑ\8cзованиÑ\8e Ñ\87его-либо конкÑ\80еÑ\82ного. 😎
+Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c лÑ\8eбÑ\83Ñ\8e дÑ\80Ñ\83гÑ\83Ñ\8e библиоÑ\82екÑ\83 длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 SQL или NoSQL базами даннÑ\8bÑ\85 (иногда иÑ\85 назÑ\8bваÑ\8eÑ\82 <abbr title="Object Relational Mapper â\80\93 Ð\9eбÑ\8aекÑ\82но-Ñ\80елÑ\8fÑ\86ионнÑ\8bй маппеÑ\80: Ñ\82еÑ\80мин длÑ\8f библиоÑ\82еки, где некоÑ\82оÑ\80Ñ\8bе клаÑ\81Ñ\81Ñ\8b пÑ\80едÑ\81Ñ\82авлÑ\8fÑ\8eÑ\82 SQL-Ñ\82аблиÑ\86Ñ\8b, а Ñ\8dкземплÑ\8fÑ\80Ñ\8b пÑ\80едÑ\81Ñ\82авлÑ\8fÑ\8eÑ\82 Ñ\81Ñ\82Ñ\80оки в Ñ\8dÑ\82иÑ\85 Ñ\82аблиÑ\86аÑ\85">"ORMs"</abbr>), FastAPI ниÑ\87его не навÑ\8fзÑ\8bваеÑ\82. 😎
///
-Ð\92 оÑ\81нове SQLModel лежиÑ\82 SQLAlchemy, поÑ\8dÑ\82омÑ\83 вÑ\8b Ñ\81покойно можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c лÑ\8eбÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85, поддеÑ\80живаемÑ\83Ñ\8e SQLAlchemy (и, Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82венно, поддерживаемую SQLModel), например:
+Так как SQLModel оÑ\81нован на SQLAlchemy, вÑ\8b можеÑ\82е легко иÑ\81полÑ\8cзоваÑ\82Ñ\8c **лÑ\8eбÑ\83Ñ\8e поддеÑ\80живаемÑ\83Ñ\8e** SQLAlchemy базÑ\83 даннÑ\8bÑ\85 (а знаÑ\87иÑ\82, и поддерживаемую SQLModel), например:
* PostgreSQL
* MySQL
* Oracle
* Microsoft SQL Server, и т.д.
-В данном примере мы будем использовать базу данных **SQLite**, т.к. она состоит из единственного файла и поддерживается встроенными библиотеками Python. Таким образом, вы сможете скопировать данный пример и запустить его как он есть.
+В этом примере мы будем использовать **SQLite**, потому что она использует один файл и имеет встроенную поддержку в Python. Так что вы можете скопировать этот пример и запустить его как есть.
-Ð\92 далÑ\8cнейÑ\88ем, длÑ\8f пÑ\80одакÑ\88н-веÑ\80Ñ\81ии ваÑ\88его пÑ\80иложениÑ\8f, возможно, вам Ñ\81Ñ\82оиÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81еÑ\80веÑ\80нÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85, напÑ\80имеÑ\80, **PostgreSQL**.
+Ð\9fозже, длÑ\8f пÑ\80одакÑ\88н-пÑ\80иложениÑ\8f, возможно, вÑ\8b заÑ\85оÑ\82иÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81еÑ\80веÑ\80нÑ\83Ñ\8e базÑ\83 даннÑ\8bÑ\85, напÑ\80имеÑ\80 **PostgreSQL**.
/// tip | Подсказка
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 оÑ\84иÑ\86иалÑ\8cнÑ\8bй генеÑ\80аÑ\82оÑ\80 пÑ\80оекÑ\82ов на **FastAPI** и **PostgreSQL**, коÑ\82оÑ\80Ñ\8bй Ñ\82акже вклÑ\8eÑ\87аеÑ\82 frontend и дополниÑ\82елÑ\8cнÑ\8bе инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
+СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 оÑ\84иÑ\86иалÑ\8cнÑ\8bй генеÑ\80аÑ\82оÑ\80 пÑ\80оекÑ\82ов на **FastAPI** и **PostgreSQL**, вклÑ\8eÑ\87аÑ\8eÑ\89ий frontend и дÑ\80Ñ\83гие инÑ\81Ñ\82Ñ\80Ñ\83менÑ\82Ñ\8b: <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
///
-Это очень простое и короткое руководство, поэтому, если вы хотите узнать о базах данных в целом, об SQL, разобраться с более продвинутым функционалом, то воспользуйтесь <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">документацией SQLModel</a>.
+Это очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, об SQL или о более продвинутых возможностях, обратитесь к <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">документации SQLModel</a>.
-## Установка `SQLModel`
+## Установка `SQLModel` { #install-sqlmodel }
-СоздайÑ\82е виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение [virtual environment](../virtual-environments.md){.internal-link target=_blank}, акÑ\82ивиÑ\80Ñ\83йÑ\82е его и Ñ\83Ñ\81Ñ\82ановиÑ\82е `sqlmodel`:
+СнаÑ\87ала Ñ\83бедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b Ñ\81оздали [виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение](../virtual-environments.md){.internal-link target=_blank}, акÑ\82ивиÑ\80овали его и заÑ\82ем Ñ\83Ñ\81Ñ\82ановили `sqlmodel`:
<div class="termy">
</div>
-## Создание приложения с единственной моделью
+## Создание приложения с единственной моделью { #create-the-app-with-a-single-model }
-Ð\9cÑ\8b наÑ\87нем Ñ\81 Ñ\81озданиÑ\8f наиболее пÑ\80оÑ\81Ñ\82ой пеÑ\80вой веÑ\80Ñ\81ии наÑ\88его пÑ\80иложениÑ\8f Ñ\81 одной единÑ\81Ñ\82венной моделью **SQLModel**.
+СнаÑ\87ала мÑ\8b Ñ\81оздадим Ñ\81амÑ\83Ñ\8e пÑ\80оÑ\81Ñ\82Ñ\83Ñ\8e пеÑ\80вÑ\83Ñ\8e веÑ\80Ñ\81иÑ\8e пÑ\80иложениÑ\8f Ñ\81 одной моделью **SQLModel**.
-Ð\92 далÑ\8cнейÑ\88ем Ñ\81 помоÑ\89Ñ\8cÑ\8e **дополниÑ\82елÑ\8cнÑ\8bÑ\85 моделей** мÑ\8b его Ñ\83лÑ\83Ñ\87Ñ\88им и Ñ\81делаем более безопаÑ\81нÑ\8bм и Ñ\83нивеÑ\80Ñ\81алÑ\8cнÑ\8bм. 🤓
+Ð\9fозже мÑ\8b Ñ\83лÑ\83Ñ\87Ñ\88им его, повÑ\8bÑ\81ив безопаÑ\81ноÑ\81Ñ\82Ñ\8c и Ñ\83нивеÑ\80Ñ\81алÑ\8cноÑ\81Ñ\82Ñ\8c, добавив **неÑ\81колÑ\8cко моделей**. 🤓
-### Создание моделей
+### Создание моделей { #create-models }
Импортируйте `SQLModel` и создайте модель базы данных:
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
-Ð\9aлаÑ\81Ñ\81 `Hero` оÑ\87енÑ\8c напоминаеÑ\82 модель Pydantic (фактически, под капотом, *это и есть модель Pydantic*).
+Ð\9aлаÑ\81Ñ\81 `Hero` оÑ\87енÑ\8c поÑ\85ож на модель Pydantic (фактически, под капотом, *это и есть модель Pydantic*).
-Ð\9dо еÑ\81Ñ\82Ñ\8c и некоÑ\82оÑ\80Ñ\8bе Ñ\80азлиÑ\87иÑ\8f
+Ð\95Ñ\81Ñ\82Ñ\8c неÑ\81колÑ\8cко оÑ\82лиÑ\87ий:
-* `table=True` для SQLModel означает, что это *модель-таблица*, которая должна представлять **таблицу** в реляционной базе данных. Это не просто *модель данных* (в отличие от обычного класса в Pydantic).
+* `table=True` сообщает SQLModel, что это *модель-таблица*, она должна представлять **таблицу** в SQL базе данных, это не просто *модель данных* (как обычный класс Pydantic).
-* `Field(primary_key=True)` для SQLModel означает, что поле `id` является первичным ключом в таблице базы данных (вы можете подробнее узнать о первичных ключах баз данных в документации по SQLModel).
+* `Field(primary_key=True)` сообщает SQLModel, что `id` — это **первичный ключ** в SQL базе данных (подробнее о первичных ключах можно узнать в документации SQLModel).
- Тип `int | None` Ñ\81игнализиÑ\80Ñ\83еÑ\82 длÑ\8f SQLModel, Ñ\87Ñ\82о Ñ\81Ñ\82олбеÑ\86 Ñ\82аблиÑ\86Ñ\8b базÑ\8b даннÑ\8bÑ\85 должен имеÑ\82Ñ\8c Ñ\82ип `INTEGER`, или имеÑ\82Ñ\8c пÑ\83Ñ\81Ñ\82ое знаÑ\87ение `NULL`.
+ Ð\91лагодаÑ\80Ñ\8f Ñ\82ипÑ\83 `int | None`, SQLModel бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о Ñ\8dÑ\82оÑ\82 Ñ\81Ñ\82олбеÑ\86 должен бÑ\8bÑ\82Ñ\8c `INTEGER` в SQL базе даннÑ\8bÑ\85 и должен допÑ\83Ñ\81каÑ\82Ñ\8c знаÑ\87ение `NULL`.
-* `Field(index=True)` для SQLModel означает, что нужно создать **SQL индекс** для данного столбца. Это обеспечит более быстрый поиск при чтении данных, отфильтрованных по данному столбцу.
+* `Field(index=True)` сообщает SQLModel, что нужно создать **SQL индекс** для этого столбца, что позволит быстрее выполнять выборки при чтении данных, отфильтрованных по этому столбцу.
- SQLModel бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о даннÑ\8bе Ñ\82ипа `str`, бÑ\83дÑ\83Ñ\82 пÑ\80едÑ\81Ñ\82авленÑ\8b в базе даннÑ\8bÑ\85 как `TEXT` (или `VARCHAR`, в завиÑ\81имоÑ\81Ñ\82и оÑ\82 Ñ\82ипа базы данных).
+ SQLModel бÑ\83деÑ\82 знаÑ\82Ñ\8c, Ñ\87Ñ\82о обÑ\8aÑ\8fвленное как `str` Ñ\81Ñ\82анеÑ\82 SQL-Ñ\81Ñ\82олбÑ\86ом Ñ\82ипа `TEXT` (или `VARCHAR`, в завиÑ\81имоÑ\81Ñ\82и оÑ\82 базы данных).
-### Создание соединения с базой данных (Engine)
+### Создание Engine { #create-an-engine }
-Ð\92 SQLModel обÑ\8aекÑ\82 Ñ\81оединениÑ\8f `engine` (по Ñ\81Ñ\83Ñ\82и Ñ\8dÑ\82о `Engine` из SQLAlchemy) **Ñ\81одеÑ\80жиÑ\82 пÑ\83л Ñ\81оединений** к базе данных.
+Ð\9eбÑ\8aекÑ\82 `engine` в SQLModel (под капоÑ\82ом Ñ\8dÑ\82о `engine` из SQLAlchemy) **Ñ\83деÑ\80живаеÑ\82 Ñ\81оединениÑ\8f** Ñ\81 базой данных.
-Ð\94лÑ\8f обеÑ\81пеÑ\87ениÑ\8f вÑ\81еÑ\85 подклÑ\8eÑ\87ений пÑ\80иложениÑ\8f к одной базе даннÑ\8bÑ\85 нÑ\83жен Ñ\82олÑ\8cко один обÑ\8aекÑ\82 Ñ\81оединениÑ\8f `engine`.
+У ваÑ\81 должен бÑ\8bÑ\82Ñ\8c **один обÑ\8aекÑ\82 `engine`** длÑ\8f вÑ\81ей кодовой базÑ\8b, Ñ\87Ñ\82обÑ\8b подклÑ\8eÑ\87аÑ\82Ñ\8cÑ\81Ñ\8f к одной и Ñ\82ой же базе даннÑ\8bÑ\85.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
-Ð\98Ñ\81полÑ\8cзование наÑ\81Ñ\82Ñ\80ойки `check_same_thread=False` позволÑ\8fеÑ\82 FastAPI иÑ\81полÑ\8cзоваÑ\82Ñ\8c однÑ\83 и Ñ\82Ñ\83 же SQLite базÑ\83 даннÑ\8bÑ\85 в Ñ\80азлиÑ\87нÑ\8bÑ\85 поÑ\82окаÑ\85 (threads). ÐÑ\82о необÑ\85одимо, когда **один запÑ\80оÑ\81** иÑ\81полÑ\8cзÑ\83еÑ\82 **более одного потока** (например, в зависимостях).
+Ð\9fаÑ\80амеÑ\82Ñ\80 `check_same_thread=False` позволÑ\8fеÑ\82 FastAPI иÑ\81полÑ\8cзоваÑ\82Ñ\8c однÑ\83 и Ñ\82Ñ\83 же базÑ\83 даннÑ\8bÑ\85 SQLite в Ñ\80азнÑ\8bÑ\85 поÑ\82окаÑ\85. ÐÑ\82о необÑ\85одимо, Ñ\82ак как **один запÑ\80оÑ\81** можеÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c **болÑ\8cÑ\88е одного потока** (например, в зависимостях).
-Ð\9dе беÑ\81покойÑ\82еÑ\81Ñ\8c, Ñ\83Ñ\87иÑ\82Ñ\8bваÑ\8f Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80Ñ\83 кода, мÑ\8b позже позабоÑ\82имÑ\81Ñ\8f о Ñ\82ом, Ñ\87Ñ\82обÑ\8b иÑ\81полÑ\8cзоваÑ\82Ñ\8c **оÑ\82делÑ\8cнÑ\83Ñ\8e SQLModel-Ñ\81еÑ\81Ñ\81иÑ\8e на каждÑ\8bй оÑ\82делÑ\8cнÑ\8bй запÑ\80оÑ\81**, Ñ\8dÑ\82о как Ñ\80аз Ñ\82о, Ñ\87Ñ\82о пÑ\8bÑ\82аеÑ\82Ñ\81Ñ\8f обеÑ\81пеÑ\87иÑ\82Ñ\8c `check_same_thread`.
+Ð\9dе волнÑ\83йÑ\82еÑ\81Ñ\8c, Ñ\81 Ñ\82акой Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80ой кода мÑ\8b позже обеÑ\81пеÑ\87им иÑ\81полÑ\8cзование **одной *Ñ\81еÑ\81Ñ\81ии* SQLModel на запÑ\80оÑ\81**, по Ñ\81Ñ\83Ñ\82и именно Ñ\8dÑ\82ого и добиваеÑ\82Ñ\81Ñ\8f `check_same_thread`.
-### Создание таблиц
+### Создание таблиц { #create-the-tables }
-Ð\94алее мÑ\8b добавлÑ\8fем Ñ\84Ñ\83нкÑ\86иÑ\8e, иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\89Ñ\83Ñ\8e `SQLModel.metadata.create_all(engine)`, длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b Ñ\81оздаÑ\82Ñ\8c **Ñ\82аблиÑ\86Ñ\8b** длÑ\8f каждой из **моделей Ñ\82аблиÑ\86Ñ\8b**.
+Ð\94алее мÑ\8b добавим Ñ\84Ñ\83нкÑ\86иÑ\8e, коÑ\82оÑ\80аÑ\8f иÑ\81полÑ\8cзÑ\83еÑ\82 `SQLModel.metadata.create_all(engine)`, Ñ\87Ñ\82обÑ\8b **Ñ\81оздаÑ\82Ñ\8c Ñ\82аблиÑ\86Ñ\8b** длÑ\8f вÑ\81еÑ\85 *моделей-Ñ\82аблиÑ\86*.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
-### Создание зависимости Session
+### Создание зависимости Session { #create-a-session-dependency }
-Сессия базы данных (**`Session`**) хранит **объекты в памяти** и отслеживает любые необходимые изменения в данных, а затем **использует `engine`** для коммуникации с базой данных.
+**`Session`** хранит **объекты в памяти** и отслеживает необходимые изменения в данных, затем **использует `engine`** для общения с базой данных.
-Мы создадим FastAPI-**зависимость** с помощью `yield`, которая будет создавать новую сессию (Session) для каждого запроса. Это как раз и обеспечит использование отдельной сессии на каждый отдельный запрос. 🤓
+Мы создадим **зависимость** FastAPI с `yield`, которая будет предоставлять новую `Session` для каждого запроса. Это и обеспечивает использование одной сессии на запрос. 🤓
-Затем мы создадим объявленную (`Annotated`) зависимость `SessionDep`. Мы сделаем это для того, чтобы упростить остальной код, который будет использовать эту зависимость.
+Затем мы создадим объявленную (`Annotated`) зависимость `SessionDep`, чтобы упростить остальной код, который будет использовать эту зависимость.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
-### Создание таблиц базы данных при запуске приложения
+### Создание таблиц базы данных при старте { #create-database-tables-on-startup }
-Мы будем создавать таблицы базы данных при запуске приложения.
+Мы создадим таблицы базы данных при запуске приложения.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
-Ð\92 данном пÑ\80имеÑ\80е мÑ\8b Ñ\81оздаем Ñ\82аблиÑ\86Ñ\8b пÑ\80и наÑ\81Ñ\82Ñ\83плении события запуска приложения.
+Ð\97деÑ\81Ñ\8c мÑ\8b Ñ\81оздаÑ\91м Ñ\82аблиÑ\86Ñ\8b в обÑ\80абоÑ\82Ñ\87ике события запуска приложения.
-Ð\92 пÑ\80одÑ\83кÑ\82овом пÑ\80иложении вÑ\8b, Ñ\81коÑ\80ее вÑ\81его, бÑ\83деÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81кÑ\80ипÑ\82 длÑ\8f мигÑ\80аÑ\86ии базÑ\8b даннÑ\8bÑ\85, коÑ\82оÑ\80Ñ\8bй вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f пеÑ\80ед запÑ\83Ñ\81ком приложения. 🤓
+Ð\94лÑ\8f пÑ\80одакÑ\88на вÑ\8b, веÑ\80оÑ\8fÑ\82но, бÑ\83деÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\81кÑ\80ипÑ\82 мигÑ\80аÑ\86ий, коÑ\82оÑ\80Ñ\8bй вÑ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f до запÑ\83Ñ\81ка приложения. 🤓
/// tip | Подсказка
-В SQLModel будут включены утилиты миграции, входящие в состав Alembic, но на данный момент вы просто можете использовать
-<a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a> напрямую.
+В SQLModel появятся утилиты миграций - обёртки над Alembic, но пока вы можете использовать <a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a> напрямую.
///
-### Создание героя (Hero)
+### Создание героя (Hero) { #create-a-hero }
-Ð\9aаждаÑ\8f моделÑ\8c в SQLModel Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\82акже моделÑ\8cÑ\8e Pydantic, поÑ\8dÑ\82омÑ\83 вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c еÑ\91 пÑ\80и **обÑ\8aÑ\8fвлении Ñ\82ипов**, Ñ\82оÑ\87но Ñ\82акже, как и модели Pydantic.
+Так как каждаÑ\8f моделÑ\8c SQLModel Ñ\82акже Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f моделÑ\8cÑ\8e Pydantic, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c еÑ\91 в Ñ\82еÑ\85 же **анноÑ\82аÑ\86иÑ\8fÑ\85 Ñ\82ипов**, в коÑ\82оÑ\80Ñ\8bÑ\85 иÑ\81полÑ\8cзÑ\83еÑ\82е модели Pydantic.
-Ð\9dапÑ\80имеÑ\80, пÑ\80и обÑ\8aÑ\8fвлении паÑ\80амеÑ\82Ñ\80а Ñ\82ипа `Hero`, она бÑ\83деÑ\82 Ñ\81Ñ\87иÑ\82ана из **Ñ\82ела JSON**.
+Ð\9dапÑ\80имеÑ\80, еÑ\81ли вÑ\8b обÑ\8aÑ\8fвиÑ\82е паÑ\80амеÑ\82Ñ\80 Ñ\82ипа `Hero`, он бÑ\83деÑ\82 пÑ\80оÑ\87иÑ\82ан из **JSON body (Ñ\82ела запÑ\80оÑ\81а)**.
-ТоÑ\87но Ñ\82акже, вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c еÑ\91 пÑ\80и обÑ\8aÑ\8fвлении Ñ\82ипа знаÑ\87ениÑ\8f, возвÑ\80аÑ\89аемого Ñ\84Ñ\83нкÑ\86ией, и Ñ\82огда Ñ\81Ñ\82Ñ\80Ñ\83кÑ\82Ñ\83Ñ\80иÑ\80ованнÑ\8bе даннÑ\8bе бÑ\83дÑ\83Ñ\82 оÑ\82обÑ\80аженÑ\8b Ñ\87еÑ\80ез полÑ\8cзоваÑ\82елÑ\8cÑ\81кий инÑ\82еÑ\80Ñ\84ейÑ\81 авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\81генеÑ\80иÑ\80ованной докÑ\83менÑ\82аÑ\86ии FastAPI.
+Ð\90налогиÑ\87но вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c еÑ\91 как **Ñ\82ип возвÑ\80аÑ\89аемого знаÑ\87ениÑ\8f** Ñ\84Ñ\83нкÑ\86ии, и Ñ\82огда Ñ\84оÑ\80ма даннÑ\8bÑ\85 оÑ\82обÑ\80азиÑ\82Ñ\81Ñ\8f в авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\81генеÑ\80иÑ\80ованном UI докÑ\83менÑ\82аÑ\86ии API.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
-Ð\9cÑ\8b иÑ\81полÑ\8cзÑ\83ем завиÑ\81имоÑ\81Ñ\82Ñ\8c `SessionDep` (Ñ\81еÑ\81Ñ\81иÑ\8e базÑ\8b даннÑ\8bÑ\85) длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b добавиÑ\82Ñ\8c нового геÑ\80оÑ\8f `Hero` в обÑ\8aекÑ\82 Ñ\81еÑ\81Ñ\81ии (`Session`), Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\8c изменениÑ\8f в базе даннÑ\8bÑ\85, обновиÑ\82Ñ\8c даннÑ\8bе геÑ\80оÑ\8f и заÑ\82ем веÑ\80нÑ\83Ñ\82Ñ\8c иÑ\85.
+Ð\97деÑ\81Ñ\8c мÑ\8b иÑ\81полÑ\8cзÑ\83ем завиÑ\81имоÑ\81Ñ\82Ñ\8c `SessionDep` (Ñ\8dÑ\82о `Session`), Ñ\87Ñ\82обÑ\8b добавиÑ\82Ñ\8c нового `Hero` в Ñ\8dкземплÑ\8fÑ\80 `Session`, заÑ\84икÑ\81иÑ\80оваÑ\82Ñ\8c изменениÑ\8f в базе даннÑ\8bÑ\85, обновиÑ\82Ñ\8c даннÑ\8bе в `hero` и заÑ\82ем веÑ\80нÑ\83Ñ\82Ñ\8c его.
-### ЧÑ\82ение даннÑ\8bÑ\85 о геÑ\80оÑ\8fÑ\85
+### ЧÑ\82ение геÑ\80оев { #read-heroes }
-Ð\9cÑ\8b можем **Ñ\87иÑ\82аÑ\82Ñ\8c** даннÑ\8bе геÑ\80оев из базÑ\8b даннÑ\8bÑ\85 Ñ\81 помоÑ\89Ñ\8cÑ\8e `select()`. Ð\9cÑ\8b можем вклÑ\8eÑ\87иÑ\82Ñ\8c `limit` и `offset` длÑ\8f поÑ\81Ñ\82Ñ\80аниÑ\87ного Ñ\81Ñ\87иÑ\82Ñ\8bваниÑ\8f результатов.
+Ð\9cÑ\8b можем **Ñ\87иÑ\82аÑ\82Ñ\8c** запиÑ\81и `Hero` из базÑ\8b даннÑ\8bÑ\85 Ñ\81 помоÑ\89Ñ\8cÑ\8e `select()`. Ð\9cожно добавиÑ\82Ñ\8c `limit` и `offset` длÑ\8f поÑ\81Ñ\82Ñ\80аниÑ\87ного вÑ\8bвода результатов.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
-### ЧÑ\82ение даннÑ\8bÑ\85 оÑ\82делÑ\8cного геÑ\80оÑ\8f
+### ЧÑ\82ение одного геÑ\80оÑ\8f { #read-one-hero }
-Мы можем прочитать данные отдельного героя (`Hero`).
+Мы можем **прочитать** одного `Hero`.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
-### Удаление даннÑ\8bÑ\85 геÑ\80оÑ\8f
+### Удаление геÑ\80оÑ\8f { #delete-a-hero }
-Мы также можем удалить героя `Hero` из базы данных.
+Мы также можем **удалить** `Hero`.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
-### Запуск приложения
+### Запуск приложения { #run-the-app }
-Вы можете запустить приложение следующим образом:
+Вы можете запустить приложение:
<div class="termy">
</div>
-Ð\94алее пеÑ\80ейдиÑ\82е в полÑ\8cзоваÑ\82елÑ\8cÑ\81кий инÑ\82еÑ\80Ñ\84ейÑ\81 API `/docs`. Ð\92Ñ\8b Ñ\83видиÑ\82е, Ñ\87Ñ\82о **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 модели длÑ\8f Ñ\81озданиÑ\8f докÑ\83менÑ\82аÑ\86ии API. ÐÑ\82и же модели иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82Ñ\81Ñ\8f длÑ\8f Ñ\81еÑ\80иализаÑ\86ии и пÑ\80овеÑ\80ки данных.
+Ð\97аÑ\82ем пеÑ\80ейдиÑ\82е в UI `/docs`. Ð\92Ñ\8b Ñ\83видиÑ\82е, Ñ\87Ñ\82о **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Ñ\8dÑ\82и **модели** длÑ\8f **докÑ\83менÑ\82иÑ\80ованиÑ\8f** API, а Ñ\82акже длÑ\8f **Ñ\81еÑ\80иализаÑ\86ии** и **валидаÑ\86ии** данных.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image01.png">
</div>
-## Ð\94обавление в пÑ\80иложение дополниÑ\82елÑ\8cнÑ\8bÑ\85 (вÑ\81помогаÑ\82елÑ\8cнÑ\8bÑ\85) моделей
+## Ð\9eбновление пÑ\80иложениÑ\8f Ñ\81 неÑ\81колÑ\8cкими моделÑ\8fми { #update-the-app-with-multiple-models }
-ТепеÑ\80Ñ\8c давайÑ\82е пÑ\80оведÑ\91м **Ñ\80еÑ\84акÑ\82оÑ\80инг** наÑ\88его пÑ\80иложениÑ\8f, Ñ\87Ñ\82обÑ\8b Ñ\81делаÑ\82Ñ\8c его более безопаÑ\81нÑ\8bм и более Ñ\83нивеÑ\80Ñ\81алÑ\8cнÑ\8bм.
+ТепеÑ\80Ñ\8c давайÑ\82е немного **оÑ\82Ñ\80еÑ\84акÑ\82оÑ\80им** пÑ\80иложение, Ñ\87Ñ\82обÑ\8b повÑ\8bÑ\81иÑ\82Ñ\8c **безопаÑ\81ноÑ\81Ñ\82Ñ\8c** и **Ñ\83нивеÑ\80Ñ\81алÑ\8cноÑ\81Ñ\82Ñ\8c**.
-Ð\9eбÑ\80аÑ\82иÑ\82е внимание, Ñ\87Ñ\82о на данном Ñ\8dÑ\82апе наÑ\88е пÑ\80иложение позволÑ\8fеÑ\82 на Ñ\83Ñ\80овне клиенÑ\82а опÑ\80еделÑ\8fÑ\82Ñ\8c `id` Ñ\81оздаваемого геÑ\80оÑ\8f (`Hero`). 😱
+Ð\95Ñ\81ли вÑ\8b поÑ\81моÑ\82Ñ\80иÑ\82е на пÑ\80едÑ\8bдÑ\83Ñ\89Ñ\83Ñ\8e веÑ\80Ñ\81иÑ\8e, в UI видно, Ñ\87Ñ\82о до Ñ\81иÑ\85 поÑ\80 клиенÑ\82 мог Ñ\81ам задаваÑ\82Ñ\8c `id` Ñ\81оздаваемого `Hero`. 😱
-Ð\9cÑ\8b не можем Ñ\8dÑ\82ого допÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c, Ñ\82.к. Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 Ñ\80иÑ\81к пеÑ\80епиÑ\81аÑ\82Ñ\8c Ñ\83же пÑ\80иÑ\81военнÑ\8bе `id` в базе даннÑ\8bÑ\85. Ð\9fÑ\80иÑ\81воение `id` должно пÑ\80оиÑ\81Ñ\85одиÑ\82Ñ\8c **на Ñ\83Ñ\80овне бÑ\8dкÑ\8dнда (backend)** или **на Ñ\83Ñ\80овне базÑ\8b даннÑ\8bÑ\85**, но никак **не на Ñ\83Ñ\80овне клиенÑ\82а**.
+Так делаÑ\82Ñ\8c нелÑ\8cзÑ\8f, инаÑ\87е они могли бÑ\8b пеÑ\80езапиÑ\81аÑ\82Ñ\8c `id`, коÑ\82оÑ\80Ñ\8bй Ñ\83же пÑ\80иÑ\81воен в Ð\91Ð\94. РеÑ\88ение по `id` должно пÑ\80инимаÑ\82Ñ\8cÑ\81Ñ\8f **бÑ\8dкендом** или **базой даннÑ\8bÑ\85**, а **не клиенÑ\82ом**.
-Кроме того, мы создаем секретное имя `secret_name` для героя, но пока что, мы возвращаем его повсеместно, и это слабо напоминает **секретность**... 😅
+Кроме того, мы создаём для героя `secret_name`, но пока что возвращаем его повсюду — это не очень **секретно**... 😅
-Ð\9cÑ\8b попÑ\80авим Ñ\8dÑ\82о Ñ\81 помоÑ\89Ñ\8cÑ\8e неÑ\81колÑ\8cкиÑ\85 дополниÑ\82елÑ\8cнÑ\8bÑ\85 (вÑ\81помогаÑ\82елÑ\8cнÑ\8bÑ\85) моделей. Ð\92оÑ\82 где SQLModel по-наÑ\81Ñ\82оÑ\8fÑ\89емÑ\83 покажеÑ\82 Ñ\81ебÑ\8f. ✨
+Ð\9cÑ\8b иÑ\81пÑ\80авим Ñ\8dÑ\82о, добавив неÑ\81колÑ\8cко **дополниÑ\82елÑ\8cнÑ\8bÑ\85 моделей**. Ð\97деÑ\81Ñ\8c SQLModel Ñ\80аÑ\81кÑ\80оеÑ\82Ñ\81Ñ\8f во вÑ\81ей кÑ\80аÑ\81е. ✨
-### Создание дополниÑ\82елÑ\8cнÑ\8bÑ\85 моделей
+### Создание неÑ\81колÑ\8cкиÑ\85 моделей { #create-multiple-models }
-В **SQLModel**, любая модель с параметром `table=True` является **моделью таблицы**.
+В **SQLModel** любая модель с `table=True` — это **модель-таблица**.
-Любая модель, не содержащая `table=True` является **моделью данных**, это по сути обычные модели Pydantic (с несколько расширенным функционалом). 🤓
+Любая модель без `table=True` — это **модель данных**, по сути обычная модель Pydantic (с парой небольших дополнений). 🤓
-С помощью SQLModel мы можем использовать **наследование**, что поможет нам **избежать дублирования** всех полей.
+С SQLModel мы можем использовать **наследование**, чтобы **избежать дублирования** полей.
-#### Базовый класс `HeroBase`
+#### `HeroBase` — базовый класс { #herobase-the-base-class }
-Ð\94авайÑ\82е наÑ\87нÑ\91м Ñ\81 модели `HeroBase`, коÑ\82оÑ\80аÑ\8f Ñ\81одеÑ\80жиÑ\82 полÑ\8f, обÑ\89ие для всех моделей:
+Ð\9dаÑ\87нÑ\91м Ñ\81 модели `HeroBase`, коÑ\82оÑ\80аÑ\8f Ñ\81одеÑ\80жиÑ\82 **обÑ\89ие полÑ\8f** для всех моделей:
* `name`
* `age`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
-#### Модель таблицы `Hero`
+#### `Hero` — *модель-таблица* { #hero-the-table-model }
-Далее давайте создадим **модель таблицы** `Hero` с дополнительными полями, которых может не быть в других моделях:
+Далее создадим `Hero`, фактическую *модель-таблицу*, с **дополнительными полями**, которых может не быть в других моделях:
* `id`
* `secret_name`
-Ð\9cоделÑ\8c `Hero` наÑ\81ледÑ\83еÑ\82 оÑ\82 `HeroBase`, и поÑ\8dÑ\82омÑ\83 вклÑ\8eÑ\87аеÑ\82 Ñ\82акже полÑ\8f из `HeroBase`. Таким обÑ\80азом, вÑ\81е полÑ\8f, Ñ\81одеÑ\80жаÑ\89иеÑ\81Ñ\8f в `Hero`, бÑ\83дÑ\83Ñ\82 Ñ\81ледÑ\83Ñ\8eÑ\89ими:
+Так как `Hero` наÑ\81ледÑ\83еÑ\82Ñ\81Ñ\8f оÑ\82 `HeroBase`, он **Ñ\82акже** имееÑ\82 **полÑ\8f**, обÑ\8aÑ\8fвленнÑ\8bе в `HeroBase`, поÑ\8dÑ\82омÑ\83 вÑ\81е полÑ\8f `Hero`:
* `id`
* `name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
-#### Публичная модель данных `HeroPublic`
+#### `HeroPublic` — публичная *модель данных* { #heropublic-the-public-data-model }
-Далее мы создадим модель `HeroPublic`. Мы будем возвращать её клиентам API.
+Далее мы создадим модель `HeroPublic`, именно она будет **возвращаться** клиентам API.
-Ð\9eна вклÑ\8eÑ\87аеÑ\82 в Ñ\81ебÑ\8f Ñ\82е же полÑ\8f, Ñ\87Ñ\82о и `HeroBase`, и, Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82венно, поле `secret_name` в ней оÑ\82Ñ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83еÑ\82.
+У неÑ\91 Ñ\82е же полÑ\8f, Ñ\87Ñ\82о и Ñ\83 `HeroBase`, поÑ\8dÑ\82омÑ\83 она не вклÑ\8eÑ\87аеÑ\82 `secret_name`.
Наконец-то личность наших героев защищена! 🥷
-Ð\92 модели `HeroPublic` Ñ\82акже обÑ\8aÑ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f поле `id: int`. Ð\9cÑ\8b как бÑ\8b заклÑ\8eÑ\87аем договоÑ\80енноÑ\81Ñ\82Ñ\8c Ñ\81 API клиенÑ\82ом, на Ñ\82о, Ñ\87Ñ\82о пеÑ\80едаваемÑ\8bе даннÑ\8bе вÑ\81егда должнÑ\8b Ñ\81одеÑ\80жаÑ\82Ñ\8c поле `id`, и Ñ\8dÑ\82о поле должно Ñ\81одеÑ\80жаÑ\82Ñ\8c Ñ\86елое Ñ\87иÑ\81ло (и никогда не Ñ\81одеÑ\80жаÑ\82Ñ\8c `None`).
+Также здеÑ\81Ñ\8c заново обÑ\8aÑ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f `id: int`. Тем Ñ\81амÑ\8bм мÑ\8b заклÑ\8eÑ\87аем **конÑ\82Ñ\80акÑ\82** Ñ\81 клиенÑ\82ами API: они вÑ\81егда могÑ\83Ñ\82 Ñ\80аÑ\81Ñ\81Ñ\87иÑ\82Ñ\8bваÑ\82Ñ\8c, Ñ\87Ñ\82о поле `id` пÑ\80иÑ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83еÑ\82 и Ñ\8dÑ\82о `int` (никогда не `None`).
/// tip | Подсказка
-Ð\9cоделÑ\8c оÑ\82веÑ\82а, гаÑ\80анÑ\82иÑ\80Ñ\83Ñ\8eÑ\89аÑ\8f налиÑ\87ие полÑ\8f Ñ\81о знаÑ\87ением Ñ\82ипа `int` (не `None`), оÑ\87енÑ\8c полезна пÑ\80и Ñ\80азÑ\80абоÑ\82ке API клиенÑ\82ов. Ð\9eпÑ\80еделенноÑ\81Ñ\82Ñ\8c в пеÑ\80едаваемÑ\8bÑ\85 даннÑ\8bÑ\85 можеÑ\82 обеÑ\81пеÑ\87иÑ\82Ñ\8c напиÑ\81ание более пÑ\80оÑ\81Ñ\82ого кода.
+Ð\93аÑ\80анÑ\82иÑ\8f Ñ\82ого, Ñ\87Ñ\82о в модели оÑ\82веÑ\82а знаÑ\87ение вÑ\81егда пÑ\80иÑ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83еÑ\82 и Ñ\8dÑ\82о `int` (не `None`), оÑ\87енÑ\8c полезна длÑ\8f клиенÑ\82ов API â\80\94 Ñ\82ак можно пиÑ\81аÑ\82Ñ\8c гоÑ\80аздо более пÑ\80оÑ\81Ñ\82ой код.
-Также **авÑ\82омаÑ\82иÑ\87еÑ\81ки генеÑ\80иÑ\80Ñ\83емÑ\8bе клиенÑ\82Ñ\8b** бÑ\83дÑ\83Ñ\82 имеÑ\82Ñ\8c более пÑ\80оÑ\81Ñ\82ой инÑ\82еÑ\80Ñ\84ейÑ\81. Ð\98 в Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82е жизнÑ\8c Ñ\80азÑ\80абоÑ\82Ñ\87иков, иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\89иÑ\85 ваÑ\88 API, Ñ\81Ñ\82анеÑ\82 знаÑ\87иÑ\82елÑ\8cно легÑ\87е. 😎
+Ð\9aÑ\80оме Ñ\82ого, **авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\81генеÑ\80иÑ\80ованнÑ\8bе клиенÑ\82Ñ\8b** бÑ\83дÑ\83Ñ\82 имеÑ\82Ñ\8c более пÑ\80оÑ\81Ñ\82Ñ\8bе инÑ\82еÑ\80Ñ\84ейÑ\81Ñ\8b, и Ñ\80азÑ\80абоÑ\82Ñ\87икам, взаимодейÑ\81Ñ\82вÑ\83Ñ\8eÑ\89им Ñ\81 ваÑ\88им API, бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c знаÑ\87иÑ\82елÑ\8cно комÑ\84оÑ\80Ñ\82нее. 😎
///
-`HeroPublic` содержит все поля `HeroBase`, а также поле `id`, объявленное как `int` (не `None`):
+Все поля `HeroPublic` такие же, как в `HeroBase`, а `id` объявлен как `int` (не `None`):
* `id`
* `name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
-#### Модель для создания героя `HeroCreate`
+#### `HeroCreate` — *модель данных* для создания героя { #herocreate-the-data-model-to-create-a-hero }
-СейÑ\87аÑ\81 мÑ\8b Ñ\81оздадим моделÑ\8c `HeroCreate`. ÐÑ\82а моделÑ\8c бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f длÑ\8f пÑ\80овеÑ\80ки даннÑ\8bÑ\85, пеÑ\80еданнÑ\8bÑ\85 клиенÑ\82ом.
+ТепеÑ\80Ñ\8c Ñ\81оздадим моделÑ\8c `HeroCreate`, она бÑ\83деÑ\82 **валидиÑ\80оваÑ\82Ñ\8c** даннÑ\8bе оÑ\82 клиенÑ\82ов.
-Ð\9eна Ñ\81одеÑ\80жиÑ\82 Ñ\82е же полÑ\8f, Ñ\87Ñ\82о и `HeroBase`, а Ñ\82акже поле `secret_name`.
+У неÑ\91 Ñ\82е же полÑ\8f, Ñ\87Ñ\82о и Ñ\83 `HeroBase`, а Ñ\82акже еÑ\81Ñ\82Ñ\8c `secret_name`.
-ТепеÑ\80Ñ\8c, пÑ\80и Ñ\81оздании нового геÑ\80оÑ\8f, клиенÑ\82Ñ\8b бÑ\83дÑ\83Ñ\82 пеÑ\80едаваÑ\82Ñ\8c Ñ\81екÑ\80еÑ\82ное имÑ\8f `secret_name`, коÑ\82оÑ\80ое бÑ\83деÑ\82 Ñ\81оÑ\85Ñ\80анено в базе даннÑ\8bÑ\85, но не бÑ\83деÑ\82 возвÑ\80аÑ\89ено в оÑ\82веÑ\82е API клиенÑ\82ам.
+ТепеÑ\80Ñ\8c, когда клиенÑ\82Ñ\8b **Ñ\81оздаÑ\8eÑ\82 нового геÑ\80оÑ\8f**, они бÑ\83дÑ\83Ñ\82 оÑ\82пÑ\80авлÑ\8fÑ\82Ñ\8c `secret_name`, он Ñ\81оÑ\85Ñ\80аниÑ\82Ñ\81Ñ\8f в базе даннÑ\8bÑ\85, но не бÑ\83деÑ\82 возвÑ\80аÑ\89аÑ\82Ñ\8cÑ\81Ñ\8f клиенÑ\82ам в API.
/// tip | Подсказка
-Ð\92оÑ\82 как нÑ\83жно Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 **паÑ\80олÑ\8fми**: полÑ\83Ñ\87айÑ\82е иÑ\85, но не возвÑ\80аÑ\89айÑ\82е иÑ\85 Ñ\87еÑ\80ез API.
+Так Ñ\81ледÑ\83еÑ\82 обÑ\80абаÑ\82Ñ\8bваÑ\82Ñ\8c **паÑ\80оли**: пÑ\80инимаÑ\82Ñ\8c иÑ\85, но не возвÑ\80аÑ\89аÑ\82Ñ\8c в API.
-Также хэшируйте значения паролей перед тем, как их сохранить. Ни в коем случае не храните пароли в открытом виде, как обычный текст.
+Также перед сохранением значения паролей нужно **хэшировать**, **никогда не храните их в открытом виде**.
///
-Поля модели `HeroCreate`:
+Поля `HeroCreate`:
* `name`
* `age`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
-#### Модель для обновления данных героя `HeroUpdate`
+#### `HeroUpdate` — *модель данных* для обновления героя { #heroupdate-the-data-model-to-update-a-hero }
-Ð\92 пÑ\80едÑ\8bдÑ\83Ñ\89иÑ\85 веÑ\80Ñ\81иÑ\8fÑ\85 наÑ\88ей пÑ\80огÑ\80аммÑ\8b мÑ\8b не могли обновиÑ\82Ñ\8c даннÑ\8bе геÑ\80оÑ\8f, Ñ\82епеÑ\80Ñ\8c, воÑ\81полÑ\8cзовавÑ\88иÑ\81Ñ\8c дополниÑ\82елÑ\8cнÑ\8bми моделÑ\8fми, мÑ\8b Ñ\81можем это сделать. 🎉
+Ð\92 пÑ\80едÑ\8bдÑ\83Ñ\89ей веÑ\80Ñ\81ии пÑ\80иложениÑ\8f Ñ\83 наÑ\81 не бÑ\8bло Ñ\81поÑ\81оба **обновлÑ\8fÑ\82Ñ\8c геÑ\80оÑ\8f**, но Ñ\82епеÑ\80Ñ\8c, Ñ\81 **неÑ\81колÑ\8cкими моделÑ\8fми**, мÑ\8b можем это сделать. 🎉
-Модель данных `HeroUpdate` в некотором смысле особенная. Она содержит все те же поля, что и модель создания героя, но все поля модели являются **необязательными**. (Все они имеют значение по умолчанию.) Таким образом, при обновлении данных героя, вам достаточно передать только те поля, которые требуют изменения.
+*Модель данных* `HeroUpdate` особенная: у неё **те же поля**, что и для создания нового героя, но все поля **необязательные** (у всех есть значение по умолчанию). Таким образом, при обновлении героя можно отправлять только те поля, которые нужно изменить.
-Поскольку **все поля по сути меняются** (теперь тип каждого поля допускает значение `None` и значение по умолчанию `None`), мы должны их **объявить заново**.
+Поскольку **фактически меняются все поля** (их тип теперь включает `None`, и по умолчанию они равны `None`), нам нужно **переобъявить** их.
-ФакÑ\82иÑ\87еÑ\81ки, нам не нÑ\83жно наÑ\81ледоваÑ\82Ñ\8cÑ\81Ñ\8f оÑ\82 `HeroBase`, поÑ\82омÑ\83 Ñ\87Ñ\82о мÑ\8b бÑ\83дем заново обÑ\8aÑ\8fвлÑ\8fÑ\82Ñ\8c вÑ\81е полÑ\8f. Я оÑ\81Ñ\82авлÑ\8e наÑ\81ледование пÑ\80оÑ\81Ñ\82о длÑ\8f поддеÑ\80жаниÑ\8f обÑ\89его Ñ\81Ñ\82илÑ\8f, но оно (наÑ\81ледование) здеÑ\81Ñ\8c необÑ\8fзаÑ\82елÑ\8cно. 🤷
+Ð\9dаÑ\81ледоваÑ\82Ñ\8cÑ\81Ñ\8f оÑ\82 `HeroBase` не обÑ\8fзаÑ\82елÑ\8cно, Ñ\82ак как мÑ\8b заново обÑ\8aÑ\8fвлÑ\8fем вÑ\81е полÑ\8f. Я оÑ\81Ñ\82авлÑ\8e наÑ\81ледование длÑ\8f единообÑ\80азиÑ\8f, но Ñ\8dÑ\82о не необÑ\85одимо. СкоÑ\80ее дело вкÑ\83Ñ\81а. 🤷
Поля `HeroUpdate`:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
-### Создание героя с помощью `HeroCreate` и возвращение результатов с помощью `HeroPublic`
+### Создание с `HeroCreate` и возврат `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }
-Теперь, когда у нас есть дополнительные модели, мы можем обновить те части приложения, которые их используют.
+Теперь, когда у нас есть **несколько моделей**, мы можем обновить части приложения, которые их используют.
-Ð\92меÑ\81Ñ\82е c запÑ\80оÑ\81ом на Ñ\81оздание геÑ\80оÑ\8f мÑ\8b полÑ\83Ñ\87аем обÑ\8aекÑ\82 даннÑ\8bÑ\85 `HeroCreate`, и Ñ\81оздаем на его оÑ\81нове обÑ\8aекÑ\82 модели Ñ\82аблиÑ\86Ñ\8b `Hero`.
+Ð\9cÑ\8b полÑ\83Ñ\87аем в запÑ\80оÑ\81е *моделÑ\8c даннÑ\8bÑ\85* `HeroCreate` и на еÑ\91 оÑ\81нове Ñ\81оздаÑ\91м *моделÑ\8c-Ñ\82аблиÑ\86Ñ\83* `Hero`.
-СозданнÑ\8bй обÑ\8aекÑ\82 *модели Ñ\82аблиÑ\86Ñ\8b* `Hero` бÑ\83деÑ\82 имеÑ\82Ñ\8c вÑ\81е полÑ\8f, пеÑ\80еданнÑ\8bе клиенÑ\82ом, а Ñ\82акже поле `id`, Ñ\81генеÑ\80иÑ\80ованное базой данных.
+Ð\9dоваÑ\8f *моделÑ\8c-Ñ\82аблиÑ\86а* `Hero` бÑ\83деÑ\82 имеÑ\82Ñ\8c полÑ\8f, оÑ\82пÑ\80авленнÑ\8bе клиенÑ\82ом, а Ñ\82акже `id`, Ñ\81генеÑ\80иÑ\80ованнÑ\8bй базой данных.
-Ð\94алее Ñ\84Ñ\83нкÑ\86иÑ\8f веÑ\80нÑ\91Ñ\82 обÑ\8aекÑ\82 *модели Ñ\82аблиÑ\86Ñ\8b* `Hero`. Ð\9dо поÑ\81колÑ\8cкÑ\83, мÑ\8b обÑ\8aÑ\8fвили `HeroPublic` как моделÑ\8c оÑ\82веÑ\82а, Ñ\82о **FastAPI** бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c именно еÑ\91 длÑ\8f пÑ\80овеÑ\80ки и сериализации данных.
+Ð\97аÑ\82ем возвÑ\80аÑ\89аем из Ñ\84Ñ\83нкÑ\86ии Ñ\82Ñ\83 же *моделÑ\8c-Ñ\82аблиÑ\86Ñ\83* `Hero` как еÑ\81Ñ\82Ñ\8c. Ð\9dо Ñ\82ак как мÑ\8b обÑ\8aÑ\8fвили `response_model` Ñ\81 *моделÑ\8cÑ\8e даннÑ\8bÑ\85* `HeroPublic`, **FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 `HeroPublic` длÑ\8f валидаÑ\86ии и сериализации данных.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
/// tip | Подсказка
-Теперь мы используем модель ответа `response_model=HeroPublic`, вместо того, чтобы объявить тип возвращаемого значения как `-> HeroPublic`. Мы это делаем потому, что тип возвращаемого значения не относится к `HeroPublic`.
+Теперь мы используем `response_model=HeroPublic` вместо **аннотации типа возвращаемого значения** `-> HeroPublic`, потому что фактически возвращаемое значение — это *не* `HeroPublic`.
-Если бы мы объявили тип возвращаемого значения как `-> HeroPublic`, то редактор и линтер начали бы ругаться (и вполне справедливо), что возвращаемое значение принадлежит типу `Hero`, а совсем не `HeroPublic`.
+Если бы мы объявили `-> HeroPublic`, ваш редактор кода и линтер справедливо пожаловались бы, что вы возвращаете `Hero`, а не `HeroPublic`.
-Ð\9eбÑ\8aÑ\8fвлÑ\8fÑ\8f моделÑ\8c оÑ\82веÑ\82а в `response_model`, мÑ\8b как бÑ\8b говоÑ\80им **FastAPI**: делай Ñ\81вое дело, не вмеÑ\88иваÑ\8fÑ\81Ñ\8c в анноÑ\82аÑ\86иÑ\8e Ñ\82ипов и не полагаÑ\8fÑ\81Ñ\8c на помоÑ\89Ñ\8c Ñ\80едакÑ\82оÑ\80а или других инструментов.
+Ð\9eбÑ\8aÑ\8fвлÑ\8fÑ\8f моделÑ\8c в `response_model`, мÑ\8b говоÑ\80им **FastAPI** Ñ\81делаÑ\82Ñ\8c Ñ\81воÑ\91 дело, не вмеÑ\88иваÑ\8fÑ\81Ñ\8c в анноÑ\82аÑ\86ии Ñ\82ипов и Ñ\80абоÑ\82Ñ\83 Ñ\80едакÑ\82оÑ\80а кода и других инструментов.
///
-### ЧÑ\82ение даннÑ\8bÑ\85 геÑ\80оев Ñ\81 помоÑ\89Ñ\8cÑ\8e `HeroPublic`
+### ЧÑ\82ение геÑ\80оев Ñ\81 `HeroPublic` { #read-heroes-with-heropublic }
-Ð\9cÑ\8b можем пÑ\80оделаÑ\82Ñ\8c Ñ\82о же Ñ\81амое **длÑ\8f Ñ\87Ñ\82ениÑ\8f даннÑ\8bÑ\85** геÑ\80оев. Ð\9cÑ\8b пÑ\80именим моделÑ\8c оÑ\82веÑ\82а `response_model=list[HeroPublic]`, и Ñ\82ем Ñ\81амÑ\8bм обеÑ\81пеÑ\87им пÑ\80авилÑ\8cнÑ\83Ñ\8e пÑ\80овеÑ\80кÑ\83 и Ñ\81еÑ\80иализаÑ\86иÑ\8e даннÑ\8bÑ\85.
+Ð\90налогиÑ\87но мÑ\8b можем **Ñ\87иÑ\82аÑ\82Ñ\8c** `Hero` â\80\94 Ñ\81нова иÑ\81полÑ\8cзÑ\83ем `response_model=list[HeroPublic]`, Ñ\87Ñ\82обÑ\8b даннÑ\8bе валидиÑ\80овалиÑ\81Ñ\8c и Ñ\81еÑ\80иализовалиÑ\81Ñ\8c коÑ\80Ñ\80екÑ\82но.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
-### ЧÑ\82ение даннÑ\8bÑ\85 оÑ\82делÑ\8cного геÑ\80оÑ\8f Ñ\81 помоÑ\89Ñ\8cÑ\8e `HeroPublic`
+### ЧÑ\82ение одного геÑ\80оÑ\8f Ñ\81 `HeroPublic` { #read-one-hero-with-heropublic }
-Ð\9cÑ\8b можем **пÑ\80оÑ\87иÑ\82аÑ\82Ñ\8c** даннÑ\8bе оÑ\82делÑ\8cного героя:
+Ð\9cÑ\8b можем **пÑ\80оÑ\87иÑ\82аÑ\82Ñ\8c** одного героя:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
-### Ð\9eбновление даннÑ\8bÑ\85 геÑ\80оÑ\8f Ñ\81 помоÑ\89Ñ\8cÑ\8e `HeroUpdate`
+### Ð\9eбновление геÑ\80оÑ\8f Ñ\81 `HeroUpdate` { #update-a-hero-with-heroupdate }
-Ð\9cÑ\8b можем **обновиÑ\82Ñ\8c даннÑ\8bе геÑ\80оÑ\8f**. Ð\94лÑ\8f Ñ\8dÑ\82ого мÑ\8b воÑ\81полÑ\8cзÑ\83емÑ\81Ñ\8f HTTP меÑ\82одом `PATCH`.
+Ð\9cÑ\8b можем **обновиÑ\82Ñ\8c геÑ\80оÑ\8f**. Ð\94лÑ\8f Ñ\8dÑ\82ого иÑ\81полÑ\8cзÑ\83ем HTTP опеÑ\80аÑ\86иÑ\8e `PATCH`.
-В коде мы получаем объект словаря `dict` с данными, переданными клиентом (т.е. **только c данными, переданными клиентом**, исключая любые значения, которые могли бы быть там только потому, что они являются значениями по умолчанию). Для того чтобы сделать это, мы воспользуемся опцией `exclude_unset=True`. В этом главная хитрость. 🪄
+В коде мы получаем `dict` со всеми данными, отправленными клиентом — **только с данными, отправленными клиентом**, исключая любые значения, которые были бы там лишь как значения по умолчанию. Для этого мы используем `exclude_unset=True`. Это главный трюк. 🪄
-Ð\97аÑ\82ем мÑ\8b пÑ\80именим `hero_db.sqlmodel_update(hero_data)`, и обновим `hero_db`, иÑ\81полÑ\8cзовав даннÑ\8bе `hero_data`.
+Ð\97аÑ\82ем мÑ\8b иÑ\81полÑ\8cзÑ\83ем `hero_db.sqlmodel_update(hero_data)`, Ñ\87Ñ\82обÑ\8b обновиÑ\82Ñ\8c `hero_db` даннÑ\8bми из `hero_data`.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
-### Удалим геÑ\80оÑ\8f еÑ\89Ñ\91 Ñ\80аз
+### Снова Ñ\83даление геÑ\80оÑ\8f { #delete-a-hero-again }
-Ð\9eпеÑ\80аÑ\86иÑ\8f **Ñ\83далениÑ\8f** геÑ\80оÑ\8f пÑ\80акÑ\82иÑ\87еÑ\81ки не менÑ\8fеÑ\82Ñ\81Ñ\8f.
+Ð\9eпеÑ\80аÑ\86иÑ\8f **Ñ\83далениÑ\8f** геÑ\80оÑ\8f оÑ\81Ñ\82аÑ\91Ñ\82Ñ\81Ñ\8f пÑ\80акÑ\82иÑ\87еÑ\81ки пÑ\80ежней.
-Ð\92 данном Ñ\81лÑ\83Ñ\87ае желание *`оÑ\82Ñ\80еÑ\84акÑ\82оÑ\80иÑ\82Ñ\8c вÑ\81Ñ\91`* оÑ\81Ñ\82аÑ\91Ñ\82Ñ\81Ñ\8f неÑ\83довлеÑ\82воÑ\80енным. 😅
+Ð\96елание *«оÑ\82Ñ\80еÑ\84акÑ\82оÑ\80иÑ\82Ñ\8c вÑ\81Ñ\91»* на Ñ\8dÑ\82оÑ\82 Ñ\80аз оÑ\81Ñ\82анеÑ\82Ñ\81Ñ\8f неÑ\83довлеÑ\82воÑ\80Ñ\91нным. 😅
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
-### Снова запустим приложение
+### Снова запустим приложение { #run-the-app-again }
Вы можете снова запустить приложение:
</div>
-Если вы перейдете в пользовательский интерфейс API `/docs`, то вы увидите, что он был обновлен, и больше не принимает параметра `id` от клиента при создании нового героя, и т.д.
+Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т. д.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image02.png">
</div>
-## Резюме
+## Резюме { #recap }
-Вы можете использовать <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> для взаимодействия с реляционными базами данных, а также для упрощения работы с **моделями данных** и **моделями таблиц**.
+Вы можете использовать <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> для взаимодействия с SQL базой данных и упростить код с помощью *моделей данных* и *моделей-таблиц*.
-Ð\92Ñ\8b можеÑ\82е Ñ\83знаÑ\82Ñ\8c гоÑ\80аздо болÑ\8cÑ\88е инÑ\84оÑ\80маÑ\86ии в докÑ\83менÑ\82аÑ\86ии по **SQLModel**. Там вÑ\8b найдеÑ\82е более подÑ\80обное <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">мини-Ñ\80Ñ\83ководÑ\81Ñ\82во по иÑ\81полÑ\8cзованиÑ\8e SQLModel с **FastAPI**</a>. 🚀
+Ð\93оÑ\80аздо болÑ\8cÑ\88е вÑ\8b можеÑ\82е Ñ\83знаÑ\82Ñ\8c в докÑ\83менÑ\82аÑ\86ии **SQLModel**, Ñ\82ам еÑ\81Ñ\82Ñ\8c более подÑ\80обнÑ\8bй мини-<a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">Ñ\82Ñ\83Ñ\82оÑ\80иал по иÑ\81полÑ\8cзованиÑ\8e SQLModel с **FastAPI**</a>. 🚀
-# Статические Файлы
+# Статические Файлы { #static-files }
Вы можете предоставлять статические файлы автоматически из директории, используя `StaticFiles`.
-## Использование `StaticFiles`
+## Использование `StaticFiles` { #use-staticfiles }
* Импортируйте `StaticFiles`.
-* "Примонтируйте" экземпляр `StaticFiles()` с указанием определенной директории.
+* "Примонтируйте" экземпляр `StaticFiles()` к определённому пути.
{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
///
-### Что такое "Монтирование"
+### Что такое "Монтирование" { #what-is-mounting }
-"Ð\9cонÑ\82иÑ\80ование" ознаÑ\87аеÑ\82 добавление полноÑ\86енного "незавиÑ\81имого" пÑ\80иложениÑ\8f в опÑ\80еделеннÑ\83Ñ\8e диÑ\80екÑ\82оÑ\80иÑ\8e, которое затем обрабатывает все подпути.
+"Ð\9cонÑ\82иÑ\80ование" ознаÑ\87аеÑ\82 добавление полноÑ\86енного "незавиÑ\81имого" пÑ\80иложениÑ\8f на опÑ\80еделÑ\91ннÑ\8bй пÑ\83Ñ\82Ñ\8c, которое затем обрабатывает все подпути.
Это отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым.
-OpenAPI и документация из вашего главного приложения не будет содержать ничего из примонтированного приложения, и т.д.
+OpenAPI и документация из вашего главного приложения не будут содержать ничего из примонтированного приложения, и т.д.
-Вы можете прочитать больше об этом в **Расширенном руководстве пользователя**.
+Вы можете прочитать больше об этом в [Расширенном руководстве пользователя](../advanced/index.md){.internal-link target=_blank}.
-## Детали
+## Детали { #details }
Первый параметр `"/static"` относится к подпути, по которому это "подприложение" будет "примонтировано". Таким образом, любой путь начинающийся со `"/static"` будет обработан этим приложением.
Все эти параметры могут отличаться от "`static`", настройте их в соответствии с вашими нуждами и конкретными деталями вашего собственного приложения.
-## Больше информации
+## Больше информации { #more-info }
Для получения дополнительной информации о деталях и настройках ознакомьтесь с <a href="https://www.starlette.io/staticfiles/" class="external-link" target="_blank">Документацией Starlette о статических файлах</a>.
-# Тестирование
+# Тестирование { #testing }
Благодаря <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>, тестировать приложения **FastAPI** легко и приятно.
Используя эти инструменты, Вы можете напрямую задействовать <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> с **FastAPI**.
-## Использование класса `TestClient`
+## Использование класса `TestClient` { #using-testclient }
/// info | Информация
-Для использования класса `TestClient` необходимо установить библиотеку <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>.
+Для использования класса `TestClient` сначала установите <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>.
-Например, так: `pip install httpx`.
+Убедитесь, что Вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили пакет, например:
+
+```console
+$ pip install httpx
+```
///
Также можно написать `from starlette.testclient import TestClient`.
-**FastAPI** предоставляет тот же самый `starlette.testclient` как `fastapi.testclient`. Это всего лишь небольшое удобство для Вас, как разработчика.
+**FastAPI** предоставляет тот же самый `starlette.testclient` как `fastapi.testclient`. Это всего лишь небольшое удобство для Вас, как разработчика. Но он берётся напрямую из Starlette.
///
///
-## Разделение тестов и приложения
+## Разделение тестов { #separating-tests }
В реальном приложении Вы, вероятно, разместите тесты в отдельном файле.
Кроме того, Ваше приложение **FastAPI** может состоять из нескольких файлов, модулей и т.п.
-### Файл приложения **FastAPI**
+### Файл приложения **FastAPI** { #fastapi-app-file }
Допустим, структура файлов Вашего приложения похожа на ту, что описана на странице [Более крупные приложения](bigger-applications.md){.internal-link target=_blank}:
│ └── main.py
```
-Ð\97деÑ\81Ñ\8c Ñ\84айл `main.py` Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f "Ñ\82оÑ\87кой вÑ\85ода" в Ð\92аÑ\88е пÑ\80иложение и Ñ\81одеÑ\80жиÑ\82 иниÑ\86иализаÑ\86иÑ\8e Ð\92аÑ\88его пÑ\80иложениÑ\8f **FastAPI**:
+Ð\92 Ñ\84айле `main.py` наÑ\85одиÑ\82Ñ\81Ñ\8f Ð\92аÑ\88е пÑ\80иложение **FastAPI**:
{* ../../docs_src/app_testing/main.py *}
-### Файл тестов
+### Файл тестов { #testing-file }
Также у Вас может быть файл `test_main.py` содержащий тесты. Можно разместить тестовый файл и файл приложения в одной директории (в директориях для Python-кода желательно размещать и файл `__init__.py`):
...и писать дальше тесты, как и раньше.
-## Тестирование: расширенный пример
+## Тестирование: расширенный пример { #testing-extended-example }
Теперь давайте расширим наш пример и добавим деталей, чтоб посмотреть, как тестировать различные части приложения.
-### Расширенный файл приложения **FastAPI**
+### Расширенный файл приложения **FastAPI** { #extended-fastapi-app-file }
Мы продолжим работу с той же файловой структурой, что и ранее:
В нём описана операция `GET`, которая может вернуть ошибку.
-Ещё есть операция `POST` и она тоже может вернуть ошибку.
+Ещё есть операция `POST`, и она может вернуть несколько ошибок.
Обе *операции пути* требуют наличия в запросе заголовка `X-Token`.
////
-//// tab | Python 3.8+ без Annotated
+//// tab | Python 3.8+ без Annotated
/// tip | Подсказка
////
-### Расширенный файл тестов
+### Расширенный файл тестов { #extended-testing-file }
Теперь обновим файл `test_main.py`, добавив в него тестов:
///
-## Запуск тестов
+## Запуск { #run-it }
+
+Далее Вам нужно установить `pytest`.
-Ð\94алее Ð\92ам нÑ\83жно Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c `pytest`:
+УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о Ð\92Ñ\8b Ñ\81оздали [виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение](../virtual-environments.md){.internal-link target=_blank}, акÑ\82ивиÑ\80овали его, а заÑ\82ем Ñ\83Ñ\81Ñ\82ановили пакеÑ\82, напÑ\80имеÑ\80:
<div class="termy">
Он автоматически найдёт все файлы и тесты, выполнит их и предоставит Вам отчёт о результатах тестирования.
-Запустите тесты командой `pytest` и увидите результат:
+Запустите тесты:
<div class="termy">
-# Виртуальная среда
+# Виртуальные окружения { #virtual-environments }
-Ð\9fÑ\80и Ñ\80абоÑ\82е Ñ\81 пÑ\80оекÑ\82ами в Python Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c **виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83 Ñ\80азÑ\80абоÑ\82ки** (или какой-нибÑ\83дÑ\8c дÑ\80Ñ\83гой подобнÑ\8bй меÑ\85анизм). ÐÑ\82о нÑ\83жно длÑ\8f Ñ\82ого, Ñ\87Ñ\82обÑ\8b изолиÑ\80оваÑ\82Ñ\8c Ñ\83Ñ\81Ñ\82анавливаемÑ\8bе пакеÑ\82Ñ\8b длÑ\8f каждого оÑ\82делÑ\8cного проекта.
+Ð\9fÑ\80и Ñ\80абоÑ\82е Ñ\81 пÑ\80оекÑ\82ами на Python Ñ\80екомендÑ\83еÑ\82Ñ\81Ñ\8f иÑ\81полÑ\8cзоваÑ\82Ñ\8c **виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение** (или поÑ\85ожий меÑ\85анизм), Ñ\87Ñ\82обÑ\8b изолиÑ\80оваÑ\82Ñ\8c пакеÑ\82Ñ\8b, коÑ\82оÑ\80Ñ\8bе вÑ\8b Ñ\83Ñ\81Ñ\82анавливаеÑ\82е длÑ\8f каждого проекта.
/// info | Дополнительная информация
-Если вы уже знакомы с виртуальными средами разработки, знаете как их создавать и использовать, то вы можете свободно пропустить данный раздел. 🤓
+Если вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓
///
/// tip | Подсказка
-**Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f Ñ\81Ñ\80еда** и **пеÑ\80еменнаÑ\8f окÑ\80Ñ\83жениÑ\8f** Ñ\8dÑ\82о две Ñ\80азнÑ\8bе веÑ\89и.
+**Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение** â\80\94 Ñ\8dÑ\82о не Ñ\82о же Ñ\81амое, Ñ\87Ñ\82о **пеÑ\80еменнаÑ\8f окÑ\80Ñ\83жениÑ\8f**.
-**Переменная окружения** это системная переменная, которую могут использовать программы.
+**Переменная окружения** — это переменная в системе, которую могут использовать программы.
-**Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f Ñ\81Ñ\80еда** Ñ\8dÑ\82о папка, Ñ\81одеÑ\80жаÑ\89аÑ\8f Ñ\84айлÑ\8b.
+**Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение** â\80\94 Ñ\8dÑ\82о диÑ\80екÑ\82оÑ\80иÑ\8f Ñ\81 Ñ\84айлами внÑ\83Ñ\82Ñ\80и.
///
/// info | Дополнительная информация
-Ð\92 Ñ\8dÑ\82ом Ñ\80азделе мÑ\8b наÑ\83Ñ\87им ваÑ\81 полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bми Ñ\81Ñ\80едами Ñ\80азÑ\80абоÑ\82ки и Ñ\80аÑ\81Ñ\81кажем, как они работают.
+Ð\9dа Ñ\8dÑ\82ой Ñ\81Ñ\82Ñ\80аниÑ\86е вÑ\8b Ñ\83знаеÑ\82е, как полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f **виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bми окÑ\80Ñ\83жениÑ\8fми** и как они работают.
-Если же вы готовы воспользоваться инструментом, **который умеет управлять всем, что касается Python-проектов**,
-(включая установку Python), то попробуйте <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
+Если вы готовы начать использовать **инструмент, который управляет всем** за вас (включая установку Python), попробуйте <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
///
-## Создание проекта
+## Создание проекта { #create-a-project }
-Ð\92 пеÑ\80вÑ\83Ñ\8e оÑ\87еÑ\80едÑ\8c, создайте директорию для вашего проекта.
+СнаÑ\87ала создайте директорию для вашего проекта.
-Я обÑ\8bÑ\87но Ñ\81оздаÑ\8e папкÑ\83 под названием `code` внÑ\83Ñ\82Ñ\80и моего домаÑ\88него каÑ\82алога `/home/user`.
+Ð\9eбÑ\8bÑ\87но Ñ\8f Ñ\81оздаÑ\8e папкÑ\83 Ñ\81 именем `code` в моем домаÑ\88нем каÑ\82алоге.
-Ð\97аÑ\82ем внÑ\83Ñ\82Ñ\80и данной папки Ñ\8f Ñ\81оздаÑ\8e оÑ\82делÑ\8cнÑ\83Ñ\8e диÑ\80екÑ\82оÑ\80иÑ\8e под каждÑ\8bй Ñ\81вой пÑ\80оекÑ\82.
+Ð\90 внÑ\83Ñ\82Ñ\80и неÑ\91 Ñ\81оздаÑ\8e оÑ\82делÑ\8cнÑ\83Ñ\8e диÑ\80екÑ\82оÑ\80иÑ\8e длÑ\8f каждого пÑ\80оекÑ\82а.
<div class="termy">
```console
// Перейдите в домашний каталог
$ cd
-// СоздайÑ\82е оÑ\82делÑ\8cнÑ\83Ñ\8e папкÑ\83 под вÑ\81е бÑ\83дÑ\83Ñ\89ие пÑ\80огÑ\80аммнÑ\8bе пÑ\80оекÑ\82Ñ\8b (code)
+// СоздайÑ\82е диÑ\80екÑ\82оÑ\80иÑ\8e длÑ\8f вÑ\81еÑ\85 ваÑ\88иÑ\85 пÑ\80оекÑ\82ов Ñ\81 кодом
$ mkdir code
-// Ð\92ойдиÑ\82е в директорию code
+// Ð\9fеÑ\80ейдиÑ\82е в Ñ\8dÑ\82Ñ\83 директорию code
$ cd code
-// Создайте директрорию под данный проект (awesome-project)
+// Создайте директорию для этого проекта
$ mkdir awesome-project
-// Перейдите в созданную директорию проекта
+// Перейдите в директорию проекта
$ cd awesome-project
```
</div>
-## Создание виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки
+## Создание виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f { #create-a-virtual-environment }
-Начиная работу с Python-проектом, сразу же создавайте виртуальную среду разработки
-**<abbr title="есть и другие опции, но мы рассмотрим наиболее простой вариант">внутри вашего проекта</abbr>**.
+Когда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **<abbr title="есть и другие опции, но это простой ориентир">внутри вашего проекта</abbr>**.
/// tip | Подсказка
-Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f Ñ\81Ñ\80еда Ñ\80азÑ\80абоÑ\82ки Ñ\81оздаеÑ\82Ñ\81Ñ\8f один Ñ\80аз, и в далÑ\8cнейÑ\88ем, Ñ\80абоÑ\82аÑ\8f Ñ\81 пÑ\80оекÑ\82ом, Ñ\8dÑ\82ого болÑ\8cÑ\88е делаÑ\82Ñ\8c не пÑ\80идеÑ\82Ñ\81Ñ\8f.
+Ð\94елаÑ\82Ñ\8c Ñ\8dÑ\82о нÑ\83жно **один Ñ\80аз на пÑ\80оекÑ\82**, не каждÑ\8bй Ñ\80аз, когда вÑ\8b Ñ\80абоÑ\82аеÑ\82е.
///
//// tab | `venv`
-Ð\94лÑ\8f Ñ\81озданиÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b вÑ\8b можеÑ\82е воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f модÑ\83лем `venv`, коÑ\82оÑ\80Ñ\8bй Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e вÑ\81Ñ\82Ñ\80оенной библиоÑ\82еки Python.
+Ð\94лÑ\8f Ñ\81озданиÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f вÑ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c модÑ\83лÑ\8c `venv`, коÑ\82оÑ\80Ñ\8bй поÑ\81Ñ\82авлÑ\8fеÑ\82Ñ\81Ñ\8f вмеÑ\81Ñ\82е Ñ\81 Python.
<div class="termy">
/// details | Что делает эта команда?
-* `python`: иÑ\81полÑ\8cзоваÑ\82Ñ\8c пÑ\80огÑ\80аммÑ\83 под именем `python`
-* `-m`: вызывать модуль как скрипт, в следующей инструкции мы скажем какой именно модуль вызвать
-* `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python
-* `.venv`: создать виртуальную среду разработки в новой директории `.venv`
+* `python`: иÑ\81полÑ\8cзоваÑ\82Ñ\8c пÑ\80огÑ\80аммÑ\83 под названием `python`
+* `-m`: вызвать модуль как скрипт, далее мы укажем, какой модуль вызвать
+* `venv`: использовать модуль `venv`, который обычно устанавливается вместе с Python
+* `.venv`: создать виртуальное окружение в новой директории `.venv`
///
//// tab | `uv`
-Если вы установили <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, то вы можете им воспользоваться для создания виртуальной среды разработки.
+Если у вас установлен <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, вы можете использовать его для создания виртуального окружения.
<div class="termy">
/// tip | Подсказка
-По умолчанию `uv` создаст виртуальную среду разработки в папке под названием `.venv`.
+По умолчанию `uv` создаст виртуальное окружение в директории с именем `.venv`.
-Но вы можете это изменить, передав дополнительный аргумент с именем директории.
+Но вы можете переопределить это, передав дополнительный аргумент с именем директории.
///
////
-Ð\94аннаÑ\8f команда Ñ\81оздаÑ\81Ñ\82 новÑ\83Ñ\8e виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83 Ñ\80азÑ\80абоÑ\82ки в папке `.venv`.
+ÐÑ\82а команда Ñ\81оздаÑ\81Ñ\82 новое виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение в диÑ\80екÑ\82оÑ\80ии `.venv`.
/// details | `.venv` или другое имя?
-Вы можете поместить виртуальную среду разработки в папку с другим именем, но традиционным (конвенциональным) названием является `.venv` .
+Вы можете создать виртуальное окружение в другой директории, но по соглашению его называют `.venv`.
///
-## Ð\90кÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки
+## Ð\90кÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f { #activate-the-virtual-environment }
-Ð\90кÑ\82ивиÑ\80Ñ\83йÑ\82е виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83 Ñ\80азÑ\80абоÑ\82ки, и Ñ\82огда лÑ\8eбаÑ\8f запÑ\83Ñ\81каемаÑ\8f Python-команда или Ñ\83Ñ\81Ñ\82анавливаемÑ\8bй пакеÑ\82 бÑ\83дÑ\83Ñ\82 ее иÑ\81полÑ\8cзоваÑ\82Ñ\8c.
+Ð\90кÑ\82ивиÑ\80Ñ\83йÑ\82е новое виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение, Ñ\87Ñ\82обÑ\8b вÑ\81е командÑ\8b Python и Ñ\83Ñ\81Ñ\82анавливаемÑ\8bе пакеÑ\82Ñ\8b иÑ\81полÑ\8cзовали именно его.
/// tip | Подсказка
-Ð\9fÑ\80и Ñ\80абоÑ\82е над пÑ\80оекÑ\82ом делайÑ\82е Ñ\8dÑ\82о **каждÑ\8bй Ñ\80аз** пÑ\80и запÑ\83Ñ\81ке **новой Ñ\81еÑ\81Ñ\81ии в Ñ\82еÑ\80минале**.
+Ð\94елайÑ\82е Ñ\8dÑ\82о **каждÑ\8bй Ñ\80аз**, когда вÑ\8b наÑ\87инаеÑ\82е **новÑ\83Ñ\8e Ñ\81еÑ\81Ñ\81иÑ\8e Ñ\82еÑ\80минала** длÑ\8f Ñ\80абоÑ\82Ñ\8b над пÑ\80оекÑ\82ом.
///
//// tab | Windows Bash
-Ð\98ли пÑ\80и иÑ\81полÑ\8cзовании Bash длÑ\8f Windows (напÑ\80. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
+Ð\98ли еÑ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Bash длÑ\8f Windows (напÑ\80имеÑ\80, <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
////
-## Проверка активации виртуальной среды
+/// tip | Подсказка
+
+Каждый раз, когда вы устанавливаете **новый пакет** в это окружение, **активируйте** окружение снова.
-Проверьте, активна ли виртуальная среда (удостоверимся, что предыдущая команда сработала).
+Это гарантирует, что если вы используете **программу терминала (<abbr title="command line interface – интерфейс командной строки">CLI</abbr>)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна.
+
+///
+
+## Проверка, что виртуальное окружение активно { #check-the-virtual-environment-is-active }
+
+Проверьте, что виртуальное окружение активно (предыдущая команда сработала).
/// tip | Подсказка
-УбедиÑ\82еÑ\81Ñ\8c в Ñ\82ом, Ñ\87Ñ\82о вÑ\81е Ñ\80абоÑ\82аеÑ\82 Ñ\82ак, как нÑ\83жно и вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е именно Ñ\82Ñ\83 виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83 Ñ\80азÑ\80абоÑ\82ки, коÑ\82оÑ\80Ñ\83Ñ\8e нÑ\83жно. Ð\94елаÑ\82Ñ\8c Ñ\8dÑ\82о необÑ\8fзаÑ\82елÑ\8cно, но желаÑ\82елÑ\8cно.
+ÐÑ\82о **необÑ\8fзаÑ\82елÑ\8cно**, но Ñ\8dÑ\82о Ñ\85оÑ\80оÑ\88ий Ñ\81поÑ\81об **пÑ\80овеÑ\80иÑ\82Ñ\8c**, Ñ\87Ñ\82о вÑ\81Ñ\91 Ñ\80абоÑ\82аеÑ\82 как ожидаеÑ\82Ñ\81Ñ\8f и вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е запланиÑ\80ованное виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение.
///
</div>
-Ð\95Ñ\81ли даннаÑ\8f команда показÑ\8bваеÑ\82, Ñ\87Ñ\82о иÑ\81полнÑ\8fемÑ\8bй Ñ\84айл `python` (`.venv\bin\python`), наÑ\85одиÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80и виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b ваÑ\88его пÑ\80оекÑ\82а (Ñ\83 наÑ\81 Ñ\8dÑ\82о `awesome-project`), знаÑ\87иÑ\82 вÑ\81е оÑ\82Ñ\80абоÑ\82ало как нÑ\83жно. 🎉
+Ð\95Ñ\81ли оÑ\82обÑ\80ажаеÑ\82Ñ\81Ñ\8f иÑ\81полнÑ\8fемÑ\8bй Ñ\84айл `python` по пÑ\83Ñ\82и `.venv/bin/python` внÑ\83Ñ\82Ñ\80и ваÑ\88его пÑ\80оекÑ\82а (в наÑ\88ем Ñ\81лÑ\83Ñ\87ае `awesome-project`), знаÑ\87иÑ\82 вÑ\81Ñ\91 Ñ\81Ñ\80абоÑ\82ало. 🎉
////
</div>
-Ð\95Ñ\81ли даннаÑ\8f команда показÑ\8bваеÑ\82, Ñ\87Ñ\82о иÑ\81полнÑ\8fемÑ\8bй Ñ\84айл `python` (`.venv\Scripts\python`), наÑ\85одиÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80и виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b ваÑ\88его пÑ\80оекÑ\82а (Ñ\83 наÑ\81 Ñ\8dÑ\82о `awesome-project`), знаÑ\87иÑ\82 вÑ\81е оÑ\82Ñ\80абоÑ\82ало как нÑ\83жно. 🎉
+Ð\95Ñ\81ли оÑ\82обÑ\80ажаеÑ\82Ñ\81Ñ\8f иÑ\81полнÑ\8fемÑ\8bй Ñ\84айл `python` по пÑ\83Ñ\82и `.venv\Scripts\python` внÑ\83Ñ\82Ñ\80и ваÑ\88его пÑ\80оекÑ\82а (в наÑ\88ем Ñ\81лÑ\83Ñ\87ае `awesome-project`), знаÑ\87иÑ\82 вÑ\81Ñ\91 Ñ\81Ñ\80абоÑ\82ало. 🎉
////
-## Обновление `pip`
+## Обновление `pip` { #upgrade-pip }
/// tip | Подсказка
-Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, Ñ\82о вÑ\8b должнÑ\8b бÑ\83деÑ\82е его иÑ\81полÑ\8cзоваÑ\82Ñ\8c длÑ\8f Ñ\83Ñ\81Ñ\82ановки пакеÑ\82ов вмеÑ\81Ñ\82о `pip`, поÑ\8dÑ\82омÑ\83 обновлÑ\8fÑ\82Ñ\8c `pip` вам ненужно. 😎
+Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, Ñ\82о длÑ\8f Ñ\83Ñ\81Ñ\82ановки вÑ\8b бÑ\83деÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c его вмеÑ\81Ñ\82о `pip`, поÑ\8dÑ\82омÑ\83 обновлÑ\8fÑ\82Ñ\8c `pip` не нужно. 😎
///
-Если для установки пакетов вы используете `pip` (он устанавливается по умолчанию вместе с Python), то обновите `pip` до последней версии.
+Если для установки пакетов вы используете `pip` (он идёт по умолчанию вместе с Python), вам стоит **обновить** его до последней версии.
-Ð\91олÑ\8cÑ\88инÑ\81Ñ\82во Ñ\8dкзоÑ\82иÑ\87еÑ\81киÑ\85 оÑ\88ибок, возникаÑ\8eÑ\89иÑ\85 пÑ\80и Ñ\83Ñ\81Ñ\82ановке пакеÑ\82ов, Ñ\83Ñ\81Ñ\82Ñ\80анÑ\8fеÑ\82Ñ\81Ñ\8f предварительным обновлением `pip`.
+Ð\9cногие Ñ\8dкзоÑ\82иÑ\87еÑ\81кие оÑ\88ибки пÑ\80и Ñ\83Ñ\81Ñ\82ановке пакеÑ\82ов Ñ\80еÑ\88аÑ\8eÑ\82Ñ\81Ñ\8f пÑ\80оÑ\81Ñ\82Ñ\8bм предварительным обновлением `pip`.
/// tip | Подсказка
-Обычно это делается только один раз, сразу после создания виртуальной среды разработки.
+Обычно это делается **один раз**, сразу после создания виртуального окружения.
///
-Убедитесь в том, что виртуальная среда активирована (с помощью вышеуказанной команды) и запустите следующую команду:
+Убедитесь, что виртуальное окружение активно (см. команду выше) и запустите:
<div class="termy">
</div>
-## Добавление `.gitignore`
+## Добавление `.gitignore` { #add-gitignore }
-Если вы используете **Git** (а вы должны его использовать), то добавьте файл `.gitignore` и исключите из Git всё, что находится в папке `.venv`.
+Если вы используете **Git** (а вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить из Git всё, что находится в вашей `.venv`.
/// tip | Подсказка
-Ð\95Ñ\81ли длÑ\8f Ñ\81озданиÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, Ñ\82о длÑ\8f ваÑ\81 вÑ\81е Ñ\83же Ñ\81делано и вÑ\8b можеÑ\82е пропустить этот шаг. 😎
+Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзовали <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a> длÑ\8f Ñ\81озданиÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f, он Ñ\83же Ñ\81делал Ñ\8dÑ\82о за ваÑ\81 â\80\94 можно пропустить этот шаг. 😎
///
/// tip | Подсказка
-ÐÑ\82о делаеÑ\82Ñ\81Ñ\8f один Ñ\80аз, Ñ\81Ñ\80азÑ\83 поÑ\81ле Ñ\81озданиÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки.
+СделайÑ\82е Ñ\8dÑ\82о **один Ñ\80аз**, Ñ\81Ñ\80азÑ\83 поÑ\81ле Ñ\81озданиÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f.
///
/// details | Что делает эта команда?
-* `echo "*"`: напечатать `*` в консоли (следующий шаг это слегка изменит)
-* `>`: все что находится слева от `>` не печатать в консоль, но записать в файл находящийся справа от `>`
-* `.gitignore`: имя файла, в который нужно записать текст.
+* `echo "*"`: «напечатать» в терминале текст `*` (следующая часть немного меняет поведение)
+* `>`: всё, что команда слева от `>` выводит в терминал, вместо печати нужно записать в файл, указанный справа от `>`
+* `.gitignore`: имя файла, в который нужно записать текст
-`*` в Git означает "всё". Т.е. будет проигнорировано всё, что содержится в папке `.venv`.
+А `*` в Git означает «всё». То есть будет игнорироваться всё в директории `.venv`.
-Ð\94аннаÑ\8f команда Ñ\81оздаÑ\81Ñ\82 Ñ\84айл `.gitignore` Ñ\81ледÑ\83Ñ\8eÑ\89его Ñ\81одеÑ\80жаниÑ\8f:
+ÐÑ\82а команда Ñ\81оздаÑ\81Ñ\82 Ñ\84айл `.gitignore` Ñ\81о Ñ\81ледÑ\83Ñ\8eÑ\89им Ñ\81одеÑ\80жимÑ\8bм:
```gitignore
*
///
-## Установка пакетов
+## Установка пакетов { #install-packages }
-После установки виртуальной среды, вы можете устанавливать в нее пакеты.
+После активации окружения вы можете устанавливать в него пакеты.
/// tip | Подсказка
-Сделайте это **один раз**, при установке или обновлении пакетов, нужных вашему проекту.
+Сделайте это **один раз** при установке или обновлении пакетов, необходимых вашему проекту.
-Ð\95Ñ\81ли вам понадобиÑ\82Ñ\81Ñ\8f обновиÑ\82Ñ\8c веÑ\80Ñ\81иÑ\8e пакеÑ\82а или добавиÑ\82Ñ\8c новÑ\8bй пакеÑ\82, Ñ\82о вÑ\8b должнÑ\8b бÑ\83деÑ\82е **Ñ\81делаÑ\82Ñ\8c это снова**.
+Ð\95Ñ\81ли вам нÑ\83жно обновиÑ\82Ñ\8c веÑ\80Ñ\81иÑ\8e или добавиÑ\82Ñ\8c новÑ\8bй пакеÑ\82, вÑ\8b **Ñ\81делаеÑ\82е это снова**.
///
-### Установка пакетов напрямую
+### Установка пакетов напрямую { #install-packages-directly }
-Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, то вы можете установить их напрямую.
+Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, вы можете установить их напрямую.
/// tip | Подсказка
-Объявление пакетов, которые использует ваш проект, и их версий в отдельном файле (например, в `requirements.txt` или в `pyproject.toml`) - это отличная идея.
+Очень хорошая идея — указать используемые вашим проектом пакеты и их версии в файле (например, `requirements.txt` или `pyproject.toml`).
///
//// tab | `uv`
-Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
+Если у вас установлен <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
<div class="termy">
////
-### Установка из `requirements.txt`
+### Установка из `requirements.txt` { #install-from-requirements-txt }
-Если у вас есть `requirements.txt`, то вы можете использовать его для установки пакетов.
+Если у вас есть `requirements.txt`, вы можете использовать его для установки пакетов.
//// tab | `pip`
//// tab | `uv`
-Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
+Если у вас установлен <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
<div class="termy">
/// details | `requirements.txt`
-`requirements.txt` Ñ\81 паÑ\80оÑ\87кой пакеÑ\82ов внÑ\83Ñ\82Ñ\80и вÑ\8bглÑ\8fдиÑ\82 пÑ\80иблизиÑ\82елÑ\8cно так:
+`requirements.txt` Ñ\81 некоÑ\82оÑ\80Ñ\8bми пакеÑ\82ами можеÑ\82 вÑ\8bглÑ\8fдеÑ\82Ñ\8c так:
```requirements.txt
fastapi[standard]==0.113.0
///
-## Ð\97апÑ\83Ñ\81к пÑ\80огÑ\80аммÑ\8b
+## Ð\97апÑ\83Ñ\81к ваÑ\88ей пÑ\80огÑ\80аммÑ\8b { #run-your-program }
-Ð\9fоÑ\81ле акÑ\82иваÑ\86ии виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c Ñ\81воÑ\8e пÑ\80огÑ\80аммÑ\83 и она бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c веÑ\80Ñ\81иÑ\8e Python и пакеÑ\82Ñ\8b, Ñ\83Ñ\81Ñ\82ановленнÑ\8bе в виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80еде.
+Ð\9fоÑ\81ле акÑ\82иваÑ\86ии виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c Ñ\81воÑ\8e пÑ\80огÑ\80аммÑ\83, и она бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c Python из ваÑ\88его виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f вмеÑ\81Ñ\82е Ñ\81 Ñ\83Ñ\81Ñ\82ановленнÑ\8bми Ñ\82ам пакеÑ\82ами.
<div class="termy">
</div>
-## Настройка редактора
+## Настройка вашего редактора кода { #configure-your-editor }
-Ð\92еÑ\80оÑ\8fÑ\82но, вÑ\8b заÑ\85оÑ\82иÑ\82е воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f Ñ\80едакÑ\82оÑ\80ом. УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b наÑ\81Ñ\82Ñ\80оили его на иÑ\81полÑ\8cзование Ñ\82ой Ñ\81амой виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b, коÑ\82оÑ\80Ñ\83Ñ\8e вÑ\8b Ñ\81оздали. (СкоÑ\80ее вÑ\81его, она авÑ\82омаÑ\82иÑ\87еÑ\81ки бÑ\83деÑ\82 обнаÑ\80Ñ\83жена). ÐÑ\82о позволиÑ\82 вам иÑ\81полÑ\8cзоваÑ\82Ñ\8c авÑ\82о-завеÑ\80Ñ\88ение и вÑ\8bделение оÑ\88ибок в Ñ\80едакÑ\82оÑ\80е.
+СкоÑ\80ее вÑ\81его, вÑ\8b бÑ\83деÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c Ñ\80едакÑ\82оÑ\80 кода. УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о вÑ\8b наÑ\81Ñ\82Ñ\80оили его на иÑ\81полÑ\8cзование Ñ\82ого же виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f, коÑ\82оÑ\80ое вÑ\8b Ñ\81оздали (обÑ\8bÑ\87но он опÑ\80еделÑ\8fеÑ\82 его авÑ\82омаÑ\82иÑ\87еÑ\81ки), Ñ\87Ñ\82обÑ\8b полÑ\83Ñ\87иÑ\82Ñ\8c авÑ\82озавеÑ\80Ñ\88ение и подÑ\81веÑ\82кÑ\83 оÑ\88ибок.
Например:
/// tip | Подсказка
-Ð\9eбÑ\8bÑ\87но Ñ\8dÑ\82о делаеÑ\82Ñ\81Ñ\8f один Ñ\80аз, пÑ\80и Ñ\81оздании виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки.
+Ð\9eбÑ\8bÑ\87но Ñ\8dÑ\82о нÑ\83жно Ñ\81делаÑ\82Ñ\8c Ñ\82олÑ\8cко **один Ñ\80аз**, пÑ\80и Ñ\81оздании виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f.
///
-## Ð\94еакÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки
+## Ð\94еакÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f { #deactivate-the-virtual-environment }
-Ð\9fо оконÑ\87ании Ñ\80абоÑ\82Ñ\8b над пÑ\80оекÑ\82ом вÑ\8b можеÑ\82е деакÑ\82ивиÑ\80оваÑ\82Ñ\8c виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83.
+Ð\9aогда законÑ\87иÑ\82е Ñ\80абоÑ\82Ñ\83 над пÑ\80оекÑ\82ом, вÑ\8b можеÑ\82е **деакÑ\82ивиÑ\80оваÑ\82Ñ\8c** виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение.
<div class="termy">
</div>
-Таким образом, при запуске `python`, будет использована версия `python` установленная глобально, а не из этой виртуальной среды вместе с установленными в ней пакетами.
+Таким образом, при запуске `python` он не будет пытаться запускаться из этого виртуального окружения с установленными там пакетами.
-## Ð\92Ñ\81е гоÑ\82ово к Ñ\80абоÑ\82е
+## Ð\93оÑ\82ово к Ñ\80абоÑ\82е { #ready-to-work }
-ТепеÑ\80Ñ\8c вÑ\8b гоÑ\82овÑ\8b к Ñ\82омÑ\83, Ñ\87Ñ\82обÑ\8b наÑ\87аÑ\82Ñ\8c Ñ\80абоÑ\82Ñ\83 над своим проектом.
+ТепеÑ\80Ñ\8c вÑ\8b гоÑ\82овÑ\8b наÑ\87аÑ\82Ñ\8c Ñ\80абоÑ\82аÑ\82Ñ\8c над своим проектом.
/// tip | Подсказка
-Хотите разобраться со всем, что написано выше?
+Хотите понять, что это всё было выше?
Продолжайте читать. 👇🤓
///
-## Ð\97аÑ\87ем иÑ\81полÑ\8cзоваÑ\82Ñ\8c виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83?
+## Ð\97аÑ\87ем нÑ\83жнÑ\8b виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bе окÑ\80Ñ\83жениÑ\8f { #why-virtual-environments }
-Ð\94лÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 FastAPI вам поÑ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f установить <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>.
+ЧÑ\82обÑ\8b Ñ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 FastAPI, вам нÑ\83жно установить <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>.
-Ð\9fоÑ\81ле Ñ\8dÑ\82ого вам нÑ\83жно бÑ\83деÑ\82 **Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c** FastAPI и дÑ\80Ñ\83гие **пакеÑ\82Ñ\8b**, коÑ\82оÑ\80Ñ\8bе вÑ\8b Ñ\81обиÑ\80аеÑ\82еÑ\81Ñ\8c использовать.
+Ð\9fоÑ\81ле Ñ\8dÑ\82ого вам нÑ\83жно бÑ\83деÑ\82 **Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c** FastAPI и дÑ\80Ñ\83гие **пакеÑ\82Ñ\8b**, коÑ\82оÑ\80Ñ\8bе вÑ\8b Ñ\85оÑ\82иÑ\82е использовать.
-Для установки пакетов обычно используют `pip`, который устанавливается вместе с Python (или же используют альтернативные решения).
+Для установки пакетов обычно используют команду `pip`, которая идет вместе с Python (или альтернативные инструменты).
-Тем не менее, еÑ\81ли вÑ\8b пÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзÑ\83еÑ\82е `pip` напÑ\80Ñ\8fмÑ\83Ñ\8e, Ñ\82о пакеÑ\82Ñ\8b бÑ\83дÑ\83Ñ\82 Ñ\83Ñ\81Ñ\82ановленÑ\8b в **глобалÑ\8cное Python-окÑ\80Ñ\83жение** (глобально установленный Python).
+Тем не менее, еÑ\81ли пÑ\80оÑ\81Ñ\82о иÑ\81полÑ\8cзоваÑ\82Ñ\8c `pip` напÑ\80Ñ\8fмÑ\83Ñ\8e, пакеÑ\82Ñ\8b бÑ\83дÑ\83Ñ\82 Ñ\83Ñ\81Ñ\82ановленÑ\8b в **глобалÑ\8cное окÑ\80Ñ\83жение Python** (глобально установленный Python).
-### Проблема
+### Проблема { #the-problem }
-Так в чем же проблема с установкой пакетов в глобальную среду Python?
+Так в чём проблема установки пакетов в глобальное окружение Python?
-Ð\92 какой-Ñ\82о моменÑ\82 вам, веÑ\80оÑ\8fÑ\82но, пÑ\80идеÑ\82Ñ\81Ñ\8f пиÑ\81аÑ\82Ñ\8c множеÑ\81Ñ\82во Ñ\80азнÑ\8bÑ\85 пÑ\80огÑ\80амм, коÑ\82оÑ\80Ñ\8bе иÑ\81полÑ\8cзÑ\83Ñ\8eÑ\82 Ñ\80азлиÑ\87нÑ\8bе пакеÑ\82Ñ\8b. 😱
+Со вÑ\80еменем вÑ\8b, веÑ\80оÑ\8fÑ\82но, бÑ\83деÑ\82е пиÑ\81аÑ\82Ñ\8c много Ñ\80азнÑ\8bÑ\85 пÑ\80огÑ\80амм, завиÑ\81Ñ\8fÑ\89иÑ\85 оÑ\82 **Ñ\80азнÑ\8bÑ\85 пакеÑ\82ов**. Ð\98 некоÑ\82оÑ\80Ñ\8bе из ваÑ\88иÑ\85 пÑ\80оекÑ\82ов бÑ\83дÑ\83Ñ\82 завиÑ\81еÑ\82Ñ\8c оÑ\82 **Ñ\80азнÑ\8bÑ\85 веÑ\80Ñ\81ий** одного и Ñ\82ого же пакеÑ\82а. 😱
-Например, вы создаете проект `philosophers-stone`, который зависит от пакета под названием **`harry`, версии `1`**. Таким образом, вам нужно установить `harry`.
+Например, вы можете создать проект `philosophers-stone`, который зависит от пакета **`harry` версии `1`**. Значит, нужно установить `harry`.
```mermaid
flowchart LR
stone(philosophers-stone) -->|requires| harry-1[harry v1]
```
-Затем, в какой-то момент, вы создаете другой проект под названием `prisoner-of-azkaban`, и этот проект тоже зависит от `harry`, но он уже использует **`harry` версии `3`**.
+Затем вы создаёте другой проект `prisoner-of-azkaban`, который тоже зависит от `harry`, но ему нужен **`harry` версии `3`**.
```mermaid
flowchart LR
azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
```
-Ð\9fÑ\80облема заклÑ\8eÑ\87аеÑ\82Ñ\81Ñ\8f в Ñ\82ом, Ñ\87Ñ\82о пÑ\80и Ñ\83Ñ\81Ñ\82ановке в глобалÑ\8cное окÑ\80Ñ\83жение, а не в локалÑ\8cнÑ\83Ñ\8e виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83 Ñ\80азÑ\80абоÑ\82ки, вам нÑ\83жно бÑ\83деÑ\82 вÑ\8bбиÑ\80аÑ\82Ñ\8c, какÑ\83Ñ\8e веÑ\80Ñ\81иÑ\8e пакеÑ\82а `harry` Ñ\83Ñ\81Ñ\82анавливать.
+Ð\9fÑ\80облема в Ñ\82ом, Ñ\87Ñ\82о еÑ\81ли Ñ\83Ñ\81Ñ\82анавливаÑ\82Ñ\8c пакеÑ\82Ñ\8b глобалÑ\8cно (в глобалÑ\8cное окÑ\80Ñ\83жение), а не в локалÑ\8cное **виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение**, вам пÑ\80идÑ\91Ñ\82Ñ\81Ñ\8f вÑ\8bбиÑ\80аÑ\82Ñ\8c, какÑ\83Ñ\8e веÑ\80Ñ\81иÑ\8e `harry` Ñ\83Ñ\81Ñ\82ановить.
-Если вам нужен `philosophers-stone`, то вам нужно сначала установить `harry` версии `1`:
+Если вы хотите запустить `philosophers-stone`, сначала нужно установить `harry` версии `1`, например так:
<div class="termy">
</div>
-Ð\98 Ñ\82огда в ваÑ\88ем глобальном окружении Python будет установлен `harry` версии `1`:
+Тогда Ñ\83 ваÑ\81 в глобальном окружении Python будет установлен `harry` версии `1`:
```mermaid
flowchart LR
end
```
-Ð\9dо еÑ\81ли позднее вÑ\8b заÑ\85оÑ\82иÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c `prisoner-of-azkaban`, Ñ\82о вам нÑ\83жно бÑ\83деÑ\82 Ñ\83далиÑ\82Ñ\8c `harry` веÑ\80Ñ\81ии 1, и Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c `harry` веÑ\80Ñ\81ии `3` (пÑ\80и Ñ\83Ñ\81Ñ\82ановке пакеÑ\82а веÑ\80Ñ\81ии `3` повеÑ\80Ñ\85 пакеÑ\82а веÑ\80Ñ\81ии `1`, пакеÑ\82 веÑ\80Ñ\81ии `1` Ñ\83далÑ\8fеÑ\82Ñ\81Ñ\8f авÑ\82омаÑ\82иÑ\87еÑ\81ки).
+Ð\9dо еÑ\81ли заÑ\82ем вÑ\8b заÑ\85оÑ\82иÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c `prisoner-of-azkaban`, вам нÑ\83жно бÑ\83деÑ\82 Ñ\83далиÑ\82Ñ\8c `harry` веÑ\80Ñ\81ии `1` и Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c `harry` веÑ\80Ñ\81ии `3` (или пÑ\80оÑ\81Ñ\82о Ñ\83Ñ\81Ñ\82ановка веÑ\80Ñ\81ии `3` авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\83далиÑ\82 веÑ\80Ñ\81иÑ\8e `1`).
<div class="termy">
</div>
-Ð\98 Ñ\82огда, в ваÑ\88ей глобалÑ\8cной Ñ\81Ñ\80еде окÑ\80Ñ\83жениÑ\8f Python, бÑ\83деÑ\82 Ñ\83Ñ\81Ñ\82ановлен пакеÑ\82 `harry` веÑ\80Ñ\81ии `3`.
+Ð\92 иÑ\82оге Ñ\83 ваÑ\81 бÑ\83деÑ\82 Ñ\83Ñ\81Ñ\82ановлен `harry` веÑ\80Ñ\81ии `3` в глобалÑ\8cном окÑ\80Ñ\83жении Python.
-Ð\98 когда вÑ\8b Ñ\81нова попÑ\8bÑ\82аеÑ\82еÑ\81Ñ\8c запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c `philosophers-stone`, Ñ\82о Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 веÑ\80оÑ\8fÑ\82ноÑ\81Ñ\82Ñ\8c Ñ\82ого, Ñ\87Ñ\82о он не бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c, Ñ\82ак как он иÑ\81полÑ\8cзÑ\83еÑ\82 `harry` версии `1`.
+Ð\90 еÑ\81ли вÑ\8b Ñ\81нова попÑ\80обÑ\83еÑ\82е запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c `philosophers-stone`, еÑ\81Ñ\82Ñ\8c Ñ\88анÑ\81, Ñ\87Ñ\82о он **не бÑ\83деÑ\82 Ñ\80абоÑ\82аÑ\82Ñ\8c**, Ñ\82ак как емÑ\83 нÑ\83жен `harry` версии `1`.
```mermaid
flowchart LR
/// tip | Подсказка
-В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новые версии, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно.
+В Python-пакетах часто стараются изо всех сил **избегать ломающих изменений** в **новых версиях**, но лучше действовать осторожно: устанавливать новые версии осознанно и тогда, когда вы можете прогнать тесты и убедиться, что всё работает корректно.
///
-Теперь представьте, что это происходит со многими другими пакетами, которые используются в ваших проектах. С этим очень сложно справиться. И скорее всего, в конечном итоге вы будете запускать некоторые проекты с некоторыми несовместимыми зависимостями и не будете знать, почему что-то не работает.
+Теперь представьте то же самое с **многими** другими **пакетами**, от которых зависят все ваши **проекты**. Этим очень сложно управлять. И вы, скорее всего, в какой‑то момент будете запускать проекты с **несовместимыми версиями** пакетов и не понимать, почему что‑то не работает.
-Ð\9aÑ\80оме Ñ\82ого, в завиÑ\81имоÑ\81Ñ\82и оÑ\82 ваÑ\88ей опеÑ\80аÑ\86ионной Ñ\81иÑ\81Ñ\82емÑ\8b (напÑ\80. Linux, Windows, macOS), она можеÑ\82 поÑ\81Ñ\82авлÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81 Ñ\83же Ñ\83Ñ\81Ñ\82ановленнÑ\8bм Python. Ð\92еÑ\80оÑ\8fÑ\82но, Ñ\87Ñ\82о в Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае в ней Ñ\83же Ñ\83Ñ\81Ñ\82ановленÑ\8b Ñ\81иÑ\81Ñ\82емнÑ\8bе пакеÑ\82Ñ\8b опÑ\80еделеннÑ\8bÑ\85 веÑ\80Ñ\81ий. Ð\95Ñ\81ли вÑ\8b Ñ\83Ñ\81Ñ\82анавливаеÑ\82е пакеÑ\82Ñ\8b глобалÑ\8cно, Ñ\82о вÑ\8b можеÑ\82е **поломаÑ\82Ñ\8c** пÑ\80огÑ\80аммÑ\8b, Ñ\8fвлÑ\8fÑ\8eÑ\89иеÑ\81Ñ\8f Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e Ð\9eС.
+Ð\9aÑ\80оме Ñ\82ого, в завиÑ\81имоÑ\81Ñ\82и оÑ\82 Ð\9eС (напÑ\80имеÑ\80, Linux, Windows, macOS), она можеÑ\82 поÑ\81Ñ\82авлÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81 Ñ\83же Ñ\83Ñ\81Ñ\82ановленнÑ\8bм Python. Ð\98 Ñ\82огда, веÑ\80оÑ\8fÑ\82но, в Ñ\81иÑ\81Ñ\82еме Ñ\83же еÑ\81Ñ\82Ñ\8c пÑ\80едÑ\83Ñ\81Ñ\82ановленнÑ\8bе пакеÑ\82Ñ\8b опÑ\80еделÑ\91ннÑ\8bÑ\85 веÑ\80Ñ\81ий, **нÑ\83жнÑ\8bе ваÑ\88ей Ñ\81иÑ\81Ñ\82еме**. Ð\95Ñ\81ли вÑ\8b Ñ\83Ñ\81Ñ\82анавливаеÑ\82е пакеÑ\82Ñ\8b в глобалÑ\8cное окÑ\80Ñ\83жение Python, вÑ\8b можеÑ\82е в иÑ\82оге **Ñ\81ломаÑ\82Ñ\8c** некоÑ\82оÑ\80Ñ\8bе Ñ\81иÑ\81Ñ\82емнÑ\8bе пÑ\80огÑ\80аммÑ\8b.
-## Куда устанавливаются пакеты?
+## Куда устанавливаются пакеты { #where-are-packages-installed }
-Когда вы устанавливаете Python, то на вашей машине создается некоторое количество директорий, содержащих некоторое количество файлов.
+Когда вы устанавливаете Python, на вашем компьютере создаются некоторые директории с файлами.
-СÑ\80еди ниÑ\85 еÑ\81Ñ\82Ñ\8c каÑ\82алоги, оÑ\82веÑ\87аÑ\8eÑ\89ие за хранение всех устанавливаемых вами пакетов.
+ЧаÑ\81Ñ\82Ñ\8c Ñ\8dÑ\82иÑ\85 диÑ\80екÑ\82оÑ\80ий оÑ\82веÑ\87аеÑ\82 за хранение всех устанавливаемых вами пакетов.
-Когда вы запустите команду:
+Когда вы запускаете:
<div class="termy">
```console
-// Не запускайте эту команду, это просто пример 🤓
+// Не запускайте это сейчас, это просто пример 🤓
$ pip install "fastapi[standard]"
---> 100%
```
</div>
-То бÑ\83деÑ\82 Ñ\81каÑ\87ан Ñ\81жаÑ\82Ñ\8bй Ñ\84айл, Ñ\81одеÑ\80жаÑ\89ий код FastAPI, обÑ\8bÑ\87но Ñ\81каÑ\87ивание пÑ\80оиÑ\81Ñ\85одиÑ\82 с <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>.
+Ð\91Ñ\83деÑ\82 загÑ\80Ñ\83жен Ñ\81жаÑ\82Ñ\8bй Ñ\84айл Ñ\81 кодом FastAPI, обÑ\8bÑ\87но с <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>.
-Также будут скачаны файлы, содержащие пакеты, которые использует FastAPI.
+Также будут **загружены** файлы для других пакетов, от которых зависит FastAPI.
-Ð\97аÑ\82ем вÑ\81е Ñ\84айлÑ\8b бÑ\83дÑ\83Ñ\82 извлеÑ\87енÑ\8b и помещены в директорию на вашем компьютере.
+Ð\97аÑ\82ем вÑ\81е Ñ\8dÑ\82и Ñ\84айлÑ\8b бÑ\83дÑ\83Ñ\82 **Ñ\80аÑ\81пакованÑ\8b** и помещены в директорию на вашем компьютере.
-По умолчанию эти файлы будут загружены и извлечены в один из каталогов установки Python, т.е. в глобальную среду.
+По умолчанию они попадут в директорию из вашей установки Python — это **глобальное окружение**.
-## Что такое виртуальная среда разработки?
+## Что такое виртуальные окружения { #what-are-virtual-environments }
-Решением проблемы размещения всех пакетов в глобальной среде будет использование отдельной виртуальной среды под каждый проект, над которым вы работаете.
+Решение проблемы с пакетами в глобальном окружении — использовать **виртуальное окружение для каждого проекта**, над которым вы работаете.
-Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cнаÑ\8f Ñ\81Ñ\80еда Ñ\8dÑ\82о обÑ\8bÑ\87наÑ\8f папка, оÑ\87енÑ\8c поÑ\85ожаÑ\8f на глобалÑ\8cнÑ\83Ñ\8e, кÑ\83да вÑ\8b можеÑ\82е Ñ\83Ñ\81Ñ\82анавливаÑ\82Ñ\8c пакеÑ\82Ñ\8b длÑ\8f ваÑ\88его проекта.
+Ð\92иÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение â\80\94 Ñ\8dÑ\82о **диÑ\80екÑ\82оÑ\80иÑ\8f**, оÑ\87енÑ\8c поÑ\85ожаÑ\8f на глобалÑ\8cнÑ\83Ñ\8e, кÑ\83да вÑ\8b можеÑ\82е Ñ\83Ñ\81Ñ\82анавливаÑ\82Ñ\8c пакеÑ\82Ñ\8b длÑ\8f конкÑ\80еÑ\82ного проекта.
-Таким образом, каждый проект будет иметь свою отдельную виртуальную среду разработки (в директории `.venv`) вместе со своими пакетами.
+Таким образом, у каждого проекта будет своё виртуальное окружение (директория `.venv`) со своими пакетами.
```mermaid
flowchart TB
stone-project ~~~ azkaban-project
```
-## ЧÑ\82о ознаÑ\87аеÑ\82 акÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b?
+## ЧÑ\82о ознаÑ\87аеÑ\82 акÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f { #what-does-activating-a-virtual-environment-mean }
-Когда вы активируете виртуальную среду разработки, например, так:
+Когда вы активируете виртуальное окружение, например так:
//// tab | Linux, macOS
//// tab | Windows Bash
-Ð\98ли еÑ\81ли вÑ\8b воÑ\81полÑ\8cзÑ\83еÑ\82еÑ\81Ñ\8c Bash под Windows (напÑ\80. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
+Ð\98ли еÑ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Bash длÑ\8f Windows (напÑ\80имеÑ\80, <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
////
+Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для следующих команд.
-Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд.
-
-Одной из таких переменных является `PATH`.
+Одна из таких переменных — `PATH`.
/// tip | Подсказка
///
-Ð\9fÑ\80и акÑ\82иваÑ\86ии виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b пÑ\83Ñ\82Ñ\8c `.venv/bin` (длÑ\8f Linux и macOS) или `.venv\Scripts` (длÑ\8f Windows) добавлÑ\8fеÑ\82Ñ\81Ñ\8f в переменную окружения `PATH`.
+Ð\90кÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f добавлÑ\8fеÑ\82 его пÑ\83Ñ\82Ñ\8c `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) в переменную окружения `PATH`.
-Ð\9fÑ\80едположим, Ñ\87Ñ\82о до акÑ\82иваÑ\86ии виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b переменная `PATH` выглядела так:
+Ð\9fÑ\80едположим, Ñ\87Ñ\82о до акÑ\82иваÑ\86ии окÑ\80Ñ\83жениÑ\8f переменная `PATH` выглядела так:
//// tab | Linux, macOS
/usr/bin:/bin:/usr/sbin:/sbin
```
-ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\81иÑ\81Ñ\82ема иÑ\89еÑ\82 пÑ\80огÑ\80аммÑ\8b в Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 каÑ\82алогаÑ\85:
+ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\81иÑ\81Ñ\82ема бÑ\83деÑ\82 иÑ\81каÑ\82Ñ\8c пÑ\80огÑ\80аммÑ\8b в:
* `/usr/bin`
* `/bin`
C:\Windows\System32
```
-ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\81иÑ\81Ñ\82ема иÑ\89еÑ\82 программы в:
+ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\81иÑ\81Ñ\82ема бÑ\83деÑ\82 иÑ\81каÑ\82Ñ\8c программы в:
* `C:\Windows\System32`
////
-Ð\9fоÑ\81ле акÑ\82иваÑ\86ии виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b пеÑ\80еменнаÑ\8f окÑ\80Ñ\83жение `PATH` будет выглядеть примерно так:
+Ð\9fоÑ\81ле акÑ\82иваÑ\86ии виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f пеÑ\80еменнаÑ\8f `PATH` будет выглядеть примерно так:
//// tab | Linux, macOS
/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
-ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\81иÑ\81Ñ\82ема Ñ\82епеÑ\80ь будет искать программы в:
+ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\82епеÑ\80Ñ\8c Ñ\81иÑ\81Ñ\82ема в пеÑ\80вÑ\83Ñ\8e оÑ\87еÑ\80едь будет искать программы в:
```plaintext
/home/user/code/awesome-project/.venv/bin
```
-пÑ\80ежде Ñ\87ем наÑ\87аÑ\82Ñ\8c иÑ\81каÑ\82Ñ\8c в дÑ\80Ñ\83гиÑ\85 каÑ\82алогах.
+пÑ\80ежде Ñ\87ем иÑ\81каÑ\82Ñ\8c в дÑ\80Ñ\83гиÑ\85 диÑ\80екÑ\82оÑ\80иÑ\8fх.
-Таким обÑ\80азом, когда вÑ\8b введеÑ\82е в конÑ\81олÑ\8c `python`, Ñ\81иÑ\81Ñ\82ема бÑ\83деÑ\82 иÑ\81каÑ\82Ñ\8c Python в
+Ð\9fоÑ\8dÑ\82омÑ\83, когда вÑ\8b введÑ\91Ñ\82е в Ñ\82еÑ\80минале `python`, Ñ\81иÑ\81Ñ\82ема найдÑ\91Ñ\82 пÑ\80огÑ\80аммÑ\83 Python по пÑ\83Ñ\82и
```plaintext
/home/user/code/awesome-project/.venv/bin/python
```
-и бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8c именно его.
+и иÑ\81полÑ\8cзÑ\83еÑ\82 именно еÑ\91.
////
C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
```
-ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\81иÑ\81Ñ\82ема в пеÑ\80вÑ\83Ñ\8e оÑ\87еÑ\80едÑ\8c наÑ\87нет искать программы в:
+ÐÑ\82о ознаÑ\87аеÑ\82, Ñ\87Ñ\82о Ñ\82епеÑ\80Ñ\8c Ñ\81иÑ\81Ñ\82ема в пеÑ\80вÑ\83Ñ\8e оÑ\87еÑ\80едÑ\8c бÑ\83дет искать программы в:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts
```
-пÑ\80ежде Ñ\87ем наÑ\87аÑ\82Ñ\8c иÑ\81каÑ\82Ñ\8c в дÑ\80Ñ\83гиÑ\85 диÑ\80екÑ\82оÑ\80иÑ\8fÑ\85.
+прежде чем искать в других директориях.
-Таким обÑ\80азом, еÑ\81ли вÑ\8b введеÑ\82е в конÑ\81олÑ\8c командÑ\83 `python`, Ñ\82о Ñ\81иÑ\81Ñ\82ема найдеÑ\82 Python в:
+Ð\9fоÑ\8dÑ\82омÑ\83, когда вÑ\8b введÑ\91Ñ\82е в Ñ\82еÑ\80минале `python`, Ñ\81иÑ\81Ñ\82ема найдÑ\91Ñ\82 пÑ\80огÑ\80аммÑ\83 Python по пÑ\83Ñ\82и
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
-и иÑ\81полÑ\8cзÑ\83еÑ\82 его.
+и иÑ\81полÑ\8cзÑ\83еÑ\82 именно еÑ\91.
////
-Ð\9eÑ\87енÑ\8c важной деÑ\82алÑ\8cÑ\8e Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\82о, Ñ\87Ñ\82о пÑ\83Ñ\82Ñ\8c к виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80еде бÑ\83деÑ\82 помеÑ\89ен в Ñ\81амое наÑ\87ало пеÑ\80еменной `PATH`. СиÑ\81Ñ\82ема обнаÑ\80Ñ\83жиÑ\82 даннÑ\8bй пÑ\83Ñ\82Ñ\8c к Python Ñ\80анÑ\8cÑ\88е, Ñ\87ем какой-либо дÑ\80Ñ\83гой. Таким обÑ\80азом, пÑ\80и запÑ\83Ñ\81ке командÑ\8b `python`, бÑ\83деÑ\82 иÑ\81полÑ\8cзован именно Python из виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки, а не какой-нибÑ\83дÑ\8c дÑ\80Ñ\83гой (напÑ\80имеÑ\80, Python из глобалÑ\8cной Ñ\81Ñ\80едÑ\8b)
+Ð\92ажнаÑ\8f деÑ\82алÑ\8c: пÑ\83Ñ\82Ñ\8c к виÑ\80Ñ\82Ñ\83алÑ\8cномÑ\83 окÑ\80Ñ\83жениÑ\8e бÑ\83деÑ\82 добавлен в Ñ\81амое **наÑ\87ало** пеÑ\80еменной `PATH`. СиÑ\81Ñ\82ема найдÑ\91Ñ\82 его **Ñ\80анÑ\8cÑ\88е**, Ñ\87ем лÑ\8eбой дÑ\80Ñ\83гой Ñ\83Ñ\81Ñ\82ановленнÑ\8bй Python. Таким обÑ\80азом, пÑ\80и запÑ\83Ñ\81ке `python` бÑ\83деÑ\82 иÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f Python **из виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f**, а не какойâ\80\91Ñ\82о дÑ\80Ñ\83гой `python` (напÑ\80имеÑ\80, из глобалÑ\8cного окÑ\80Ñ\83жениÑ\8f).
-Ð\90кÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b Ñ\80азÑ\80абоÑ\82ки Ñ\82акже менÑ\8fеÑ\82 и неÑ\81колÑ\8cко дÑ\80Ñ\83гиÑ\85 веÑ\89ей, но даннаÑ\8f Ñ\84Ñ\83нкÑ\86иÑ\8f Ñ\8fвлÑ\8fеÑ\82Ñ\81Ñ\8f оÑ\81новной.
+Ð\90кÑ\82иваÑ\86иÑ\8f виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f Ñ\82акже менÑ\8fеÑ\82 еÑ\89Ñ\91 неÑ\81колÑ\8cко веÑ\89ей, но Ñ\8dÑ\82о â\80\94 одна из важнейÑ\88иÑ\85.
-## Ð\9fÑ\80овеÑ\80ка виÑ\80Ñ\82Ñ\83алÑ\8cной Ñ\81Ñ\80едÑ\8b
+## Ð\9fÑ\80овеÑ\80ка виÑ\80Ñ\82Ñ\83алÑ\8cного окÑ\80Ñ\83жениÑ\8f { #checking-a-virtual-environment }
-Когда вы проверяете активна ли виртуальная среда разработки, например, так:
+Когда вы проверяете, активно ли виртуальное окружение, например, так:
//// tab | Linux, macOS, Windows Bash
////
-Это означает, что будет использоваться `python` **из виртуальной среды разработки**.
+Это означает, что будет использоваться программа `python` **из виртуального окружения**.
-Ð\92Ñ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е `which` длÑ\8f Linux и macOS и `Get-Command` длÑ\8f Windows PowerShell.
+Ð\9dа Linux и macOS иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f `which`, а в Windows PowerShell â\80\94 `Get-Command`.
-ÐÑ\82а команда Ñ\80абоÑ\82аеÑ\82 Ñ\81ледÑ\83Ñ\8eÑ\89им обÑ\80азом: она пÑ\80овеÑ\80Ñ\8fеÑ\82 пеÑ\80еменнÑ\83Ñ\8e окÑ\80Ñ\83жениÑ\8f `PATH`, пÑ\80оÑ\85одÑ\8f по оÑ\87еÑ\80еди каждÑ\8bй Ñ\83казаннÑ\8bй пÑ\83Ñ\82Ñ\8c в поиÑ\81каÑ\85 пÑ\80огÑ\80аммÑ\8b под названием `python`. Ð\98 когда она еÑ\91 наÑ\85одиÑ\82, Ñ\82о возвÑ\80аÑ\89аеÑ\82 пÑ\83Ñ\82Ñ\8c к данной программе.
+Ð\9aак Ñ\80абоÑ\82аеÑ\82 Ñ\8dÑ\82а команда: она пÑ\80оÑ\85одиÑ\82 по пеÑ\80еменной окÑ\80Ñ\83жениÑ\8f `PATH`, идÑ\8f **по каждомÑ\83 пÑ\83Ñ\82и по поÑ\80Ñ\8fдкÑ\83**, и иÑ\89еÑ\82 пÑ\80огÑ\80аммÑ\83 Ñ\81 именем `python`. Ð\9aак Ñ\82олÑ\8cко наÑ\85одиÑ\82 â\80\94 **показÑ\8bваеÑ\82 пÑ\83Ñ\82Ñ\8c** к Ñ\8dÑ\82ой программе.
-Ð\9eÑ\81новной моменÑ\82 пÑ\80и вÑ\8bзове командÑ\8b `python` Ñ\81оÑ\81Ñ\82оиÑ\82 в Ñ\82ом, какой именно "`python`" бÑ\83деÑ\82 запÑ\83Ñ\89ен.
+Самое важное â\80\94 пÑ\80и вÑ\8bзове `python` именно Ñ\8dÑ\82оÑ\82 «`python`» и бÑ\83деÑ\82 вÑ\8bполнÑ\8fÑ\82Ñ\8cÑ\81Ñ\8f.
-Таким образом, вы можете убедиться, что используете правильную виртуальную среду разработки.
+Так вы можете подтвердить, что находитесь в правильном виртуальном окружении.
/// tip | Подсказка
-Легко активировать одну виртуальную среду, вызвать один Python и **перейти к следующему проекту**.
+Легко активировать одно виртуальное окружение, получить один Python, а затем **перейти к другому проекту**.
-И следующий проект не будет работать потому, что вы используете **неправильный Python** из виртуальной среды другого проекта.
+И второй проект **не будет работать**, потому что вы используете **не тот Python**, из виртуального окружения другого проекта.
-Так Ñ\87Ñ\82о, бÑ\83деÑ\82 нелиÑ\88ним пÑ\80овеÑ\80иÑ\82Ñ\8c, какой `python` вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е. 🤓
+Ð\9fолезно Ñ\83меÑ\82Ñ\8c пÑ\80овеÑ\80иÑ\82Ñ\8c, какой именно `python` иÑ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f. 🤓
///
-## Зачем деактивируют виртуальную среду?
+## Зачем деактивировать виртуальное окружение { #why-deactivate-a-virtual-environment }
-Ð\9fÑ\80едположим, Ñ\87Ñ\82о вÑ\8b Ñ\80абоÑ\82аеÑ\82е над пÑ\80оекÑ\82ом `philosophers-stone`, **акÑ\82ивиÑ\80Ñ\83еÑ\82е виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e Ñ\81Ñ\80едÑ\83 Ñ\80азÑ\80абоÑ\82ки**, Ñ\83Ñ\81Ñ\82анавливаеÑ\82е пакеÑ\82Ñ\8b и Ñ\80абоÑ\82аеÑ\82е Ñ\81 данной Ñ\81Ñ\80едой.
+Ð\9dапÑ\80имеÑ\80, вÑ\8b Ñ\80абоÑ\82аеÑ\82е над пÑ\80оекÑ\82ом `philosophers-stone`, **акÑ\82ивиÑ\80Ñ\83еÑ\82е виÑ\80Ñ\82Ñ\83алÑ\8cное окÑ\80Ñ\83жение**, Ñ\83Ñ\81Ñ\82анавливаеÑ\82е пакеÑ\82Ñ\8b и Ñ\80абоÑ\82аеÑ\82е Ñ\81 ним.
-Ð\98 позже вам понадобилоÑ\81Ñ\8c поÑ\80абоÑ\82аÑ\82Ñ\8c Ñ\81 **другим проектом** `prisoner-of-azkaban`.
+Ð\97аÑ\82ем вÑ\8b Ñ\85оÑ\82иÑ\82е поÑ\80абоÑ\82аÑ\82Ñ\8c над **другим проектом** `prisoner-of-azkaban`.
-Ð\92Ñ\8b пеÑ\80еÑ\85одиÑ\82е к Ñ\8dÑ\82омÑ\83 пÑ\80оекÑ\82Ñ\83:
+Ð\92Ñ\8b пеÑ\80еÑ\85одиÑ\82е в Ñ\8dÑ\82оÑ\82 пÑ\80оекÑ\82:
<div class="termy">
</div>
-Если вы не деактивировали виртуальное окружение проекта `philosophers-stone`, то при запуске `python` через консоль будет вызван Python из `philosophers-stone`
+Если вы не деактивируете виртуальное окружение `philosophers-stone`, при запуске `python` в терминале он попытается использовать Python из `philosophers-stone`.
<div class="termy">
</div>
-Но если вы деактивируете виртуальную среду разработки и активируете новую среду для `prisoner-of-askaban`, то вы тогда запустите Python из виртуального окружения `prisoner-of-azkaban`.
+Но если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, тогда при запуске `python` он будет использовать Python из виртуального окружения `prisoner-of-azkaban`.
<div class="termy">
```console
$ cd ~/code/prisoner-of-azkaban
-// Вам не требуется находится в старой директории для деактивации среды разработки, вы можете это сделать откуда угодно, даже из каталога другого проекта, в который вы перешли. 😎
+// Вам не нужно находиться в старой директории, чтобы деактивировать окружение, вы можете сделать это где угодно, даже после перехода в другой проект 😎
$ deactivate
-// Активируйте виртуальную среду разработки в prisoner-of-azkaban/.venv 🚀
+// Активируйте виртуальное окружение в prisoner-of-azkaban/.venv 🚀
$ source .venv/bin/activate
-// Тепреь, когда вы запустите python, он найдет пакет sirius, установленный в виртуальной среде ✨
+// Теперь при запуске python он найдёт пакет sirius, установленный в этом виртуальном окружении ✨
$ python main.py
-Я торжественно клянусь в этом! 🐺
+I solemnly swear 🐺
```
</div>
-## Альтернативы
+## Альтернативы { #alternatives }
-Это простое руководство поможет вам начать работу и научит тому, как всё работает **изнутри**.
+Это простое руководство, чтобы вы начали и поняли, как всё работает **под капотом**.
-Существует много альтернативных решений для работы с виртуальными средами разработки, с программными зависимостями, а также с проектами.
+Существует много **альтернатив** для управления виртуальными окружениями, зависимостями (requirements), проектами.
-Когда вы будете готовы использовать единый инструмент для управления проектом, программными зависимостями, виртуальными средами разработки и т.д., то я рекомендую вам попробовать <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
+Когда вы будете готовы и захотите использовать инструмент для **управления всем проектом** — зависимостями пакетов, виртуальными окружениями и т. п., я бы предложил попробовать <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
-`uv` можеÑ\82 оÑ\87енÑ\8c многое. Ð\9eн Ñ\83мееÑ\82:
+`uv` можеÑ\82 многое:
-* **УÑ\81Ñ\82анавливаÑ\82Ñ\8c Python**, вклÑ\8eÑ\87аÑ\8f Ñ\83Ñ\81Ñ\82ановкÑ\83 Ñ\80азлиÑ\87нÑ\8bÑ\85 веÑ\80Ñ\81ий
-* Управлять средой виртуального окружения вашего проекта
+* **УÑ\81Ñ\82анавливаÑ\82Ñ\8c Python**, вклÑ\8eÑ\87аÑ\8f Ñ\80азнÑ\8bе веÑ\80Ñ\81ии
+* Управлять **виртуальным окружением** ваших проектов
* Устанавливать **пакеты**
-* Управлять пакетами и их версиями внутри вашего проекта
-* УдоÑ\81Ñ\82овеÑ\80иÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е **Ñ\82оÑ\87нÑ\8bй** набоÑ\80 пакеÑ\82ов и веÑ\80Ñ\81ий пÑ\80и Ñ\83Ñ\81Ñ\82ановке, вклÑ\8eÑ\87аÑ\8f завиÑ\81имоÑ\81Ñ\82и. Таким обÑ\80азом, вÑ\8b можеÑ\82е бÑ\8bÑ\82Ñ\8c Ñ\83веÑ\80еннÑ\8b, Ñ\87Ñ\82о пÑ\80оекÑ\82, запÑ\83Ñ\81каеÑ\82Ñ\81Ñ\8f в production, Ñ\82оÑ\87но Ñ\82акже, как и пÑ\80и Ñ\80азÑ\80абоÑ\82ке, Ñ\8dÑ\82оÑ\82 меÑ\85анизм назÑ\8bваеÑ\82Ñ\81Ñ\8f *locking*
-* Ð\9cногие дÑ\80Ñ\83гие веÑ\89и
+* Управлять **зависимостями и версиями** пакетов вашего проекта
+* Ð\9eбеÑ\81пеÑ\87иваÑ\82Ñ\8c налиÑ\87ие **Ñ\82оÑ\87ного** набоÑ\80а пакеÑ\82ов и веÑ\80Ñ\81ий к Ñ\83Ñ\81Ñ\82ановке, вклÑ\8eÑ\87аÑ\8f иÑ\85 завиÑ\81имоÑ\81Ñ\82и, Ñ\87Ñ\82обÑ\8b вÑ\8b бÑ\8bли Ñ\83веÑ\80енÑ\8b, Ñ\87Ñ\82о Ñ\81можеÑ\82е запÑ\83Ñ\81каÑ\82Ñ\8c пÑ\80оекÑ\82 в пÑ\80одакÑ\88не Ñ\82оÑ\87но Ñ\82ак же, как и на компÑ\8cÑ\8eÑ\82еÑ\80е пÑ\80и Ñ\80азÑ\80абоÑ\82ке â\80\94 Ñ\8dÑ\82о назÑ\8bваеÑ\82Ñ\81Ñ\8f **locking**
+* Ð\98 многое дÑ\80Ñ\83гое
-## Заключение
+## Заключение { #conclusion }
-Ð\95Ñ\81ли вÑ\8b пÑ\80оÑ\87иÑ\82али и понÑ\8fли вÑ\81Ñ\91 Ñ\8dÑ\82о, Ñ\82о Ñ\82епеÑ\80Ñ\8c вÑ\8b знаеÑ\82е **гоÑ\80аздо болÑ\8cÑ\88е** о виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bÑ\85 Ñ\81Ñ\80едаÑ\85 Ñ\80азÑ\80абоÑ\82ки, Ñ\87ем многие дÑ\80Ñ\83гие разработчики. 🤓
+Ð\95Ñ\81ли вÑ\8b пÑ\80оÑ\87иÑ\82али и понÑ\8fли вÑ\81Ñ\91 Ñ\8dÑ\82о, Ñ\82епеÑ\80Ñ\8c **вÑ\8b знаеÑ\82е гоÑ\80аздо болÑ\8cÑ\88е** о виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8fÑ\85, Ñ\87ем многие разработчики. 🤓
-СкоÑ\80ее вÑ\81его, знание Ñ\8dÑ\82иÑ\85 деÑ\82алей бÑ\83деÑ\82 полезно вам в бÑ\83дÑ\83Ñ\89ем. Ð\9aогда вÑ\8b бÑ\83деÑ\82е оÑ\82лаживаÑ\82Ñ\8c Ñ\87Ñ\82о-Ñ\82о, кажÑ\83Ñ\89ееÑ\81Ñ\8f Ñ\81ложнÑ\8bм, вÑ\8b бÑ\83деÑ\82е знаÑ\82Ñ\8c, **как Ñ\8dÑ\82о работает под капотом**. 😎
+Ð\97нание Ñ\8dÑ\82иÑ\85 деÑ\82алей, Ñ\81коÑ\80ее вÑ\81его, пÑ\80игодиÑ\82Ñ\81Ñ\8f вам в бÑ\83дÑ\83Ñ\89ем, когда вÑ\8b бÑ\83деÑ\82е оÑ\82лаживаÑ\82Ñ\8c Ñ\87Ñ\82оâ\80\91Ñ\82о Ñ\81ложное: вÑ\8b бÑ\83деÑ\82е понимаÑ\82Ñ\8c, **как вÑ\81Ñ\91 работает под капотом**. 😎