Browse Source

Merge 6dfbce1de3 into 6df50d40fe

pull/13935/merge
Sebastián Ramírez 4 days ago
committed by GitHub
parent
commit
58f783c6ea
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 437
      docs/ru/docs/async.md
  2. 43
      docs/ru/docs/benchmarks.md
  3. 176
      docs/ru/docs/deployment/manually.md
  4. 221
      docs/ru/docs/help-fastapi.md
  5. 103
      docs/ru/docs/index.md
  6. 112
      docs/ru/docs/project-generation.md
  7. 28
      docs/ru/docs/tutorial/body-multiple-params.md
  8. 15
      docs/ru/docs/tutorial/cors.md
  9. 97
      docs/ru/docs/tutorial/extra-models.md
  10. 88
      docs/ru/docs/tutorial/first-steps.md
  11. 6
      docs/ru/docs/tutorial/handling-errors.md
  12. 64
      docs/ru/docs/tutorial/index.md
  13. 47
      docs/ru/docs/tutorial/middleware.md
  14. 354
      docs/ru/docs/tutorial/query-params-str-validations.md
  15. 12
      docs/ru/docs/tutorial/response-status-code.md
  16. 289
      docs/ru/docs/virtual-environments.md

437
docs/ru/docs/async.md

@ -1,18 +1,18 @@
# Конкурентность и async / await
Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций обработки пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма.
Подробная информация о синтаксисе `async def` для *функций-обработчиков пути*, а также некоторые сведения об асинхронном программировании, конкурентности и параллелизме.
## Нет времени?<a name="in-a-hurry"></a>
<abbr title="too long; didn't read (основная мысль)"><strong>TL;DR:</strong></abbr>
<abbr title="слишком длинно; не читал"><strong>TL;DR:</strong></abbr>
Допустим, вы используете сторонюю библиотеку, которая требует вызова с ключевым словом `await`:
Если вы используете сторонние библиотеки, которые требуют вызова с `await`, например:
```Python
results = await some_library()
```
В этом случае *функции обработки пути* необходимо объявлять с использованием синтаксиса `async def`:
Тогда объявите ваши *функции-обработчики пути* с `async def`, как:
```Python hl_lines="2"
@app.get('/')
@ -21,18 +21,15 @@ async def read_results():
return results
```
/// note
/// note | Примечание
`await` можно использовать только внутри функций, объявленных с использованием `async def`.
`await` можно использовать только внутри функций, созданных с использованием `async def`.
///
---
Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует
(с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await`
(что относится сейчас к большинству библиотек для работы с базами данных), то
объявляйте *функции обработки пути* обычным образом с помощью `def`, например:
Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т. д.) и не поддерживает использование `await`, (это в настоящее время относится к большинству библиотек для работы с базами данных), тогда объявляйте ваши *функции-обработчики пути* обычным образом, с `def`, например:
```Python hl_lines="2"
@app.get('/')
@ -43,27 +40,25 @@ def results():
---
Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно,
ожидать ответа, используйте `async def`.
Если вашему приложению (каким-то образом) не нужно ни с чем взаимодействовать и ждать ответа, используйте `async def`, даже если внутри не нужно использовать `await`.
---
Если вы не уверены, используйте обычный синтаксис `def`.
Если вы просто не знаете, используйте обычный `def`.
---
**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях обработки пути*
и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно.
**Примечание**: Вы можете смешивать `def` и `async def` в ваших *функциях-обработчиках пути* так, как вам нужно, и определять каждую с использованием наилучшего варианта для вас. FastAPI сделает с ними всё, что нужно.
В любом из описанных случаев FastAPI работает асинхронно и очень быстро.
В любом случае, в любой из описанных выше ситуаций, FastAPI всё равно будет работать асинхронно и будет чрезвычайно быстро.
Однако придерживаясь указанных советов, можно получить дополнительную оптимизацию производительности.
Но, следуя указанным шагам, можно будет достичь некоторой оптимизации производительности.
## Технические подробности
Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**.
Современные версии Python поддерживают **"асинхронный код"**, используя что-то под названием **"сопрограммы"**, со **синтаксисом `async` и `await`**.
Ниже разберём эту фразу по частям:
Давайте разберём эту фразу по частям в следующих разделах:
* **Асинхронный код**
* **`async` и `await`**
@ -71,278 +66,253 @@ def results():
## Асинхронный код
Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖,
что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝.
Асинхронный код просто означает, что в языке 💬 есть способ указать компьютеру / программе 🤖, что в определённый момент кода, он 🤖 должен будет дождаться, пока *что-то ещё* завершится где-то ещё. Допустим, это *что-то ещё* называется "медленный файл" 📝.
И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач.
Итак, в это время компьютер может заниматься чем-то другим, пока "медленный файл" 📝 завершает работу.
Но при каждой возможности компьютер / программа 🤖 будет возвращаться обратно. Например, если он 🤖 опять окажется в режиме ожидания, или когда закончит всю работу. В этом случае компьютер 🤖 проверяет, не завершена ли какая-нибудь из текущих задач.
Затем компьютер / программа 🤖 возвращается каждый раз, когда у него появляется возможность, потому что он снова что-то ожидает, или вся выполняемая работа на данный момент завершена. Он 🤖 проверяет, не завершена ли какая-нибудь из ожидаемых задач, и выполняет необходимые действия.
Потом он 🤖 берёт первую выполненную задачу (допустим, наш "медленный файл" 📝) и продолжает работу, производя с ней необходимые действия.
Далее 🤖 берёт первую завершённую задачу (допустим наш "медленный файл" 📝) и продолжает действия, которые он должен был выполнить с ней.
Вышеупомянутое "что-то ещё", завершения которого приходится ожидать, обычно относится к достаточно "медленным" операциям <abbr title="Ввода-вывода">I/O</abbr> (по сравнению со скоростью работы процессора и оперативной памяти), например:
То "ожидание чего-то ещё", как правило, относится к операциям <abbr title="Ввод и вывод">I/O</abbr>, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например:
* отправка данных от клиента по сети
* получение клиентом данных, отправленных вашей программой по сети
* чтение системой содержимого файла с диска и передача этих данных программе
* запись на диск данных, которые программа передала системе
* обращение к удалённому API
* ожидание завершения операции с базой данных
* получение результатов запроса к базе данных
* данные от клиента по сети
* данные, отправленные вашей программой клиенту через сеть
* содержимое файла на диске передано системе и дано вашей программе
* содержимое вашей программы передано системе для записи на диск
* удалённая операция API
* операция с базой данных завершается
* выполнение запроса к базе данных возвращает результаты
* и т. д.
Поскольку в основном время тратится на ожидание выполнения операций <abbr title="Ввода-вывода">I/O</abbr>,
их обычно называют операциями, <abbr title="I/O bound">ограниченными скоростью ввода-вывода</abbr>.
Поскольку в основном время выполнения тратится на ожидание операций <abbr title="Ввод и вывод">I/O</abbr>, это называют "операциями, ограниченными скоростью ввода-вывода".
Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и,
будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу.
Они называются "асинхронными", поскольку компьютеру / программе не нужно быть "синхронизированными" с медленной задачей и сидеть в ожидании момента её завершения, чтобы забрать результаты и продолжить работу.
Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд),
пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться,
забрать результаты выполнения и начать их обрабатывать.
Вместо этого, в "асинхронной" системе задача, оказавшись завершённой, может немного подождать в очереди (некоторые микросекунды), пока компьютер / программа завершит то, что выполнял, и затем вернуться, чтобы забрать результаты и продолжить работу с ними.
"Синхронное" исполнение (в противовес "асинхронному") также называют <abbr title="sequential">"последовательным"</abbr>,
потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче,
даже если в процессе приходится ждать.
Для "синхронного" (в противоположность "асинхронному") они часто также используют термин "последовательный", потому что компьютер / программа следует всем шагам в последовательности, прежде чем переключиться на другую задачу, даже если эти шаги включают ожидание.
### Конкурентность и бургеры
Тот **асинхронный** код, о котором идёт речь выше, иногда называют **"конкурентностью"**. Она отличается от **"параллелизма"**.
Эта концепция **асинхронного** кода, описанного выше, также иногда называется **"конкурентностью"**. Она отличается от **"параллелизма"**.
Да, **конкурентность** и **параллелизм** подразумевают, что разные вещи происходят примерно в одно время.
**Конкурентность** и **параллелизм** оба связаны с "разными вещами, происходящими более-менее одновременно".
Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное.
Но детали между *конкурентностью* и *параллелизмом* весьма различны.
Чтобы это понять, представьте такую картину:
Чтобы увидеть разницу, представьте следующую историю про бургеры:
### Конкурентные бургеры
<!-- 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">
Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе.
Когда, наконец, подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔🍔.
Отдаёте деньги 💸.
<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">
И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик.
Пока вы ожидаете, вы идёте со своей возлюбленной выбрать столик, садитесь и довольно продолжительное время общаетесь (поскольку ваши бургеры самые навороченные, готовятся они не так быстро).
Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨.
Сидя за столиком с возлюбленной, вы можете приятно провести время, восхищаясь, как крута, мила и умна ваша возлюбленная ✨😍✨.
<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">Кетрины Томпсон</a>. 🎨
///
---
А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖.
Представьте, что в этой истории вы компьютер / программа 🤖.
В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете.
Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного.
Когда вы в очереди, вы просто ждёте своей очереди, не делая ничего особо "производительного". Но очередь движется быстро, потому что кассир только принимает заказы (не готовит их), так что это нормально.
Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д.
Когда приходит ваша очередь, вы делаете фактически "производительную" работу: просматриваете меню, выбираете, что хотите, узнаёте, что хочет ваша возлюбленная, платите, проверяете, что отдали правильную банкноту или карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д.
И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸,
поскольку теперь нужно ждать 🕙, когда заказ приготовят.
Но даже если вы пока не получили свои бургеры, ваша работа с кассиром "на паузе" ⏸, потому что вам нужно ждать, пока они будут готовы.
Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание
на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень
"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍.
Но, отойдя с номерком от прилавка, вы садитесь за столик и можете переключить внимание 🔀 на свою возлюбленную и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень "производительны" 🤓, мило болтаете вдвоём и всё такое 😍.
В какой-то момент кассир 💁 поместит на табло ваш номер, подразумевая, что бургеры готовы 🍔, но вы не станете подскакивать как умалишённый, лишь только увидев на экране свою очередь. Вы уверены, что ваши бургеры 🍔 никто не утащит, ведь у вас свой номерок, а у других свой.
Кассир 🏽 говорит "Я закончил с приготовлением бургеров" выставив номер вашей очереди на дисплей прилавка, но вы не прыгаете как безумный только увидев, как номер на дисплее поменялся на ваш. Вы уверены, что ваши бургеры никто не утащит, ведь у вас свой номерок, а у других свой.
Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓),
и мило улыбнувшись, скажете, что идёте забирать заказ ⏸.
Таким образом, вы ждёте, пока история вашей возлюбленной не будет рассказана (завершена текущая работа ⏯ / задача 🤓), мило улыбаетесь и говорите, что идёте забирать заказ.
И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹.
В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
Тогда вы идёте к прилавку 🔀, чтобы закончить начальную задачу ⏯, берете бургеры, и говорите спасибо, забираете их к столу. На этом заканчивается этап / задача взаимодействия с прилавком ⏹. Это в свою очередь, создаёт новую задачу "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
### Параллельные бургеры
Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры".
Теперь представьте, что это не "Конкурентные бургеры", а "Параллельные бургеры".
И вот вы идёте со своей возлюбленной 😍 отведать параллельного фастфуда 🍔.
Вы идёте со своей возлюбленной за параллельным фастфудом.
Вы становитесь в очередь пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами.
Вы становитесь в очередь, в то время как несколько (скажем 8) кассиров, которые одновременно являются поварами, принимают заказы у клиентов перед вами.
При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый
из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ.
Каждый перед вами клиент ждёт, когда прилавок будет готов отпускать их бургеры, прежде чем отойти от прилавка потому что каждый из 8 кассиров идёт и сразу готовит бургер, перед тем как принять следующий заказ.
Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе.
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
Ни о чём не жалея, расплачиваетесь 💸.
Наконец подходит ваша очередь, вы заказываете 2 очень навороченные бургера для вашей возлюбленной и себя.
И кассир уходит на кухню 👨‍🍳.
Вы платите 💸.
Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет.
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь,
у вас не получается уделять должного внимание своей даме сердца 😞.
Кассир идёт на кухню.
Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки,
когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой.
Вы ждёте, стоя перед прилавком 🕙, чтобы никто не забрал ваши бургеры, прежде чем вы это сделаете, так как нет никаких порядковых номеров.
Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой.
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик.
Так как вы и ваша возлюбленная заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они прибудут, вы не можете уделить внимание своей возлюбленной. 😞
Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹.
Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Вам нужно ждать 🕙 и быть в точности в тот момент, когда кассир/повар👨‍🍳 приготовит бургеры и вручит их вам, иначе кто-то другой может забрать их.
Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞.
<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">Кетрины Томпсон</a>. 🎨
///
---
Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире.
В этой истории о параллельных бургерах вы компьютер / программа 🤖 с двумя "процессорами" (вы и ваша возлюбленная 😍), оба ждут 🕙 и уделяют все своё внимание ⏯, чтобы стоять "на кассе" долгое время.
Вот более реалистичный пример. Представьте себе банк.
Фастфуд имеет 8 "процессоров" (кассиров/поваров). В то время как в магазине конкурентных бургеров, возможно, их было всего 2 (один кассир и один повар).
До недавних пор в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙.
Но все равно итоговый опыт не из лучших. 😞
Каждый кассир обслуживал одного клиента, потом следующего 👨‍💼⏯.
---
Нужно было долгое время 🕙 стоять перед окошком вместе со всеми, иначе пропустишь свою очередь.
Это была бы параллельная история для бургеров. 🍔
Сомневаюсь, что у вас бы возникло желание прийти с возлюбленной 😍 в банк 🏦 оплачивать налоги.
Для более "реалистичного" примера этого представьте себе банк.
### Выводы о бургерах
До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙.
Кассиры выполняют всю работу для клиента один за другим 👨‍💼⏯.
В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙,
поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯.
А вам приходится долго стоять в очереди 🕙 или вы пропустите свою очередь.
И то же самое с большинством веб-приложений.
Вы вряд ли хотели бы взять свою возлюбленную 😍 в банк 🏦 оплачивать налоги.
Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению.
### Выводы о бургерах
Потом снова ждать 🕙, пока вернётся ответ.
В этой истории с "фастфудом и бургером с вашей возлюбленной", так как много времени тратится на ожидание 🕙, имеет смысл иметь конкурентную систему ⏸🔀⏯.
<!--https://forum.wordreference.com/threads/%D0%9D%D0%BE-%D0%B5%D1%81%D0%BB%D0%B8.3258695/-->
Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени.
Это случай для большинства веб-приложений.
Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API.
Много-много пользователей, но ваш сервер ждёт 🕙 их не самого лучшего соединения, чтобы отправить их запросы.
Большинство популярных фреймворков (включая 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>.
### Получается, конкурентность лучше параллелизма?
Нет! Мораль истории совсем не в этом.
Нет. Это не мораль истории.
Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание.
Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях.
Конкурентность — это не то же самое, что параллелизм. Она лучше в **конкретных** сценариях, где много времени тратится на ожидание. Именно поэтому конкурентность часто лучше параллелизма при разработке веб-приложений. Но не всегда.
Давайте посмотрим с другой стороны, представьте такую картину:
Чтобы уравновесить это, представьте следующую короткую историю:
> Вам нужно убраться в большом грязном доме.
> Вам нужно убрать в большом грязном доме.
*Да, это вся история*.
---
Тут не нужно нигде ждать 🕙, просто есть куча работы в разных частях дома.
Здесь нигде нет нужды ждать 🕙, просто много работы, которая должна быть выполнена в нескольких местах дома.
Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня,
но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете.
Вы могли бы устанавливать очереди, как в примере с бургерами, сначала гостиная, потом кухня, но, так как вы нигде не ждете 🕙, просто убираете и убираете, очереди не повлияют ни на что.
И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё,
и работы будет сделано тоже одинаковое количество.
Это заняло бы одинаковое количество времени, чтобы завершить, с или без очередей (конкурентности), и вы сделали бы одинаковое количество работы.
Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳,
и каждый из них (вместе с вами) взялся бы за свой участок дома,
с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**.
Но в этом случае, если бы вы могли пригласить 8 бывших кассиров/поваров, а ныне уборщиков, и каждый из них (вместе с вами) мог бы взять участок дома, чтобы убраться, вы могли бы сделать всю работу параллельно, с дополнительной помощью, и закончить намного быстрее.
В описанном сценарии каждый уборщик (включая вас) был бы исполнителем, занятым на своём участке работы.
В этом сценарии каждый из уборщиков (включая вас) был бы процессором, выполняющим свою часть работы.
И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание),
а работу в компьютере делает <abbr title="Центральный процессор (CPU)">ЦП</abbr>,
такие задачи называют <abbr title="CPU bound">ограниченными производительностью процессора</abbr>.
И поскольку большая часть времени выполнения тратится на настоящую работу (а не на ожидание), и работа в компьютере выполняется <abbr title="Центральный процессор">ЦП</abbr>, они называют такие задачи "ограниченными производительностью процессора".
---
Ограничение по процессору проявляется в операциях, где требуется выполнять сложные математические вычисления.
Операции, ограниченные производительностью процессора, включают в себя операции, требующие сложных математических вычислений.
Например:
* Обработка **звука** или **изображений**.
* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета,
обработка обычно требует проведения расчётов по всем пикселям сразу.
* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов".
Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить.
* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание.
Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется
специальный процессор для создания и / или использования построенных таким образом моделей.
* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения / цвета, и обработка требует выполнения вычислений для всех этих пикселей одновременно.
* **Машинное обучение**: обычно требуются множества умножений "матриц" и "векторов". Представьте большую электронную таблицу с числами и перемножьте их все сразу.
* **Глубинное обучение**: это подполе машинного обучения, поэтому то же самое применяется. Разница лишь в том, что у вас нет единственной электронной таблицы чисел для умножения, а есть их большое множество, и во многих случаях используется специальный процессор для создания и / atau использования таких моделей.
### Конкурентность + параллелизм: Веб + машинное обучение
### Конкурентность + Параллелизм: Веб + Машинное обучение
**FastAPI** предоставляет возможности конкуретного программирования,
которое очень распространено в веб-разработке (именно этим славится NodeJS).
С **FastAPI** вы можете использовать возможности конкуретного программирования, что очень распространено для веб-разработки (именно это привлекательно в NodeJS).
Кроме того вы сможете использовать все преимущества параллелизма и
<abbr title="multiprocessing">многопроцессорности</abbr> (когда несколько процессов работают параллельно),
если рабочая нагрузка предполагает **ограничение по процессору**,
как, например, в системах машинного обучения. <!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_329-->
Тем не менее, вы можете также использовать преимущества параллелизма и многопроцессорности (несколько процессов, работающих параллельно) для рабочих нагрузок, ограниченных по процессору, таких как в Машинное обучение.
Необходимо также отметить, что Python является главным языком в области
<abbr title="наука о данных (data science)">**дата-сайенс**</abbr>,
машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI
отличным вариантом (среди многих других) для разработки веб-API и приложений
в области дата-сайенс / машинного обучения.
Это, плюс простой факт, что Python является главным языком в области науки о данных, Машинного и, особенно, Глубинного обучения, делает FastAPI отличным выбором для создания веб-API и приложений для науки о данных и / atau машинного обучения (среди многих других).
Как добиться такого параллелизма в эксплуатации описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}.
Чтобы узнать, как добиться такого параллелизма в производственной эксплуатации, смотрите раздел [Развертывание](deployment/index.md){.internal-link target=_blank}.
## `async` и `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):
@ -359,22 +329,18 @@ def get_sequential_burgers(number: int):
return burgers
```
Объявление `async def` указывает интерпретатору, что внутри этой функции
следует ожидать выражений `await`, и что можно поставить выполнение такой функции на "паузу" ⏸ и
переключиться на другие задачи 🔀, с тем чтобы вернуться сюда позже.
Объявляя `async def`, интерпретатор Python знает, что внутри этой функции нужно быть внимательным к выражениям `await`, и что он может "поставить на паузу" ⏸ выполнение этой функции и выполнить что-то ещё 🔀 прежде, чем вернуться.
Если вы хотите вызвать функцию с `async def`, вам нужно <abbr title="await">"ожидать"</abbr> её.
Поэтому такое не сработает:
Когда вы хотите вызвать функцию с `async def`, вам нужно "ожидать" её с помощью `await`. Таким образом, это не сработает:
```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')
@ -385,127 +351,94 @@ async def read_burgers():
### Технические подробности
Как вы могли заметить, `await` может применяться только в функциях, объявленных с использованием `async def`.
Вы могли заметить, что `await` можно использовать только внутри функций, определённых с помощью `async def`.
<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_128-->
Но выполнение такой функции необходимо "ожидать" с помощью `await`.
Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`.
Но одновременно функции, определённые с `async def`, должны быть "ожидание" с помощью `await`. Так что функции с `async def` можно вызывать только внутри функций, которые тоже определены с `async def`.
Но как же тогда появилась первая <abbr title="или яйцо?🤔">курица</abbr>? В смысле... как нам вызвать первую асинхронную функцию?
Так как же тогда появилась первая <abbr title="или яйцо?🤔">курица</abbr>? То есть... как вызвать первую асинхронную функцию?
При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*,
и дальше с этим разберётся FastAPI.
Если вы работаете с **FastAPI**, то не нужно беспокоиться об этом, потому что эта "первая" функция будет вашей *и функции-обработчиком пути*, и FastAPI знает, как сделать всё правильно.
Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI.
Тем не менее, если вы захотите использовать `async` / `await` без FastAPI, вы также можете это сделать.
### Пишите свой асинхронный код
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-->
Starlette и **FastAPI** основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, что делает их совместимыми как со стандартной библиотекой Python's <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>.
В частности, вы можете использовать <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> непосредственно для ваших расширенных вариантов использования конкурентности, которые требуют более сложных шаблонов в вашем коде.
В частности, вы можете напрямую использовать <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> в тех проектах, где требуется более сложная логика работы с конкурентностью.
И даже если вы не использовали FastAPI, вы также можете писать свои асинхронные приложения с использованием <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> для обеспечения их высокой совместимости и получения его преимуществ (например, *структурированной конкурентности*).
Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, чтобы они были максимально совместимыми и получали его преимущества (например *структурную конкурентность*).
Я создал ещё одну библиотеку на базе AnyIO, как тонкий слой сверху, чтобы немного улучшить аннотации типов и получить лучшее **автозавершение кода**, **встроенные ошибки** и т. д. У неё также есть дружественное введение и руководство, чтобы помочь вам **понять** и написать **свой асинхронный код**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. Она будет особенно полезна, если вам нужно **объединить асинхронный код с обычным** (блокирующимся/синхронным) кодом.
### Другие виды асинхронного программирования
### Другие формы асинхронного программирования
Стиль написания кода с `async` и `await` появился в языке Python относительно недавно.
Этот стиль использования `async` и `await` относительно новый в языке.
Но он сильно облегчает работу с асинхронным кодом.
Ровно такой же синтаксис (ну или почти такой же) недавно был включён в современные версии JavaScript (в браузере и NodeJS).
Точно такой же синтаксис (или почти идентичный) недавно был включён в современные версии JavaScript (в браузере и NodeJS).
До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать.
Но до этого управление асинхронным кодом было гораздо более сложным.
В предыдущих версиях Python для этого использовались потоки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Но такой код намного сложнее понимать, отлаживать и мысленно представлять.
В предыдущих версиях Python вы могли использовать потоки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Но код при этом становился намного сложнее для понимания, отладки и мышления.
Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели
<abbr title="callback">"обратные вызовы"</abbr>. Что выливалось в
<a href="http://callbackhell.ru/" class="external-link" target="_blank">ад обратных вызовов</a>.
В предыдущих версиях NodeJS/Browser JavaScript вы могли использовать "обратные вызовы". Что приводило к <a href="http://callbackhell.com/" class="external-link" target="_blank">callback hell</a>.
## Сопрограммы
<abbr title="coroutine">**Корути́на**</abbr> (или же сопрограмма) — это крутое словечко для именования той сущности,
которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию,
но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`.
<abbr title="сопрограмма">**Сопрограмма**</abbr> - это просто высокопарный термин для обозначения той вещи, которую функция `async def` возвращает. Интерпретатор Python знает, что это нечто вроде функции, что она может быть запущена и завершена в какой-то момент, но она также может быть поставлена на паузу ⏸, даже когда внутри неё есть `await`.
Всю функциональность асинхронного программирования с использованием `async` и `await`
часто обобщают словом "корутины". Они аналогичны <abbr title="Goroutines">"горутинам"</abbr>, ключевой особенности
языка Go.
Но вся эта функциональность использования асинхронного кода с `async` и `await` во многих случаях обобщается как использование "сопрограмм". Это сопоставимо с ключевой отличительной особенностью языка Go, "горутины".
## Заключение
В самом начале была такая фраза:
Давайте ещё раз вспомним ту фразу изначально:
> Современные версии Python поддерживают разработку так называемого
**"асинхронного кода"** посредством написания **"сопрограмм"** с использованием
синтаксиса **`async` и `await`**.
> Современные версии Python поддерживают **"асинхронный код"**, используя что-то под названием **"сопрограммы"** с **синтаксисом `async` и `await`**.
Теперь всё должно звучать понятнее. ✨
Теперь это должно звучать понятнее. ✨
На этом основана работа FastAPI (посредством Starlette), и именно это
обеспечивает его высокую производительность.
Именно это в основном работает в FastAPI (через Starlette) и придаёт ему такую впечатляющую производительность.
## Очень технические подробности
/// warning
/// warning | Предупреждение
Этот раздел читать не обязательно.
Вы, вероятно, можете пропустить это.
Здесь приводятся подробности внутреннего устройства **FastAPI**.
Это очень технические детали внутреннего устройства **FastAPI**.
Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.)
и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`,
читайте дальше.
Если у вас действительно много технических знаний (сопрограммы, потоки, блокировка и т. д.) и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычного `def`, читайте дальше.
///
### Функции обработки пути
### Функции-обработчики пути
Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def`
вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем
<abbr title="threadpool">пуле потоков</abbr>, а не напрямую (это бы заблокировало сервер).
Когда вы объявляете *функцию-обработчик пути* стандартным способом с `def` вместо `async def`, она выполняется в внешнем пуле потоков, который затем ожидается, а не вызывается напрямую (это бы заблокировало сервер).
Если ранее вы использовали другой асинхронный фреймворк, который работает иначе,
и привыкли объявлять простые вычислительные *функции* через `def` ради
незначительного прироста скорости (порядка 100 наносекунд), обратите внимание,
что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит
`async def`, если только *функция обработки пути* не использует код, приводящий
к блокировке <abbr title="Ввод/вывод: чтение и запись на диск, сетевые соединения.">I/O</abbr>.
<!--Уточнить: Не использовать async def, если код приводит к блокировке IO?-->
Если вы пришли из другого асинхронного фреймворка, который не работает так, как описано выше, и вы привыкли определять простые вычислительные *функции* с помощью обычного `def` ради микроскопического прироста производительности (порядка 100 наносекунд), обратите внимание, что в **FastAPI** эффект будет совершенно противоположный. В этих случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, который выполняет блокирующий <abbr title="Ввод/вывод: чтение и запись на диск, сетевые соединения.">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} (или по крайней мере сравнимо с) вашим предыдущим фреймворком
### Зависимости
То же относится к зависимостям. Если это обычная функция `def`, а не `async def`,
она запускается во внешнем пуле потоков.
То же самое применимо и к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость оформлена как стандартная `def` функция вместо `async def`, она выполняется в внешнем пуле потоков.
### Подзависимости
Вы можете объявить множество ссылающихся друг на друга зависимостей и подзависимостей
(в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`,
другие обычным образом через `def`, и такая схема вполне работоспособна. Функции,
объявленные с помощью `def` будут запускаться на внешнем потоке (из пула),
а не с помощью `await`.
Вы можете иметь несколько зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} требующих друг друга (в виде параметров определения функции), некоторые из которых могут быть созданы с помощью `async def`, а некоторые с обычным `def`. Они всё равно будут работать корректно, и те, которые созданы со стандартным `def`, будут вызываться на внешнем потоке (из пула), а не будут "ожидать".
### Другие служебные функции
Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять
с использованием `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-->
Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали.
Ещё раз, эти технические подробности, вероятно, будут полезны, только если вы специально их искали.
В противном случае просто ознакомьтесь с основными принципами в разделе выше: <a href="#_1">Нет времени?</a>.
В противном случае, ознакомьтесь со сводкой из раздела выше: <a href="#in-a-hurry">Нет времени?</a>.

43
docs/ru/docs/benchmarks.md

@ -1,37 +1,34 @@
# Замеры производительности
# Бенчмарки
Независимые тесты производительности приложений от 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).
Но при просмотре и сравнении замеров производительности следует иметь в виду нижеописанное.
Но при просмотре бенчмарков и сравнений следует иметь в виду следующее.
## Замеры производительности и скорости
## Бенчмарки и скорость
В подобных тестах часто можно увидеть, что инструменты разного типа сравнивают друг с другом, как аналогичные.
При просмотре бенчмарков часто можно увидеть, что инструменты разных типов сравниваются как эквивалентные.
В частности, сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов).
В частности, Uvicorn, Starlette и FastAPI зачастую сравниваются вместе (среди множества других инструментов).
Чем проще проблема, которую решает инструмент, тем выше его производительность. И большинство тестов не проверяют дополнительные функции, предоставляемые инструментом.
Чем проще проблема, решаемая инструментом, тем выше будет его производительность. И большинство бенчмарков не тестируют дополнительные функции, предоставляемые инструментом.
Иерархия инструментов имеет следующий вид:
Иерархия выглядит так:
* **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 и другими веб-фреймворками (или микрофреймворками).
* Следующей по производительности будет Starlette, после Uvicorn. Фактически, Starlette использует Uvicorn для запуска. Таким образом, она может быть "медленнее" Uvicorn только из-за выполнения большего объема кода.
* Но она предоставляет инструменты для создания простых веб-приложений, с маршрутизацией на основе путей и т.д.
* Если вы сравниваете Starlette, сравнивайте ее с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками).
* **FastAPI**:
* Так же как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, то есть он не может быть быстрее Starlette.
* FastAPI предоставляет больше возможностей поверх Starlette, которые наверняка Вам понадобятся при создании API, такие как проверка данных и сериализация. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске).
* Если Вы не используете FastAPI, а используете Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
* Таким образом, используя FastAPI Вы потратите меньше времени на разработку, уменьшите количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своем коде).
* FastAPI должно сравнивать с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные.
* Так же как Starlette использует Uvicorn и не может быть быстрее его, **FastAPI** использует Starlette, так что он не может быть быстрее нее.
* FastAPI предоставляет больше возможностей на базе Starlette. Возможности, которые, скорее всего, понадобятся вам при создании API, такие как валидация и сериализация данных. И благодаря этому вы получаете автоматическую документацию "бесплатно" (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске).
* Если вы не использовали FastAPI и использовали Starlette напрямую (или другой инструмент, такой как Sanic, Flask, Responder и т.д.), вам пришлось бы самостоятельно реализовать всю валидацию и сериализацию данных. То есть, в итоге, ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объем кода, написанного в приложениях.
* Таким образом, используя FastAPI, вы экономите время разработки, сокращаете количество ошибок, количество строк кода и, вероятно, получите такую же производительность (или лучше), какую получили бы, если бы не использовали его (так как вам пришлось бы реализовать все это в своем коде).
* Если вы сравниваете FastAPI, сравнивайте его с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией.

176
docs/ru/docs/deployment/manually.md

@ -1,163 +1,157 @@
# Запуск сервера вручную - Uvicorn
# Запуск сервера вручную
Для запуска приложения **FastAPI** на удалённой серверной машине вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**.
## Используйте команду `fastapi run`
Существует три наиболее распространённые альтернативы:
Кратко говоря, используйте `fastapi run` для запуска вашего приложения 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 будет устанавливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями.
Вы можете использовать эту команду, например, для запуска вашего приложения **FastAPI** в контейнере, на сервере и т. д.
В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ.
## ASGI-серверы
///
Давайте углубимся в детали.
////
FastAPI использует стандарт для создания веб-фреймворков и серверов на Python под названием <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr>. FastAPI — это веб-фреймворк на основе ASGI.
//// tab | Hypercorn
Основное, что вам требуется для запуска приложения **FastAPI** (или любого другого приложения на основе ASGI) на удаленной серверной машине — это программа ASGI-сервера, такая как **Uvicorn**, именно она используется по умолчанию в команде `fastapi`.
* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, ASGI сервер, поддерживающий протокол HTTP/2.
Существует несколько альтернатив, включая:
<div class="termy">
* <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 — легковесная и универсальная среда выполнения веб-приложений.
```console
$ pip install hypercorn
---> 100%
```
</div>
...или какой-либо другой ASGI сервер.
////
## Сервер как машина и сервер как программа
## Запуск серверной программы
Есть небольшая деталь в названиях, о которой стоит помнить. 💡
Затем запустите ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`:
Слово "**сервер**" обычно используется для обозначения как удаленного/облачного компьютера (физической или виртуальной машины), так и программы, которая на этой машине работает (например, Uvicorn).
//// tab | Uvicorn
Просто имейте в виду, что когда вы видите "сервер", это может относиться к одному из этих двух значений.
<div class="termy">
Когда речь идет о удаленной машине, часто используется термин **сервер**, но также можно встретить **машина**, **ВМ** (виртуальная машина), **нода**. Все это обозначает какую-то удаленную машину, обычно под управлением Linux, на которой вы запускаете программы.
```console
$ 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)
```
При установке 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 | Подсказка
Не забудьте удалить опцию `--reload`, если ранее пользовались ею.
Добавляя `standard`, Uvicorn установит и будет использовать некоторые рекомендованные дополнительные зависимости.
Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности.
Сюда входит `uvloop`, высокопроизводительная замена для `asyncio`, которая дает значительное ускорение производительности асинхронных программ.
Она сильно помогает во время **разработки**, но **не следует** использовать её при **реальной работе** приложения.
Когда вы устанавливаете FastAPI подобно `pip install "fastapi[standard]"`, вы уже получаете `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>.
Тем не менее 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 | Примечание
Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`:
Команда `uvicorn main:app` относится к:
<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` потребляет гораздо больше ресурсов, более нестабильна и т. д.
Она очень помогает во время **разработки**, но **не следует** использовать её в **продакшне**.
///
## Концепции развёртывания
В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`).
Эти примеры запускают программное обеспечение сервера (например, Uvicorn), начиная **один процесс**, слушающий все IP (`0.0.0.0`) на заранее определенном порту (например, `80`).
Это основная идея. Но возможно, вы озаботитесь добавлением дополнительных возможностей, таких как:
Это основная идея. Но, вероятно, вам захочется позаботиться о некоторых дополнительных вещах, таких как:
* Использование более безопасного протокола HTTPS
* Настройки запуска приложения
* Перезагрузка приложения
* Запуск нескольких экземпляров приложения
* Управление памятью
* Использование перечисленных функций перед запуском приложения.
* Безопасность - HTTPS
* Запуск при старте
* Перезапуски
* Репликация (количество запущенных процессов)
* Память
* Предварительные действия перед запуском
Я расскажу вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀
Я расскажу вам больше о каждой из этих концепций, как о них думать и приведу конкретные примеры со стратегиями их решения в следующих главах. 🚀

221
docs/ru/docs/help-fastapi.md

@ -1,24 +1,24 @@
# Помочь FastAPI - Получить помощь
Нравится ли Вам **FastAPI**?
Нравится ли вам **FastAPI**?
Хотели бы Вы помочь FastAPI, его пользователям и автору?
Хотели бы вы помочь FastAPI, его пользователям и автору?
Может быть у Вас возникли трудности с **FastAPI** и Вам нужна помощь?
Или вам нужна помощь с **FastAPI**?
Есть несколько очень простых способов оказания помощи (иногда достаточно всего лишь одного или двух кликов).
Есть очень простые способы помочь (несколько из них требуют всего один или два клика).
И также есть несколько способов получить помощь.
Также есть несколько способов получить помощь.
## Подписаться на новостную рассылку
Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md){.internal-link target=_blank} и быть в курсе о:
Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md){.internal-link target=_blank}, чтобы быть в курсе:
* Новостях о FastAPI и его друзьях 🚀
* Руководствах 📝
* Возможностях
* Исправлениях 🚨
* Подсказках и хитростях
* Новостей о FastAPI и его друзьях 🚀
* Руководств 📝
* Возможностей
* Изменений, нарушающих совместимость 🚨
* Советов и хитростей
## Подписаться на FastAPI в Twitter
@ -26,177 +26,185 @@
## Добавить **FastAPI** звезду на 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>. ⭐️
Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих.
Чем больше звёзд, тем легче другим пользователям найти его и увидеть, что проект уже стал полезным для многих.
## Отслеживать свежие выпуски в репозитории на GitHub
Вы можете "отслеживать" 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** с исправлениями ошибок и новыми возможностями.
Таким образом вы будете получать уведомления (по электронной почте) каждый раз, когда будет выпускаться новая версия **FastAPI** с исправлениями ошибок и новыми возможностями.
## Связаться с автором
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себястьян Рамирез / `tiangolo`)</a>, автором FastAPI.
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себастьян Рамирез / `tiangolo`)</a>, автором FastAPI.
Вы можете:
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Подписаться на меня на **GitHub**</a>.
* Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
* Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
* Посмотреть другие мои open-source проекты, которые могут быть вам полезны.
* Подписавшись на меня, вы сможете видеть, когда я создаю новый проект с открытым исходным кодом.
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Подписаться на меня в **Twitter**</a> или в <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>.
* Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это).
* Получать уведомления, когда я делаю объявления и представляю новые инструменты.
* Вы также можете <a href="https://twitter.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в Twitter</a> (это отдельный аккаунт).
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **Linkedin**</a>.
* Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷‍♂).
* Читать, что я пишу (или подписаться на меня) в <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>.
* Читать другие идеи, статьи и читать об инструментах созданных мной.
* Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое.
* Поделиться со мной, как вы используете FastAPI (мне это очень интересно).
* Узнавать обо всех моих анонсах и новых выпусках инструментов.
* Вы также можете <a href="https://twitter.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в Twitter</a> (это отдельная учетная запись).
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **LinkedIn**</a>.
* Узнавать обо всех моих анонсах и новых выпусках инструментов (хотя я чаще использую Twitter 🤷‍♂).
* Читайте мои статьи (или подпишитесь на меня) на <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>.
* Читайте другие идеи, статьи и обзор инструментов, которые я создал.
* Подпишитесь, чтобы увидеть, когда я публикую что-то новое.
## Оставить сообщение в Twitter о **FastAPI**
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в Twitter о **FastAPI**</a> и позвольте мне и другим узнать - почему он Вам нравится. 🎉
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в Twitter о **FastAPI**</a> и дайте мне и другим узнать, почему он вам нравится. 🎉
Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п.
Мне очень нравится узнавать о том, как **FastAPI** используется, что вам нравится в нем, на каких проектах/компаниях вы его применяете и т.п.
## Оставить голос за 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>.
## Помочь другим с их проблемами на GitHub
## Помочь другим с вопросами на 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</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">Issues на GitHub</a>
Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗
Во многих случаях вы можете уже знать ответ на эти вопросы. 🤓
Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
Если вы будете много помогать людям с их вопросами, вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉
Только помните, самое важное — старайтесь быть добрыми. Люди приходят со своими разочарованиями и в большинстве случаев не задают вопросы лучшим образом, но старайтесь проявить максимум доброты. 🤗
Идея сообщества **FastAPI** заключается в доброжелательности и гостеприимстве. В то же время не допускайте издевательств или неуважительного поведения к другим. Мы должны заботиться друг о друге.
---
Как помочь другим с их проблемами:
Как помочь другим с вопросами (в обсуждениях или в вопросах):
### Понять вопрос
* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего.
* Удостоверьтесь, что понимаете **цель** и обстоятельства задающего вопрос.
* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
* Затем удостоверьтесь, что вопрос (в подавляющем большинстве случаев это именно вопрос) для вас **ясен**.
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и **лучше**. Если вы поймете проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
* Ежели вопрос Вам непонятен, запросите больше **деталей**.
* Если вопрос вам непонятен, запросите больше **деталей**.
### Воспроизвести проблему
В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего.
Для большинства случаев и большинства вопросов существует что-то связанное с **исходным кодом** того, кто задает вопрос.
Во многих случаях они будут копировать только фрагмент кода, но этого недостаточно для **воспроизведения проблемы**.
И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**.
* Вы можете попросить предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который вы можете **скопировать-вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, или лучше понять их использование.
* Попросите предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая.
* Если вы чувствуете себя слишком щедрым, попытайтесь **создать подобный пример** самостоятельно, основываясь только на описании проблемы. Просто имейте в виду, что это может занять много времени, и, возможно, лучше сначала уточнить проблему.
* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
### Предложить решения
### Предложить решение
* После того как вы поняли вопрос, вы можете дать возможный **ответ**.
* После того как Вы поняли вопрос, Вы можете дать **ответ**.
* В большинстве случаев лучше понять их **основную проблему или обстоятельства**, потому что может быть лучший способ ее решения, чем то, что они пытаются сделать.
* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать.
### Попросить закрыть
### Попросить закрыть проблему
Если они ответят, высока вероятность, что вам удалось решить проблему, поздравляю, **вы - герой**! 🦸
Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
* Если вопрос решен, попросите их:
* В таком случае, если вопрос решён, попросите **закрыть проблему**.
* В GitHub Discussions: отметить комментарий как **ответ**.
* В GitHub Issues: **закрыть** issue.
## Отслеживать репозиторий на GitHub
Вы можете "отслеживать" 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, обсуждениях или пул-реквестах и т.д.
Тогда Вы можете попробовать решить эту проблему.
Затем вы можете попробовать помочь им решить эти вопросы.
## Запросить помощь с решением проблемы
## Задавать вопросы
Вы можете <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, например, чтобы:
* Задать **вопрос** или попросить помощи в решении **проблемы**.
* Предложить новое **улучшение**.
* Задать **вопрос** или спросить о **проблеме**.
* Предложить новую **возможность**.
**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉
**Заметка**: если вы это сделаете, я попрошу вас также помочь другим. 😉
## Проверять пул-реквесты
Вы можете помочь мне проверять пул-реквесты других участников.
Вы можете помочь мне проверять пул-реквесты от других участников.
И повторюсь, постарайтесь быть доброжелательным. 🤗
И повторюсь, постарайтесь быть добрыми. 🤗
---
О том, что нужно иметь в виду при проверке пул-реквестов:
Вот что стоит иметь в виду при проверке пул-реквестов:
### Понять проблему
* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение.
* Во-первых, убедитесь, что **понимаете проблему**, которую пул-реквест пытается решить. Возможно, это будет сделано через более длинное обсуждение в Discussion или issue на GitHub.
* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт.
* Есть также вероятность, что пул-реквест не нужен, так как проблема может быть решена **другим путем**. Тогда вы можете предложить или спросить об этом.
### Не переживайте о стиле
* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную.
* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты.
* Также не беспокойтесь о правилах стиля, уже есть автоматизированные инструменты, которые это проверяют.
И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями.
И если все-таки потребуется другой стиль или согласованность, я попрошу об этом напрямую или добавлю сам коммиты с необходимыми изменениями.
### Проверить код
* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу.
* Проверьте и прочитайте код, посмотрите, имеет ли он смысл, **запустите его локально** и посмотрите, решает ли он действительно проблему.
* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код.
* Затем оставьте **комментарий**, что вы это сделали, так я узнаю, что вы действительно проверили его.
/// info | Информация
К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений.
К сожалению, я не могу просто доверять PR, которые просто получили несколько одобрений.
Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅
Было несколько случаев, когда пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅
Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓
Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что вы проделали эти действия. 🤓
///
* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах.
* Если можно упростить пул-реквест, вы можете попросить об этом, но нет нужды быть слишком дотошным, может существовать много субъективных точек зрения (и у меня своя тоже будет 🙈), так что лучше, если вы сосредоточитесь на фундаментальных вещах.
### Тестировать
### Тестирование
* Помогите мне проверить, что у пул-реквеста есть **тесты**.
* Проверьте, что тесты **падали** до пул-реквеста. 🚨
* Проверьте, что тесты **падают** до пул-реквеста. 🚨
* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅
* Затем проверьте, что тесты **проходят** после пул-реквеста. ✅
* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим.
* Многие пул-реквесты не имеют тестов, вы можете **напомнить** об их добавлении или даже **предложить** какие-либо тесты сами. Это одна из тех вещей, которые отнимают много времени, и вы можете оказать значительную помощь в этом.
* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓
* Затем добавьте комментарий, что вы испробовали в ходе проверки. Таким образом я буду знать, как вы произвели проверку. 🤓
## Создать пул-реквест
Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например:
Вы можете [внести вклад](contributing.md){.internal-link target=_blank} в исходный код с помощью пул-реквестов, например:
* Исправить опечатку, которую Вы нашли в документации.
* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>.
* Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела.
* Помочь с [переводом документации](contributing.md#_8){.internal-link target=_blank} на Ваш язык.
* Вы также можете проверять переводы сделанные другими.
* Исправить опечатку, которую вы нашли в документации.
* Поделиться статьей, видео или подкастом о 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} на ваш язык.
* Вы также можете помочь проверять переводы, сделанные другими.
* Предложить новые разделы документации.
* Исправить существующуе проблемы/баги.
* Исправить существующую проблему/ошибку.
* Убедитесь, что добавили тесты.
* Добавить новую возможность.
* Убедитесь, что добавили тесты.
@ -206,56 +214,43 @@
Помогите мне поддерживать **FastAPI**! 🤓
Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать.
Предстоит еще много работы, и в большей части из нее **вы** можете помочь.
Основные задачи, которые Вы можете выполнить прямо сейчас:
Основные задачи, которые вы можете сделать сейчас:
* [Помочь другим с их проблемами на GitHub](#github_1){.internal-link target=_blank} (смотрите вышестоящую секцию).
* [Проверить пул-реквесты](#-){.internal-link target=_blank} (смотрите вышестоящую секцию).
* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github) (смотрите выше).
* [Проверять пул-реквесты](#review-pull-requests) (смотрите выше).
Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI.
Эти две задачи — те, что чаще всего **занимают время**. Это основная работа по поддержке FastAPI.
Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
Если вы можете помочь мне с этим, **вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
## Подключиться к чату
Подключайтесь к 👥 <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 | Подсказка
Вопросы по проблемам с фреймворком лучше задавать в <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#_3){.internal-link target=_blank}.
Для вопросов, задавайте их в <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>, там больше шансов получить помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}.
Используйте этот чат только для бесед на отвлечённые темы.
Используйте чат только для других общих разговоров.
///
### Не использовать чаты для вопросов
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
В разделе "проблемы" на 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>.
Там можно просто купить мне кофе ☕️ в знак благодарности. 😄
Имейте в виду, что так как чаты позволяют более "свободное общение", легко задать вопросы, которые слишком общие и сложнее на них ответить, поэтому вы можете не получить ответов.
А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉
На GitHub шаблон поможет вам задать правильный вопрос, чтобы легче было получить хороший ответ или даже решить проблему самостоятельно до того, как вы его зададите. И на GitHub я могу быть уверен, что всегда отвечаю на все, даже если это займет время. Я не могу сделать то же самое в чатах. 😅
## Спонсировать инструменты, на которых зиждется мощь FastAPI
Общение в чатах не так легко ищется, как на GitHub, поэтому вопросы и ответы могут затеряться в разговоре. И только запросы на GitHub учитываются для получения звания [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, поэтому, вероятнее всего, вы получите больше внимания на GitHub.
Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic.
С другой стороны в чатах тысячи пользователей, поэтому вы с большой вероятностью найдете кого-то, с кем можно поговорить, почти в любое время. 😄
Им тоже можно оказать спонсорскую поддержку:
## Спонсорство для автора
* <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>. В зависимости от уровня поддержки, вы можете получить дополнительные преимущества, такие как знак в документации. 🎁
---
Благодарствую! 🚀
Благодарю! 🚀

103
docs/ru/docs/index.md

@ -37,7 +37,7 @@ FastAPI — это современный, быстрый (высокопрои
Ключевые особенности:
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков Python](#_10).
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков Python](#performance).
* **Быстрота разработки**: Увеличьте скорость разработки примерно на 200–300%. *
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
* **Интуитивно понятный**: Отличная поддержка редактора. <abbr title="также известное как автозаполнение, автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
@ -105,6 +105,12 @@ FastAPI — это современный, быстрый (высокопрои
---
"_Если кто-то хочет построить продакшн Python API, я настоятельно рекомендую **FastAPI**. Он **прекрасно спроектирован**, **прост в использовании** и **высоко масштабируем**, он стал **ключевым компонентом** нашей стратегии разработки API-first и управляет многими автоматизациями и услугами, такими как наш Виртуальный TAC-инженер._"
<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
<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>
@ -122,33 +128,25 @@ FastAPI стоит на плечах гигантов:
## Установка
<div class="termy">
```console
$ pip install fastapi
---> 100%
```
</div>
Вам также понадобится сервер ASGI для производства, такой как <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>.
Создайте и активируйте <a href="https://fastapi.tiangolo.com/virtual-environments/" class="external-link" target="_blank">виртуальное окружение</a>, затем установите FastAPI:
<div class="termy">
```console
$ pip install "uvicorn[standard]"
$ pip install "fastapi[standard]"
---> 100%
```
</div>
**Примечание**: Убедитесь, что вы взяли в кавычки `"fastapi[standard]"`, чтобы это работало во всех терминалах.
## Пример
### Создание
* Создайте файл `main.py` со следующим содержимым:
Создайте файл `main.py` со следующим содержимым:
```Python
from typing import Union
@ -204,11 +202,24 @@ async def read_item(item_id: int, q: Union[str, None] = None):
<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.
```
@ -216,13 +227,13 @@ INFO: Application startup complete.
</div>
<details markdown="1">
<summary>О команде <code>uvicorn main:app --reload</code>...</summary>
<summary>О команде <code>fastapi dev main.py</code>...</summary>
Команда `fastapi dev` читает ваш файл `main.py`, обнаруживает приложение **FastAPI** в нем и запускает сервер с использованием <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>.
Команда `uvicorn main:app` относится к:
По умолчанию `fastapi dev` запускается с включенной авто-перезагрузкой для локальной разработки.
* `main`: файл `main.py` (модуль Python).
* `app`: объект, созданный внутри `main.py` с помощью строки `app = FastAPI()`.
* `--reload`: перезапуск сервера после изменения кода. Делайте это только во время разработки.
Вы можете узнать больше об этом в <a href="https://fastapi.tiangolo.com/fastapi-cli/" target="_blank">документации FastAPI CLI</a>.
</details>
@ -295,7 +306,7 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
Сервер должен перезагрузиться автоматически (потому что вы добавили `--reload` к команде `uvicorn` выше).
Сервер должен перезагрузиться автоматически.
### Интерактивное обновление документации API
@ -356,7 +367,7 @@ item: Item
* Параметров пути.
* Параметров запроса.
* Cookies.
* Заголовков.
* HTTP-заголовков.
* Форм.
* Файлов.
* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> выходных данных: преобразование объектов Python в данные передаваемые по сети интернет (такие как JSON):
@ -430,7 +441,7 @@ item: Item
* **Веб-сокеты**
* очень простые тесты на основе HTTPX и `pytest`
* **CORS**
* **Cookie сеансы(сессии)**
* **Сессии с использованием cookie**
* ...и многое другое.
## Производительность
@ -439,7 +450,13 @@ item: Item
Чтобы узнать больше об этом, см. раздел <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Тесты производительности</a>.
## Необязательные зависимости
## Зависимости
FastAPI зависит от Pydantic и Starlette.
### Зависимости `standard`
Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он поставляется с группой необязательных зависимостей `standard`:
Используется Pydantic:
@ -447,20 +464,38 @@ item: Item
Используется Starlette:
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - Обязательно, если вы хотите использовать `TestClient`.
* <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).
Используется FastAPI / Starlette:
Используется 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`
Если вы не хотите включать необязательные зависимости `standard`, вы можете установить с `pip install fastapi` вместо `pip install "fastapi[standard]"`.
### Без `fastapi-cloud-cli`
Если вы хотите установить FastAPI с обычными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
### Дополнительные необязательные зависимости
Есть некоторые дополнительные зависимости, которые вы, возможно, захотите установить.
Дополнительные необязательные зависимости Pydantic:
* <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.
Дополнительные необязательные зависимости FastAPI:
* <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`.
Вы можете установить все это с помощью `pip install "fastapi[all]"`.
## Лицензия
Этот проект распространяется на условиях лицензии MIT.

112
docs/ru/docs/project-generation.md

@ -1,84 +1,28 @@
# Генераторы проектов - Шаблоны
Чтобы начать работу быстрее, Вы можете использовать "генераторы проектов", в которые включены множество начальных настроек для функций безопасности, баз данных и некоторые <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 Шаблон
Шаблоны, хотя и содержат определённые настройки, разработаны для гибкости и настраиваемости. Это позволяет вам модифицировать и адаптировать их в соответствии с требованиями вашего проекта, делая их отличной отправной точкой. 🏁
Вы можете использовать этот шаблон, чтобы быстрее начать работу, так как он включает в себя множество начальных настроек, функции безопасности, баз данных и несколько эндпоинтов 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 Шаблон - Технологический стек и функциональные возможности
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python-бэкенда API.
- 🧰 [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 токенов.
- 📫 Восстановление пароля через email.
- ✅ Тесты с использованием [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) в качестве реверс-прокси / балансировщика нагрузки.
- 🚢 Инструкции по развертыванию с использованием Docker Compose, включая настройку фронтенд-прокси Traefik для автоматической обработки HTTPS-сертификатов.
- 🏭 CI (непрерывная интеграция) и CD (непрерывное развёртывание) на базе GitHub Actions.

28
docs/ru/docs/tutorial/body-multiple-params.md

@ -1,10 +1,10 @@
# Body - Множество параметров
Теперь, когда мы увидели, как использовать `Path` и `Query` параметры, давайте рассмотрим более продвинутые примеры обьявления тела запроса.
Теперь, когда мы увидели, как использовать `Path` и `Query`, давайте рассмотрим более продвинутые примеры объявления тела запроса.
## Обьединение `Path`, `Query` и параметров тела запроса
## Объединение `Path`, `Query` и параметров тела запроса
Во-первых, конечно, вы можете объединять параметры `Path`, `Query` и объявления тела запроса в своих функциях обработки, **FastAPI** автоматически определит, что с ними нужно делать.
Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления тела запроса, и **FastAPI** автоматически определит, что с ними делать.
Вы также можете объявить параметры тела запроса как необязательные, установив значение по умолчанию, равное `None`:
@ -18,7 +18,7 @@
## Несколько параметров тела запроса
В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON-тело с параметрами, соответствующими атрибутам `Item`, например:
В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON с параметрами, соответствующими атрибутам `Item`, например:
```JSON
{
@ -54,13 +54,13 @@
/// note | Внимание
Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предпологается, что он находится внутри тела с ключом `item`.
Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`.
///
**FastAPI** сделает автоматические преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое происходит с пользователем `user`.
**FastAPI** выполнит автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с `user`.
Произойдёт проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах.
Произойдет проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах.
## Отдельные значения в теле запроса
@ -68,7 +68,7 @@
Например, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`.
Если вы объявите его без указания, какой именно объект (Path, Query, Body и .т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать, что это query-параметр.
Если вы объявите его без указания, какой именно объект (Path, Query, Body и т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать его query-параметром.
Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`:
@ -92,13 +92,13 @@
}
```
И всё будет работать так же - преобразование типов данных, валидация, документирование и т.д.
И все будет работать так же: преобразование типов данных, валидация, документирование и т.д.
## Множество body и query параметров
Конечно, вы также можете объявлять query-параметры в любое время, дополнительно к любым body-параметрам.
Конечно, вы также можете объявлять дополнительные query-параметры в любое время, в дополнение к любым body-параметрам.
Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
Поскольку по умолчанию отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
```Python
q: Union[str, None] = None
@ -112,7 +112,7 @@ q: str | None = None
Например:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[27] *}
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
/// info | Информация
@ -122,11 +122,11 @@ q: str | None = None
## Добавление одного body-параметра
Предположим, у вас есть только один body-параметр `item` из Pydantic модели `Item`.
Предположим, у вас есть только один body-параметр `item` из Pydantic-модели `Item`.
По умолчанию, **FastAPI** ожидает получить тело запроса напрямую.
Но если вы хотите чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, также как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`:
Но если вы хотите, чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, также как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`:
```Python
item: Item = Body(embed=True)

15
docs/ru/docs/tutorial/cors.md

@ -18,17 +18,17 @@
Допустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`).
Затем браузер отправит бэкенду HTTP-запрос `OPTIONS`, и если бэкенд вернёт соответствующие заголовки для авторизации взаимодействия с другим источником (`http://localhost:8080`), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд.
Затем браузер отправит бэкенду HTTP-запрос `OPTIONS`, и если бэкенд вернёт соответствующие HTTP-заголовки для авторизации взаимодействия с другим источником (`http://localhost:8080`), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд.
Чтобы это работало, у бэкенда должен быть список "разрешённых источников" ("allowed origins").
В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд работал корректно.
## Подстановочный символ `"*"`
## Подстановочные символы
В качестве списка источников можно указать подстановочный символ `"*"` ("wildcard"), чтобы разрешить любые источники.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, HTTP-заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п.
Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.
@ -42,7 +42,7 @@
Вы также можете указать, разрешает ли ваш бэкенд использование:
* Учётных данных (включая заголовки Authorization, куки и т.п.).
* Учётных данных (включая HTTP-заголовки Authorization, куки и т.п.).
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
@ -56,7 +56,10 @@
* `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_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`.
@ -64,7 +67,7 @@
### CORS-запросы с предварительной проверкой
Это любые `OPTIONS` запросы с заголовками `Origin` и `Access-Control-Request-Method`.
Это любые `OPTIONS` запросы с HTTP-заголовками `Origin` и `Access-Control-Request-Method`.
В этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` в информационных целях.

97
docs/ru/docs/tutorial/extra-models.md

@ -1,36 +1,44 @@
# Дополнительные модели
В продолжение прошлого примера будет уже обычным делом иметь несколько связанных между собой моделей.
В продолжение прошлого примера, будет обычным делом иметь несколько связанных между собой моделей.
Это особенно применимо в случае моделей пользователя, потому что:
Это особенно касается моделей пользователя, потому что:
* **Модель для ввода** должна иметь возможность содержать пароль.
* **Модель для вывода** не должна содержать пароль.
* **Модель для базы данных**, возможно, должна содержать хэшированный пароль.
* **Модель для базы данных**, вероятно, должна содержать хэшированный пароль.
/// danger | Внимание
Никогда не храните пароли пользователей в чистом виде. Всегда храните "безопасный хэш", который вы затем сможете проверить.
Никогда не храните пароли пользователей в чистом виде. Всегда храните "защищенный хэш", который вы затем сможете проверять.
Если вам это не знакомо, вы можете узнать про "хэш пароля" в [главах о безопасности](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
Если вы не знаете, вы узнаете, что такое "хэш пароля" в [главах о безопасности](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
///
## Множественные модели
Ниже изложена основная идея того, как могут выглядеть эти модели с полями для паролей, а также описаны места, где они используются:
Ниже представлено общее представление о том, как могут выглядеть эти модели с их полями для паролей и где они используются:
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
### Про `**user_in.dict()`
/// info | Информация
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он устарел (но все еще поддерживается) и был переименован в `.model_dump()`.
В приведенных примерах используется `.dict()` для совместимости с Pydantic v1, но вам следует использовать `.model_dump()`, если вы можете использовать Pydantic v2.
///
### О `**user_in.dict()`
#### `.dict()` из Pydantic
`user_in` - это Pydantic-модель класса `UserIn`.
`user_in` — это Pydantic модель класса `UserIn`.
У Pydantic-моделей есть метод `.dict()`, который возвращает `dict` с данными модели.
У Pydantic моделей есть метод `.dict()`, который возвращает `dict` с данными модели.
Поэтому, если мы создадим Pydantic-объект `user_in` таким способом:
Поэтому, если мы создадим Pydantic объект `user_in` таким образом:
```Python
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
@ -42,7 +50,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
user_dict = user_in.dict()
```
то теперь у нас есть `dict` с данными модели в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
то теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic модели).
И если мы вызовем:
@ -50,7 +58,7 @@ user_dict = user_in.dict()
print(user_dict)
```
мы можем получить `dict` с такими данными:
мы бы получили Python `dict` с:
```Python
{
@ -63,15 +71,15 @@ print(user_dict)
#### Распаковка `dict`
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
Если мы возьмем `dict`, аналогичный `user_dict`, и передадим его в функцию (или класс) с `**user_dict`, Python его "распакует". Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
Поэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:
Поэтому, продолжая с `user_dict`, написание следующего кода:
```Python
UserInDB(**user_dict)
```
Будет работать так же, как примерно такой код:
будет аналогично следующему:
```Python
UserInDB(
@ -82,7 +90,7 @@ UserInDB(
)
```
Или, если для большей точности мы напрямую используем `user_dict` с любым потенциальным содержимым, то этот пример будет выглядеть так:
Или, более точно, используя `user_dict` напрямую с любым потенциальным содержимым:
```Python
UserInDB(
@ -93,7 +101,7 @@ UserInDB(
)
```
#### Pydantic-модель из содержимого другой модели
#### Pydantic модель из содержимого другой модели
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
@ -102,25 +110,25 @@ user_dict = user_in.dict()
UserInDB(**user_dict)
```
будет равнозначен такому:
будет равнозначен следующему:
```Python
UserInDB(**user_in.dict())
```
...потому что `user_in.dict()` - это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` и ставим перед ним `**`.
...потому что `user_in.dict()` — это `dict`, и затем мы заставляем Python его "распаковать" при передаче в `UserInDB`, поставив впереди `**`.
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
Таким образом, мы получаем Pydantic модель на основе данных из другой Pydantic модели.
#### Распаковка `dict` и дополнительные именованные аргументы
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
И затем добавляя дополнительный именованный аргумент `hashed_password=hashed_password`, как в:
```Python
UserInDB(**user_in.dict(), hashed_password=hashed_password)
```
... то мы получим что-то подобное:
...это будет равноценно:
```Python
UserInDB(
@ -134,78 +142,81 @@ UserInDB(
/// warning | Предупреждение
Цель использованных в примере вспомогательных функций - не более чем демонстрация возможных операций с данными, но, конечно, они не обеспечивают настоящую безопасность.
Используемые в примере вспомогательные функции `fake_password_hasher` и `fake_save_user` предназначены только для демонстрации возможного потока данных, но, конечно, они не обеспечивают реальной безопасности.
///
## Сократите дублирование
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
Сокращение дублирования кода — одна из основных идей в **FastAPI**.
Поскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.
Поскольку дублирование кода увеличивает шансы на баги, проблемы с безопасностью, проблемы с десинхронизацией кода (когда вы обновляете код в одном месте, но не обновляете в другом) и т.д.
А все описанные выше модели используют много общих данных и дублируют названия атрибутов и типов.
А все описанные выше модели совместно используют много данных и дублируют названия атрибутов и типов.
Мы можем это улучшить.
Мы можем определить модель `UserBase`, которая будет базовой для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию, и т.п.).
Мы можем объявить модель `UserBase`, которая будет использоваться в качестве основы для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию и т.п.).
Все операции конвертации, валидации, документации, и т.п. будут по-прежнему работать нормально.
Все операции конвертации данных, валидации, составления документации и прочего будут по-прежнему работать нормально.
В этом случае мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля):
Таким образом, мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля):
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
## `Union` или `anyOf`
Вы можете определить ответ как `Union` из двух типов. Это означает, что ответ должен соответствовать одному из них.
Вы можете объявить, что ответ должен быть `Union` из двух или более типов, это значит, что ответ может соответствовать любому из них.
Он будет определён в OpenAPI как `anyOf`.
Это будет определено в OpenAPI как `anyOf`.
Для этого используйте стандартные аннотации типов в Python <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
Для этого используйте стандартную аннотацию типа в Python <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
/// note | Примечание
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>, сначала указывайте наиболее детальные типы, затем менее детальные. В примере ниже более детальный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
При определении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>, сначала указывайте самый конкретный тип, а затем менее конкретный тип. В примере ниже более конкретный `PlaneItem` идет перед `CarItem` в `Union[PlaneItem, CarItem]`.
///
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
### `Union` в Python 3.10
В этом примере мы передаём `Union[PlaneItem, CarItem]` в качестве значения аргумента `response_model`.
В этом примере мы передаем `Union[PlaneItem, CarItem]` как значение аргумента `response_model`.
Поскольку мы передаём его как **значение аргумента** вместо того, чтобы поместить его в **аннотацию типа**, нам придётся использовать `Union` даже в Python 3.10.
Поскольку мы передаем его как **значение аргумента**, а не как часть **аннотации типа**, мы должны использовать `Union` даже в Python 3.10.
Если оно было бы указано в аннотации типа, то мы могли бы использовать вертикальную черту как в примере:
Если бы это было в аннотации типа, мы могли бы использовать вертикальную черту, например:
```Python
some_variable: PlaneItem | CarItem
```
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
Но если мы поместим это в присваивание `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
## Список моделей
Таким же образом вы можете определять ответы как списки объектов.
Аналогично, вы можете объявить ответы в виде списков объектов.
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
Для этого используйте стандартный `typing.List` из Python (или просто `list` в Python 3.9 и выше):
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
## Ответ с произвольным `dict`
Вы также можете определить ответ, используя произвольный одноуровневый `dict` и определяя только типы ключей и значений без использования Pydantic-моделей.
Вы также можете объявить ответ, используя произвольный одноуровневый `dict`, задавая только типы ключей и значений без использования Pydantic модели.
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
Это полезно, если вы не знаете заранее допустимые названия полей/атрибутов (которые понадобятся при использовании Pydantic модели).
В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше):
В этом случае можно использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше):
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
## Резюме
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
Используйте несколько Pydantic моделей и свободно применяйте наследование в каждом случае.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.

88
docs/ru/docs/tutorial/first-steps.md

@ -6,31 +6,47 @@
Скопируйте в файл `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">&apos;/home/user/code/awesomeapp&apos;</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>
В окне вывода появится следующая строка:
@ -100,7 +116,7 @@ OpenAPI описывает схему API. Эта схема содержит о
```JSON
{
"openapi": "3.0.2",
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
@ -149,36 +165,6 @@ OpenAPI описывает схему API. Эта схема содержит о
Переменная `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` будет таким:
<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>
### Шаг 3: определите *операцию пути (path operation)*
#### Путь (path)
@ -197,7 +183,7 @@ https://example.com/items/foo
/items/foo
```
/// info | Дополнительная иформация
/// info | Дополнительная информация
Термин "path" также часто называется "endpoint" или "route".
@ -249,7 +235,7 @@ https://example.com/items/foo
* путь `/`
* использующих <abbr title="HTTP GET метод"><code>get</code> операцию</abbr>
/// info | `@decorator` Дополнительная информация
/// info | `@decorator` Info
Синтаксис `@something` в Python называется "декоратор".
@ -310,9 +296,9 @@ https://example.com/items/foo
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | Технические детали
/// note
Если не знаете в чём разница, посмотрите [Конкурентность: *"Нет времени?"*](../async.md#_1){.internal-link target=_blank}.
Если не знаете в чём разница, посмотрите [Асинхронность: *"Нет времени?"*](../async.md#_1){.internal-link target=_blank}.
///
@ -332,4 +318,4 @@ https://example.com/items/foo
* Создаём экземпляр `app`.
* Пишем **декоратор операции пути** (такой как `@app.get("/")`).
* Пишем **функцию операции пути** (`def root(): ...`).
* Запускаем сервер в режиме разработки (`uvicorn main:app --reload`).
* Запускаем сервер в режиме разработки с использованием команды `fastapi dev`.

6
docs/ru/docs/tutorial/handling-errors.md

@ -11,7 +11,7 @@
* Элемент, к которому клиент пытался получить доступ, не существует.
* и т.д.
В таких случаях обычно возвращается **HTTP-код статуса ответа** в диапазоне **400** (от 400 до 499).
В таких случаях обычно возвращается **HTTP статус-код** в диапазоне **400** (от 400 до 499).
Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно.
@ -232,9 +232,7 @@ path -> item_id
Класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`.
Единственное отличие заключается в том, что `HTTPException` от **FastAPI** позволяет добавлять заголовки, которые будут включены в ответ.
Он необходим/используется внутри системы для OAuth 2.0 и некоторых утилит безопасности.
Единственное отличие заключается в том, что исключение **FastAPI** `HTTPException` принимает любые данные, преобразуемые в JSON, в поле `detail`, в то время как исключение Starlette `HTTPException` принимает только строки.
Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своем коде.

64
docs/ru/docs/tutorial/index.md

@ -1,6 +1,6 @@
# Учебник - Руководство пользователя
В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций.
В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций.
Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API.
@ -12,18 +12,44 @@
Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы 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="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 🚀
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>
Logs:
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
<b>[</b><font color="#4E9A06">&apos;/home/user/code/awesomeapp&apos;</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>
@ -38,37 +64,25 @@ $ uvicorn main:app --reload
Первый шаг — установить FastAPI.
Для руководства вы, возможно, захотите установить его со всеми дополнительными зависимостями и функциями:
Убедитесь, что вы создаете [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируете его и затем **устанавливаете FastAPI**:
<div class="termy">
```console
$ pip install "fastapi[all]"
$ pip install "fastapi[standard]"
---> 100%
```
</div>
...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код.
/// note | Технические детали
Вы также можете установить его по частям.
Это то, что вы, вероятно, сделаете, когда захотите развернуть свое приложение в рабочей среде:
```
pip install fastapi
```
Также установите `uvicorn` для работы в качестве сервера:
Когда вы устанавливаете с помощью `pip install "fastapi[standard]"`, это включает некоторые стандартные необязательные зависимости, включая `fastapi-cloud-cli`, который позволяет развернуть приложение на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
```
pip install "uvicorn[standard]"
```
Если вы не хотите иметь эти необязательные зависимости, вы можете вместо этого выполнить установку с помощью `pip install fastapi`.
И то же самое для каждой из необязательных зависимостей, которые вы хотите использовать.
Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, вы можете установить их с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
///

47
docs/ru/docs/tutorial/middleware.md

@ -1,10 +1,8 @@
# Middleware (Промежуточный слой)
Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
"Middleware" это функция, которая выполняется с каждым запросом до его обработки какой-либо конкретной *операцией пути*.
А также с каждым ответом перед его возвращением.
Вы можете добавить middleware (промежуточный слой) в **FastAPI** приложение.
"Middleware" это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением.
* Она принимает каждый поступающий **запрос**.
* Может что-то сделать с этим **запросом** или выполнить любой нужный код.
@ -17,19 +15,19 @@
Если у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware.
Если у вас имеются некие фоновые задачи (см. документацию), то они будут запущены после middleware.
Если у вас имеются некие фоновые задачи (рассмотренные в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}), они будут запущены *после* всех middleware.
///
## Создание middleware
Для создания middleware используйте декоратор `@app.middleware("http")`.
Для создания middleware используйте декоратор `@app.middleware("http")` перед функцией.
Функция middleware получает:
* `request` (объект запроса).
* Функцию `call_next`, которая получает `request` в качестве параметра.
* Эта функция передаёт `request` соответствующей *операции пути*.
* Функцию `call_next`, которая принимает `request` в качестве параметра.
* Эта функция передает `request` соответствующей *операции пути*.
* Затем она возвращает ответ `response`, сгенерированный *операцией пути*.
* Также имеется возможность видоизменить `response`, перед тем как его вернуть.
@ -37,9 +35,9 @@
/// tip | Примечание
Имейте в виду, что можно добавлять свои собственные заголовки <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">при помощи префикса 'X-'</a>.
Имейте в виду, что собственные проприетарные заголовки можно добавлять <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">при помощи префикса 'X-'</a>.
Если же вы хотите добавить собственные заголовки, которые клиент сможет увидеть в браузере, то вам потребуется добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.
Если же у вас есть собственные заголовки, которые клиент в браузере должен видеть, вам нужно добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.
///
@ -47,13 +45,13 @@
Вы также можете использовать `from starlette.requests import Request`.
**FastAPI** предоставляет такой доступ для удобства разработчиков. Но, на самом деле, это `Request` из Starlette.
**FastAPI** предоставляет это для удобства разработчиков. Но на самом деле это `Request` из Starlette.
///
### До и после `response`
Вы можете добавить код, использующий `request` до передачи его какой-либо *операции пути*.
Вы можете добавить код, использующий `request` до передачи его какой-либо *операцией пути*.
А также после формирования `response`, до того, как вы его вернёте.
@ -63,10 +61,33 @@
/// tip | Примечание
Мы используем <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a> вместо `time.time()` для обеспечения большей точности наших примеров. 🤓
Мы используем <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a> вместо `time.time()`, потому что это может быть более точным для таких случаев. 🤓
///
## Порядок выполнения нескольких middleware
Когда вы добавляете несколько middleware с использованием декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, формируя стек. Последнее добавленное middleware становится самым *внешним*, а первое — самым *внутренним*.
На пути **запроса**, самое *внешнее* middleware выполняется первым.
На пути **ответа** оно выполняется последним.
Например:
```Python
app.add_middleware(MiddlewareA)
app.add_middleware(MiddlewareB)
```
Это приводит к следующему порядку выполнения:
* **Запрос**: MiddlewareB → MiddlewareA → маршрут
* **Ответ**: маршрут → MiddlewareA → MiddlewareB
Такое поведение с упаковкой обеспечивает выполнение middleware в предсказуемом и контролируемом порядке.
## Другие middleware
О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.

354
docs/ru/docs/tutorial/query-params-str-validations.md

@ -2,60 +2,48 @@
**FastAPI** позволяет определять дополнительную информацию и валидацию для ваших параметров.
Давайте рассмотрим следующий пример:
Рассмотрим этот пример приложения:
{* ../../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 определит параметр `q` как необязательный, потому что его значение по умолчанию `= None`.
FastAPI определяет, что значение `q` не является обязательным благодаря значению по умолчанию `= None`.
`Union` в `Union[str, None]` позволит редактору кода оказать вам лучшую поддержку и найти ошибки.
`str | None` позволяет вашему редактору кода предоставлять лучшую поддержку и обнаруживать ошибки.
///
## Расширенная валидация
## Дополнительная валидация
Добавим дополнительное условие валидации параметра `q` - **длина строки не более 50 символов** (условие проверяется всякий раз, когда параметр `q` не является `None`).
Мы собираемся обеспечить, что даже если `q` является необязательным, в случаях, когда он предоставлен, **его длина не превышает 50 символов**.
### Импорт `Query` и `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+
В версиях Python ниже Python 3.9 `Annotation` импортируется из `typing_extensions`.
/// info | Дополнительная информация
Эта библиотека будет установлена вместе с FastAPI.
FastAPI добавил поддержку `Annotated` (и начал рекомендовать его использование) в версии 0.95.0.
```Python hl_lines="3-4"
{!> ../../docs_src/query_params_str_validations/tutorial002_an.py!}
```
Если у вас более старая версия, при попытке использования `Annotated` вы получите ошибки. Убедитесь, что вы [Обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`.
////
///
## `Annotated` как тип для query-параметра `q`
## Использование `Annotated` в типе параметра `q`
Помните, как ранее я говорил об 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}?
Пришло время использовать их в FastAPI. 🚀
Теперь пришло время использовать это в FastAPI. 🚀
У нас была аннотация следующего типа:
У нас была аннотация типа:
//// tab | Python 3.10+
@ -73,7 +61,7 @@ q: Union[str, None] = None
////
Вот что мы получим, если обернём это в `Annotated`:
Что мы сделаем: обернём это в `Annotated`, таким образом:
//// tab | Python 3.10+
@ -91,117 +79,92 @@ q: Annotated[Union[str, None]] = None
////
Обе эти версии означают одно и тоже. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`.
Обе этих версии означают одно и то же, `q` это параметр, который может быть `str` или `None`, и по умолчанию он будет `None`.
Давайте повеселимся. 🎉
Теперь перейдём к интересному. 🎉
## Добавим `Query` в `Annotated` для query-параметра `q`
## Добавим `Query` в `Annotated` для параметра `q`
Теперь, когда у нас есть `Annotated`, где мы можем добавить больше метаданных, добавим `Query` со значением параметра `max_length` равным 50:
Теперь, когда у нас есть этот `Annotated`, куда мы можем поместить больше информации (в данном случае — дополнительную валидацию), добавим внутрь `Annotated` `Query`, и установим параметр `max_length` равным `50`:
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
Обратите внимание, что значение по умолчанию всё ещё `None`, так что параметр остаётся необязательным.
Обратите внимание, что значение по умолчанию все ещё `None`, так что параметр остается необязательным.
Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим извлечь это значение из параметров query-запроса (что произойдёт в любом случае 🤷), и что мы хотим иметь **дополнительные условия валидации** для этого значения (для чего мы и делаем это - чтобы получить дополнительную валидацию). 😎
Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим иметь **дополнительную валидацию** для этого значения, мы хотим, чтобы оно содержало максимум 50 символов. 😎
Теперь FastAPI:
/// tip | Подсказка
* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов
* Показывает **исчерпывающую ошибку** (будет описание местонахождения ошибки и её причины) для клиента в случаях, когда данные не валидны
* **Задокументирует** параметр в схему OpenAPI *операции пути* (что будет отображено в **UI автоматической документации**)
Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают такие же аргументы, как и `Query()`.
## Альтернативный (устаревший) способ задать `Query` как значение по умолчанию
///
Теперь FastAPI будет:
* **Валидировать** данные, удостоверяясь, что максимальная длина составляет 50 символов
* Показать **четкую ошибку** клиенту, когда данные не валидны
* **Документировать** параметр в схеме OpenAPI операции пути (таким образом, он будет отображаться в **UI автоматической документации**)
В предыдущих версиях FastAPI (ниже <abbr title="ранее 2023-03">0.95.0</abbr>) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню.
## Альтернативный (устаревший) способ: `Query` как значение по умолчанию
До версии <abbr title="до 2023-03">0.95.0</abbr> FastAPI требовалось использовать `Query` как значение по умолчанию для вашего параметра, а не помещать его в `Annotated`. Вероятно, вы увидите такой код, поэтому я объясню его вам.
/// tip | Подсказка
При написании нового кода и везде где это возможно, используйте `Annotated`, как было описано ранее. У этого способа есть несколько преимуществ (о них дальше) и никаких недостатков. 🍰
Для нового кода и везде где это возможно, используйте `Annotated` как описано выше. У этого способа есть несколько преимуществ (описаны ниже) и нет недостатков. 🍰
///
Вот как вы могли бы использовать `Query()` в качестве значения по умолчанию параметра вашей функции, установив для параметра `max_length` значение 50:
Так вы бы использовали `Query()` в качестве значения по умолчанию для параметра функции, устанавливая параметр `max_length` равным 50:
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
В таком случае (без использования `Annotated`), мы заменили значение по умолчанию с `None` на `Query()` в функции. Теперь нам нужно установить значение по умолчанию для query-параметра `Query(default=None)`, что необходимо для тех же целей, как когда ранее просто указывалось значение по умолчанию (по крайней мере, для FastAPI).
Так как в этом случае (без использования `Annotated`) нам приходится заменять значение по умолчанию `None` в функции на `Query()`, теперь нам нужно установить значение по умолчанию с параметром `Query(default=None)`, это выполняет ту же цель, как определение значения по умолчанию (по крайней мере, для FastAPI).
Таким образом:
```Python
q: Union[str, None] = Query(default=None)
```
...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
```Python
q: Union[str, None] = None
```
И для Python 3.10 и выше:
```Python
q: str | None = Query(default=None)
```
...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
...делает параметр необязательным со значением по умолчанию `None`, чем эквивалентен:
```Python
q: str | None = None
```
Но он явно объявляет его как query-параметр.
/// info | Дополнительная информация
Но версия `Query` явно объявляет его как query-параметр.
Запомните, важной частью объявления параметра как необязательного является:
Затем, мы можем передать больше параметров в `Query`. В данном случае, это параметр `max_length`, который применяется к строкам:
```Python
= None
q: str | None = Query(default=None, max_length=50)
```
или:
Это позволит валидировать данные, показать четкую ошибку когда данные не валидны, и задокументировать параметр в операции пути схемы OpenAPI.
```Python
= Query(default=None)
```
### Использование `Query` как значения по умолчанию или в `Annotated`
так как `None` указан в качестве значения по умолчанию, параметр будет **необязательным**.
Имейте в виду, что при использовании `Query` внутри `Annotated`, вы не можете использовать параметр `default` у `Query`.
`Union[str, None]` позволит редактору кода оказать вам лучшую поддержку. Но это не то, на что обращает внимание FastAPI для определения необязательности параметра.
Вместо этого, используйте фактическое значение по умолчанию параметра функции. Иначе это будет некорректно.
///
Теперь, мы можем указать больше параметров для `Query`. В данном случае, параметр `max_length` применяется к строкам:
```Python
q: Union[str, None] = Query(default=None, max_length=50)
```
Входные данные будут проверены. Если данные недействительны, тогда будет указано на ошибку в запросе (будет описание местонахождения ошибки и её причины). Кроме того, параметр задокументируется в схеме OpenAPI данной *операции пути*.
### Использовать `Query` как значение по умолчанию или добавить в `Annotated`
Когда `Query` используется внутри `Annotated`, вы не можете использовать параметр `default` у `Query`.
Вместо этого, используйте обычное указание значения по умолчанию для параметра функции. Иначе, это будет несовместимо.
Следующий пример не рабочий:
Например, это неправильно:
```Python
q: Annotated[str, Query(default="rick")] = "morty"
```
...потому что нельзя однозначно определить, что именно должно быть значением по умолчанию: `"rick"` или `"morty"`.
...потому что непонятно, какое именно значение должно быть по умолчанию: `"rick"` или `"morty"`.
Вам следует использовать (предпочтительно):
Так что, лучше всего использовать:
```Python
q: Annotated[str, Query()] = "rick"
```
...или как в старом коде, который вам может попасться:
...или в старых кодовых базах можно встретить:
```Python
q: str = Query(default="rick")
@ -209,55 +172,69 @@ q: str = Query(default="rick")
### Преимущества `Annotated`
**Рекомендуется использовать `Annotated`** вместо значения по умолчанию в параметрах функции, потому что так **лучше** по нескольким причинам. 🤓
**Рекомендуется использовать `Annotated`** вместо значения по умолчанию в параметрах функции, поскольку это **лучше** по нескольким причинам. 🤓
Значение **по умолчанию** у **параметров функции** - это **действительно значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌
Значение **по умолчанию** у **параметров функции** это **действительное значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌
Вы можете **вызвать** ту же функцию в **иных местах** без FastAPI, и она **сработает как ожидается**. Если это **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке. **Python** также укажет на ошибку, если вы вызовете функцию без передачи ей обязательного параметра.
Вы можете **вызвать** ту же функцию в **других местах** без FastAPI, и она **будет работать, как и ожидалось**. Если параметр является **обязательным** (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** также предупредит, если вы попытаетесь вызвать её без передачи этого обязательного параметра.
Если вы вместо `Annotated` используете **(устаревший) стиль значений по умолчанию**, тогда при вызове этой функции без FastAPI в **другом месте** вам необходимо **помнить** о передаче аргументов функции, чтобы она работала корректно. В противном случае, значения будут отличаться от тех, что вы ожидаете (например, `QueryInfo` или что-то подобное вместо `str`). И ни ваш редактор кода, ни Python не будут жаловаться на работу этой функции, только когда вычисления внутри дадут сбой.
Когда вы не используете `Annotated`, а вместо этого используете **(устаревший) стиль значений по умолчанию**, если вы вызовете эту функцию без FastAPI в **других местах**, вам придется **помнить** об аргументах, которые нужно передать в функцию, чтобы она работала корректно, иначе значения будут отличаться от ожидаемых (например, `QueryInfo` или что-то похожее вместо `str`). И ваш редактор кода не сообщит об ошибке, и Python не сообщит об ошибке при выполнении функции, только когда выполнение операции внутри несовместимо.
Так как `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>. 🚀
## Больше валидации
## Добавим больше валидаций
Вы также можете добавить параметр `min_length`:
Также можно добавить параметр `min_length`:
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
## Регулярные выражения
Вы можете определить <abbr title="Регулярное выражение, regex или regexp - это последовательность символов, определяющая шаблон для строк.">регулярное выражение</abbr>, которому должен соответствовать параметр:
Вы можете определить <abbr title="Регулярное выражение, regex или regexp - это последовательность символов, определяющая шаблон для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
Данное регулярное выражение проверяет, что полученное значение параметра:
Это конкретное регулярное выражение проверяет, что полученное значение параметра:
* `^`: начинается с следующих символов, не имеет символов перед этим.
* `fixedquery`: содержит точное значение `fixedquery`.
* `$`: заканчивается здесь, не имеет символов после `fixedquery`.
Если вас пугает тема **"регулярных выражений"**, не переживайте. Это сложная тема для многих людей. Вы можете реализовать множество вещей без использования регулярных выражений.
Теперь вы знаете, что когда они вам понадобятся, вы можете использовать их в **FastAPI**.
* `^`: начало строки.
* `fixedquery`: в точности содержит строку `fixedquery`.
* `$`: конец строки, не имеет символов после `fixedquery`.
### Pydantic v1 `regex` вместо `pattern`
Не переживайте, если **"регулярное выражение"** вызывает у вас трудности. Это достаточно сложная тема для многих людей. Вы можете сделать множество вещей без использования регулярных выражений.
До версии Pydantic 2 и FastAPI 0.100.0, параметр назывался `regex`, а не `pattern`, но теперь он устарел.
Но когда они вам понадобятся, и вы закончите их освоение, то не будет проблемой использовать их в **FastAPI**.
Всё ещё можно увидеть код, где это используется:
//// tab | Pydantic v1
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
////
Но это устаревший метод и его нужно обновить для использования нового параметра `pattern`. 🤓
## Значения по умолчанию
Вы точно также можете указать любое значение `по умолчанию`, как ранее указывали `None`.
Вы, конечно, можете использовать значения по умолчанию, отличные от `None`.
Например, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`:
Предположим, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`:
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
/// note | Технические детали
Наличие значения по умолчанию делает параметр необязательным.
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.
///
## Обязательный параметр
## Обязательные параметры
Когда вам не требуется дополнительная валидация или дополнительные метаданные для параметра запроса, вы можете сделать параметр `q` обязательным просто не указывая значения по умолчанию. Например:
Когда нам не требуется указывать дополнительные валидации или метаданные, мы можем сделать query-параметр `q` обязательным, просто не указывая значение по умолчанию, например:
```Python
q: str
@ -266,60 +243,46 @@ q: str
вместо:
```Python
q: Union[str, None] = None
q: str | None = None
```
Но у нас query-параметр определён как `Query`. Например:
Но мы определяем его с помощью `Query`, например, так:
//// tab | Annotated
```Python
q: Annotated[Union[str, None], Query(min_length=3)] = None
```
////
//// tab | без Annotated
```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`
Вы можете определить, что параметр может принимать `None`, но всё ещё является обязательным. Это может потребоваться для того, чтобы пользователи явно указали параметр, даже если его значение будет `None`.
Вы можете определить, что параметр может принимать `None`, но он всё равно является обязательным. Это заставит клиентов отправлять значение, даже если оно `None`.
Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но также указать `default=...`:
Для этого вы можете объявить, что `None` является допустимым типом, но просто не указывайте значение по умолчанию:
{* ../../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` можно указать, что он принимает список значений (множество значений).
Когда вы явным образом определяете query-параметр с помощью `Query`, вы также можете указать его как принимающий список значений, или, проще говоря, принимающий множество значений.
Например, query-параметр `q` может быть указан в URL несколько раз. И если вы ожидаете такой формат запроса, то можете указать это следующим образом:
Например, чтобы объявить query-параметр `q`, который может появляться несколько раз в URL, вы можете написать так:
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
Затем, получив такой URL:
Затем, с URL вида:
```
http://localhost:8000/items/?q=foo&q=bar
```
вы бы получили несколько значений (`foo` и `bar`), которые относятся к параметру `q`, в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
вы получите множество значений *query-параметров* `q` (`foo` и `bar`) в виде `list` Python внутри вашей *функции обработки пути*, в *функциональном параметре* `q`.
Таким образом, ответ на этот URL будет:
@ -338,23 +301,23 @@ http://localhost:8000/items/?q=foo&q=bar
///
Интерактивная документация API будет обновлена соответствующим образом, где будет разрешено множество значений:
Интерактивный UI документации API будет обновлён соответствующим образом, чтобы разрешать множество значений:
<img src="/img/tutorial/query-params-str-validations/image02.png">
### Query-параметр со множеством значений по умолчанию
### Множество значений для query-параметра с дефолтными значениями
Вы также можете указать тип `list` со списком значений по умолчанию на случай, если вам их не предоставят:
Вы также можете определить список значений по умолчанию, если они не предоставлены:
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
Если вы перейдёте по ссылке:
Если вы перейдете по такому URL:
```
http://localhost:8000/items/
```
значение по умолчанию для `q` будет: `["foo", "bar"]` и ответом для вас будет:
значение по умолчанию для `q` будет: `["foo", "bar"]` и ответ будет:
```JSON
{
@ -367,45 +330,45 @@ http://localhost:8000/items/
#### Использование `list`
Вы также можете использовать `list` напрямую вместо `List[str]` (или `list[str]` в Python 3.9+):
Вы также можете использовать `list` напрямую вместо `list[str]`:
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note | Технические детали
Запомните, что в таком случае, FastAPI не будет проверять содержимое списка.
Имейте в виду, что в таком случае, FastAPI не будет проверять содержимое списка.
Например, для List[int] список будет провалидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
Например, `list[int]` проверяет (и документирует), что содержимое списка - целые числа. Но просто `list` такую проверку не проводит.
///
## Больше метаданных
Вы можете добавить больше информации об query-параметре.
Вы можете добавить больше информации о параметре.
Указанная информация будет включена в генерируемую OpenAPI документацию и использована в пользовательском интерфейсе и внешних инструментах.
Эта информация будет включена в сгенерированный OpenAPI и использована интерфейсами документации и внешними инструментами.
/// note | Технические детали
Имейте в виду, что разные инструменты могут иметь разные уровни поддержки OpenAPI.
Имейте в виду, что разные инструменты могут иметь различные уровни поддержки OpenAPI.
Некоторые из них могут не отображать (на данный момент) всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
Некоторые из них могут все еще не показывать всю дополнительную информацию, хотя в большинстве случаев, недостающая функция уже запланирована к разработке.
///
Вы можете указать название query-параметра, используя параметр `title`:
Вы можете добавить `title`:
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
Добавить описание, используя параметр `description`:
И `description`:
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
## Псевдонимы параметров
Представьте, что вы хотите использовать query-параметр с названием `item-query`.
Представьте, что вы хотите использовать параметр с названием `item-query`.
Например:
Как в следующем примере:
```
http://127.0.0.1:8000/items/?item-query=foobaritems
@ -415,19 +378,19 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
Наиболее похожее валидное имя `item_query`.
Но вам всё равно необходим `item-query`...
Но вам всё равно необходимо использовать `item-query`
Тогда вы можете объявить `псевдоним`, и этот псевдоним будет использоваться для поиска значения параметра запроса:
Тогда вы можете объявить `псевдоним`, и именно он будет использован для поиска значения параметра:
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
## Устаревшие параметры
Предположим, вы больше не хотите использовать какой-либо параметр.
Теперь допустим, что вам больше не нравится этот параметр.
Вы решили оставить его, потому что клиенты всё ещё им пользуются. Но вы хотите отобразить это в документации как <abbr title="устарело, не рекомендуется использовать">устаревший функционал</abbr>.
Вы должны оставить его на некоторое время, поскольку есть клиенты, которые его используют, но вы хотите, чтобы в документации он ясно показывался как <abbr title="устарел, рекомендуется избегать его использования">устаревший</abbr>.
Тогда для `Query` укажите параметр `deprecated=True`:
Тогда передайте параметр `deprecated=True` метод `Query`:
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
@ -435,30 +398,93 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
<img src="/img/tutorial/query-params-str-validations/image01.png">
## Исключить из OpenAPI
## Исключение параметров из OpenAPI
Чтобы исключить query-параметр из генерируемой OpenAPI схемы (а также из системы автоматической генерации документации), укажите в `Query` параметр `include_in_schema=False`:
Чтобы исключить query-параметр из сгенерированной схемы OpenAPI (и таким образом, из системы автоматической документации), установите параметр `include_in_schema` в `Query` равным `False`:
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Пользовательская валидация
Могут быть случаи, когда вам нужно сделать какую-либо **пользовательскую валидацию**, которую нельзя осуществить с помощью вышеуказанных параметров.
В этих случаях вы можете использовать **функцию пользовательского валидатора**, которая будет применяться после нормальной валидации (например, после проверки, что значение `str`).
Это можно сделать, используя <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`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 означает Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма по <abbr title="IMDB (Internet Movie Database) - это сайт с информацией о фильмах">IMDB</abbr>:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
/// info | Информация
Это доступно в версии Pydantic 2 или выше. 😎
///
/// tip | Подсказка
Если вам нужно выполнить какую-либо валидацию, которая требует связи с каким-либо **внешним компонентом**, например, базой данных или другим API, вам следует вместо этого использовать **FastAPI Dependencies**, вы узнаете о них позже.
Эти пользовательские валидаторы предназначены для вещей, которые можно проверить только с использованием **тех же данных**, предоставленных в запросе.
///
### Понять этот код
Основным пунктом является использование **`AfterValidator` с функцией внутри `Annotated`**. Не стесняйтесь пропустить эту часть. 🤸
---
Но если вам интересно рассмотреть этот пример кода, который все еще вызывает интерес, вот несколько дополнительных деталей.
#### Строка с `value.startswith()`
Заметили? Строка, использующая `value.startswith()`, может принимать кортеж, и проверит каждое значение в кортеже:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
#### Случайный элемент
С `data.items()` мы получаем <abbr title="Что-то, что можно использовать в цикле for, как например, list, set и так далее.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
Мы преобразуем этот итерируемый объект в настоящий `list` с `list(data.items())`.
Тогда, с помощью `random.choice()` можем получить **случайное значение** из списка, так мы получаем кортеж `(id, name)`. Он будет чем-то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
Затем мы **присваиваем эти два значения** из кортежа переменным `id` и `name`.
Так что, если пользователь не предоставил ID элемента, они получат случайную рекомендацию.
...мы выполняем все это в **одной простой строке**. 🤯 Разве Python не потрясающий? 🐍
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
## Резюме
Вы можете объявлять дополнительные правила валидации и метаданные для ваших параметров запроса.
Вы можете объявлять дополнительные валидации и метаданные для ваших параметров.
Общие метаданные:
Общие валидации и метаданные:
* `alias`
* `title`
* `description`
* `deprecated`
* `include_in_schema`
Специфичные правила валидации для строк:
Валидации специфичны для строк:
* `min_length`
* `max_length`
* `regex`
* `pattern`
Пользовательские валидации с использованием `AfterValidator`.
В рассмотренных примерах показано объявление правил валидации для строковых значений `str`.
В этих примерах вы видели, как объявлять валидации для значений `str`.
В следующих главах вы увидете, как объявлять правила валидации для других типов (например, чисел).
Смотрите следующие главы, чтобы узнать, как объявлять валидации для других типов, таких как числа.

12
docs/ru/docs/tutorial/response-status-code.md

@ -53,20 +53,20 @@ FastAPI знает об этом и создаст документацию Open
Кратко о значениях кодов:
* `1XX` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
* **`2XX`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
* `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
* Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
* Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
* **`3XX`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
* **`4XX`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
* Пример – код `404` для статуса "Not Found".
* Для общих ошибок со стороны клиента можно просто использовать код `400`.
* `5XX` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов.
* `500 - 599`статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов.
/// 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">MDN</abbr> об HTTP кодах статуса ответа</a>.
///

289
docs/ru/docs/virtual-environments.md

@ -1,50 +1,49 @@
# Виртуальная среда
# Виртуальное окружение
При работе с проектами в Python рекомендуется использовать **виртуальную среду разработки** (или какой-нибудь другой подобный механизм). Это нужно для того, чтобы изолировать устанавливаемые пакеты для каждого отдельного проекта.
Когда вы работаете с проектами на Python, рекомендуется использовать **виртуальное окружение** (или подобный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта.
/// info | Дополнительная информация
Если вы уже знакомы с виртуальными средами разработки, знаете как их создавать и использовать, то вы можете свободно пропустить данный раздел. 🤓
Если вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓
///
/// tip | Подсказка
**Виртуальная среда** и **переменная окружения** это две разные вещи.
**Виртуальное окружение** отличается от **переменной окружения**.
**Переменная окружения** это системная переменная, которую могут использовать программы.
**Переменная окружения** это переменная в системе, которую могут использовать программы.
**Виртуальная среда** это папка, содержащая файлы.
**Виртуальное окружение** — это директория с файлами.
///
/// info | Дополнительная информация
В этом разделе мы научим вас пользоваться виртуальными средами разработки и расскажем, как они работают.
Этот раздел научит вас использовать **виртуальные окружения** и как они работают.
Если же вы готовы воспользоваться инструментом, **который умеет управлять всем, что касается 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>.
///
## Создание проекта
В первую очередь, создайте директорию для вашего проекта.
Сначала создайте директорию для вашего проекта.
Я обычно создаю папку под названием `code` внутри моего домашнего каталога `/home/user`.
Обычно я создаю директорию, названную `code`, внутри моего домашнего каталога `/home/user`.
Затем внутри данной папки я создаю отдельную директорию под каждый свой проект.
Затем, внутри этой директории, я создаю отдельную папку для каждого проекта.
<div class="termy">
```console
// Перейдите в домашний каталог
$ cd
// Создайте отдельную папку под все будущие программные проекты (code)
// Создайте отдельную папку под всё ваше программное обеспечение (code)
$ mkdir code
// Войдите в директорию code
$ cd code
// Создайте директрорию под данный проект (awesome-project)
// Создайте директорию для данного проекта
$ mkdir awesome-project
// Перейдите в созданную директорию проекта
$ cd awesome-project
@ -52,20 +51,19 @@ $ cd awesome-project
</div>
## Создание виртуальной среды разработки
## Создание виртуального окружения
Начиная работу с Python-проектом, сразу же создавайте виртуальную среду разработки
**<abbr title="есть и другие опции, но мы рассмотрим наиболее простой вариант">внутри вашего проекта</abbr>**.
Когда вы начинаете работать над Python-проектом **впервые**, создайте виртуальное окружение **<abbr title="существуют и другие опции, это простая инструкция">внутри вашего проекта</abbr>**.
/// tip | Подсказка
Виртуальная среда разработки создается один раз, и в дальнейшем, работая с проектом, этого больше делать не придется.
Это нужно сделать **один раз для каждого проекта**, а не каждый раз, когда вы начинаете работу.
///
//// tab | `venv`
Для создания виртуальной среды вы можете воспользоваться модулем `venv`, который является частью встроенной библиотеки Python.
Для создания виртуального окружения можно использовать модуль `venv`, который встроен в Python.
<div class="termy">
@ -78,9 +76,9 @@ $ python -m venv .venv
/// details | Что делает эта команда?
* `python`: использовать программу под именем `python`
* `-m`: вызывать модуль как скрипт, в следующей инструкции мы скажем какой именно модуль вызвать
* `-m`: вызывать модуль как скрипт, в следующей инструкции мы укажем, какой модуль вызвать
* `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python
* `.venv`: создать виртуальную среду разработки в новой директории `.venv`
* `.venv`: создать виртуальное окружение в новой директории `.venv`
///
@ -88,7 +86,7 @@ $ python -m 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">
@ -100,29 +98,29 @@ $ uv venv
/// tip | Подсказка
По умолчанию `uv` создаст виртуальную среду разработки в папке под названием `.venv`.
По умолчанию `uv` создаст виртуальное окружение в папке под названием `.venv`.
Но вы можете это изменить, передав дополнительный аргумент с именем директории.
Но вы можете изменить это, передав дополнительный аргумент с именем директории.
///
////
Данная команда создаст новую виртуальную среду разработки в папке `.venv`.
Эта команда создаст новое виртуальное окружение в папке `.venv`.
/// details | `.venv` или другое имя?
Вы можете поместить виртуальную среду разработки в папку с другим именем, но традиционным (конвенциональным) названием является `.venv` .
Вы можете создать виртуальное окружение в другой директории, но традиционное (конвенциональное) название — `.venv`.
///
## Активация виртуальной среды разработки
## Активация виртуального окружения
Активируйте виртуальную среду разработки, и тогда любая запускаемая Python-команда или устанавливаемый пакет будут ее использовать.
Активируйте виртуальное окружение, чтобы любая запускаемая команда Python или устанавливаемый пакет использовали его.
/// tip | Подсказка
При работе над проектом делайте это **каждый раз** при запуске **новой сессии в терминале**.
Делайте это **каждый раз**, когда начинаете **новую сессию в терминале**, чтобы работать над проектом.
///
@ -152,7 +150,7 @@ $ .venv\Scripts\Activate.ps1
//// tab | Windows Bash
Или при использовании Bash для Windows (напр. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
Если вы используете Bash для Windows (например, <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
@ -164,13 +162,13 @@ $ source .venv/Scripts/activate
////
## Проверка активации виртуальной среды
## Проверка активации виртуального окружения
Проверьте, активна ли виртуальная среда (удостоверимся, что предыдущая команда сработала).
Проверьте, активировано ли виртуальное окружение (то есть, что предыдущая команда сработала).
/// tip | Подсказка
Убедитесь в том, что все работает так, как нужно и вы используете именно ту виртуальную среду разработки, которую нужно. Делать это необязательно, но желательно.
Эта проверка **необязательна**, но это хороший способ **убедиться**, что все работает, как ожидается, и вы используете нужное вам виртуальное окружение.
///
@ -186,7 +184,7 @@ $ which python
</div>
Если данная команда показывает, что исполняемый файл `python` (`.venv\bin\python`), находится внутри виртуальной среды вашего проекта (у нас это `awesome-project`), значит все отработало как нужно. 🎉
Если показывается бинарный файл `python` в `.venv/bin/python`, внутри вашего проекта (в данном случае `awesome-project`), это значит, что все сработало. 🎉
////
@ -202,7 +200,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
</div>
Если данная команда показывает, что исполняемый файл `python` (`.venv\Scripts\python`), находится внутри виртуальной среды вашего проекта (у нас это `awesome-project`), значит все отработало как нужно. 🎉
Если показывается бинарный файл `python` в `.venv\Scripts\python`, внутри вашего проекта (в данном случае `awesome-project`), это значит, что все сработало. 🎉
////
@ -210,21 +208,21 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
/// tip | Подсказка
Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, то вы должны будете его использовать для установки пакетов вместо `pip`, поэтому обновлять `pip` вам ненужно. 😎
Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, вы должны будете использовать его для установки пакетов вместо `pip`, поэтому обновлять `pip` ненужно. 😎
///
Если для установки пакетов вы используете `pip` (он устанавливается по умолчанию вместе с Python), то обновите `pip` до последней версии.
Если вы используете `pip` для установки пакетов (он устанавливается по умолчанию вместе с Python), обновите его до последней версии.
Большинство экзотических ошибок, возникающих при установке пакетов, устраняется предварительным обновлением `pip`.
Многие экзотические ошибки при установке пакетов решаются простым обновлением `pip`.
/// tip | Подсказка
Обычно это делается только один раз, сразу после создания виртуальной среды разработки.
Обычно это делается **один раз**, сразу после создания виртуального окружения.
///
Убедитесь в том, что виртуальная среда активирована (с помощью вышеуказанной команды) и запустите следующую команду:
Убедитесь, что виртуальное окружение активно (при помощи команды выше) и запустите:
<div class="termy">
@ -238,17 +236,17 @@ $ python -m pip install --upgrade pip
## Добавление `.gitignore`
Если вы используете **Git** (а вы должны его использовать), то добавьте файл `.gitignore` и исключите из Git всё, что находится в папке `.venv`.
Если вы используете **Git** (и вам стоит это делать), добавьте файл `.gitignore` и исключите всё в `.venv` из Git.
/// tip | Подсказка
Если для создания виртуальной среды вы используете <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> для создания виртуального окружения, то он уже сделал это за вас, и вы можете пропустить этот шаг. 😎
///
/// tip | Подсказка
Это делается один раз, сразу после создания виртуальной среды разработки.
Делайте это **один раз** после создания виртуального окружения.
///
@ -262,13 +260,13 @@ $ echo "*" > .venv/.gitignore
/// details | Что делает эта команда?
* `echo "*"`: напечатать `*` в консоли (следующий шаг это слегка изменит)
* `>`: все что находится слева от `>` не печатать в консоль, но записать в файл находящийся справа от `>`
* `.gitignore`: имя файла, в который нужно записать текст.
* `echo "*"`: напечатает текст `*` в терминале (следующая часть изменит это)
* `>`: всё, что будет напечатано в терминал командой с левой стороны от `>`, не печатать, а вместо этого записать в файл, который указан справа от `>`
* `.gitignore`: имя файла, в который должен быть записан текст
`*` в Git означает "всё". Т.е. будет проигнорировано всё, что содержится в папке `.venv`.
А `*` в Git означает "всё". Следовательно, будет проигнорировано всё, что содержится в директории `.venv`.
Данная команда создаст файл `.gitignore` следующего содержания:
Эта команда создаст файл `.gitignore` со следующим содержимым:
```gitignore
*
@ -278,23 +276,23 @@ $ echo "*" > .venv/.gitignore
## Установка пакетов
После установки виртуальной среды, вы можете устанавливать в нее пакеты.
После активации окружения вы можете установить в него пакеты.
/// tip | Подсказка
Сделайте это **один раз**, при установке или обновлении пакетов, нужных вашему проекту.
Сделайте это **один раз**, при установке или обновлении пакетов, необходимых вашему проекту.
Если вам понадобится обновить версию пакета или добавить новый пакет, то вы должны будете **сделать это снова**.
Если вам нужно обновить версию или добавить новый пакет, вы должны будете **сделать это снова**.
///
### Установка пакетов напрямую
Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, то вы можете установить их напрямую.
Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, вы можете установить их напрямую.
/// tip | Подсказка
Объявление пакетов, которые использует ваш проект, и их версий в отдельном файле (например, в `requirements.txt` или в `pyproject.toml`) - это отличная идея.
Очень хорошая идея — указать пакеты и версии, которые нужны вашей программе, в отдельном файле (например, `requirements.txt` или `pyproject.toml`).
///
@ -329,7 +327,7 @@ $ uv pip install "fastapi[standard]"
### Установка из `requirements.txt`
Если у вас есть `requirements.txt`, то вы можете использовать его для установки пакетов.
Если у вас есть `requirements.txt`, вы можете использовать его для установки пакетов.
//// tab | `pip`
@ -361,7 +359,7 @@ $ uv pip install -r requirements.txt
/// details | `requirements.txt`
`requirements.txt` с парочкой пакетов внутри выглядит приблизительно так:
Файл `requirements.txt` с некоторыми пакетами может выглядеть так:
```requirements.txt
fastapi[standard]==0.113.0
@ -372,7 +370,7 @@ pydantic==2.8.0
## Запуск программы
После активации виртуальной среды разработки вы можете запустить свою программу и она будет использовать версию Python и пакеты, установленные в виртуальной среде.
После активации виртуального окружения вы можете запустить свою программу, и она будет использовать версию Python и пакеты, установленные в этом окружении.
<div class="termy">
@ -386,7 +384,7 @@ Hello World
## Настройка редактора
Вероятно, вы захотите воспользоваться редактором. Убедитесь, что вы настроили его на использование той самой виртуальной среды, которую вы создали. (Скорее всего, она автоматически будет обнаружена). Это позволит вам использовать авто-завершение и выделение ошибок в редакторе.
Вы, вероятно, будете использовать редактор, убедитесь, что вы настроили его на использование того же виртуального окружения, которое вы создали (скорее всего, он обнаружит это автоматически), чтобы получить автозавершение и выделение ошибок в коде.
Например:
@ -395,13 +393,13 @@ Hello World
/// tip | Подсказка
Обычно это делается один раз, при создании виртуальной среды разработки.
Обычно это нужно делать только **один раз**, когда вы создаете виртуальное окружение.
///
## Деактивация виртуальной среды разработки
## Деактивация виртуального окружения
По окончании работы над проектом вы можете деактивировать виртуальную среду.
Когда вы закончите работу над проектом, вы можете **деактивировать** виртуальное окружение.
<div class="termy">
@ -411,55 +409,55 @@ $ deactivate
</div>
Таким образом, при запуске `python`, будет использована версия `python` установленная глобально, а не из этой виртуальной среды вместе с установленными в ней пакетами.
Итак, при запуске `python` не будет попыток использовать Python из этого виртуального окружения с установленными там пакетами.
## Все готово к работе
Теперь вы готовы к тому, чтобы начать работу над своим проектом.
Теперь вы готовы начать работу над своим проектом.
/// tip | Подсказка
Хотите разобраться со всем, что написано выше?
Хотите понять, что это было выше?
Продолжайте читать. 👇🤓
///
## Зачем использовать виртуальную среду?
## Зачем нужно виртуальное окружение
Для работы с FastAPI вам потребуется установить <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>.
Для работы с FastAPI вам нужно установить <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>.
После этого вам нужно будет **установить** FastAPI и другие **пакеты**, которые вы собираетесь использовать.
После этого, вам нужно будет **установить** FastAPI и любые другие **пакеты**, которые вы хотите использовать.
Для установки пакетов обычно используют `pip`, который устанавливается вместе с Python (или же используют альтернативные решения).
Для установки пакетов, как правило, используется команда `pip`, которая поставляется с Python (или альтернативные решения).
Тем не менее, если вы просто используете `pip` напрямую, то пакеты будут установлены в **глобальное Python-окружение** (глобально установленный Python).
Тем не менее, если вы используете `pip` напрямую, пакеты будут установлены в **глобальное Python-окружение** (глобально установленный Python).
### Проблема
Так в чем же проблема с установкой пакетов в глобальную среду Python?
Так в чём же проблема с установкой пакетов в глобальное окружение Python?
В какой-то момент вам, вероятно, придется писать множество разных программ, которые используют различные пакеты. 😱
В какой-то момент вы, вероятно, будете писать множество различных программ, которые зависят от **разных пакетов**. И некоторые из этих проектов, над которыми вы работаете, будут зависеть от **разных версий** одного и того же пакета. 😱
Например, вы создаете проект `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]
```
Проблема заключается в том, что при установке в глобальное окружение, а не в локальную виртуальную среду разработки, вам нужно будет выбирать, какую версию пакета `harry` устанавливать.
Но теперь проблема заключается в том, что если вы установите пакеты глобально (в глобальной среде) вместо локального **виртуального окружения**, то вам придется выбирать, какую версию `harry` устанавливать.
Если вам нужен `philosophers-stone`, то вам нужно сначала установить `harry` версии `1`:
Если вы хотите запустить `philosophers-stone`, вам сначала нужно установить `harry` версии `1`, например вот так:
<div class="termy">
@ -469,7 +467,7 @@ $ pip install "harry==1"
</div>
И тогда в вашем глобальном окружении Python будет установлен `harry` версии `1`:
И тогда у вас будет установлен `harry` версии `1` в вашем глобальном окружении Python.
```mermaid
flowchart LR
@ -481,7 +479,7 @@ flowchart LR
end
```
Но если позднее вы захотите запустить `prisoner-of-azkaban`, то вам нужно будет удалить `harry` версии 1, и установить `harry` версии `3` (при установке пакета версии `3` поверх пакета версии `1`, пакет версии `1` удаляется автоматически).
Но потом, если вы хотите запустить `prisoner-of-azkaban`, вам придется удалить `harry` версии `1` и установить `harry` версии `3` (или установка версии `3` автоматически удалит версию `1`).
<div class="termy">
@ -491,9 +489,9 @@ $ pip install "harry==3"
</div>
И тогда, в вашей глобальной среде окружения Python, будет установлен пакет `harry` версии `3`.
И тогда у вас будет установлен `harry` версии `3` в вашем глобальном окружении Python.
И когда вы снова попытаетесь запустить `philosophers-stone`, то существует вероятность того, что он не будет работать, так как он использует `harry` версии `1`.
И если вы попытаетесь снова запустить `philosophers-stone`, существует вероятность, что он **не будет работать**, потому что ему нужен `harry` версии `1`.
```mermaid
flowchart LR
@ -512,47 +510,47 @@ flowchart LR
/// tip | Подсказка
В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новые версии, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно.
В пакетах Python очень часто стараются изо всех сил **избегать внесения критических изменений** в **новые версии**, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, всё ли работает правильно.
///
Теперь представьте, что это происходит со многими другими пакетами, которые используются в ваших проектах. С этим очень сложно справиться. И скорее всего, в конечном итоге вы будете запускать некоторые проекты с некоторыми несовместимыми зависимостями и не будете знать, почему что-то не работает.
Теперь представьте, что это происходит с **многими другими** **пакетами**, от которых зависят все ваши **проекты**. Управлять этим очень трудно. И вы, вероятно, в итоге будете запускать некоторые проекты с **несовместимыми версиями** пакетов, и не будете знать, почему что-то не работает.
Кроме того, в зависимости от вашей операционной системы (напр. Linux, Windows, macOS), она может поставляться с уже установленным Python. Вероятно, что в этом случае в ней уже установлены системные пакеты определенных версий. Если вы устанавливаете пакеты глобально, то вы можете **поломать** программы, являющиеся частью ОС.
Кроме того, в зависимости от используемой вами операционной системы (например, Linux, Windows, macOS), она может поставляться уже с установленным Python. И в этом случае, вероятно, были установлены некоторые системные пакеты с определёнными **версиями**, **необходимыми вашей системе**. Если вы установите пакеты в глобальное окружение Python, вы можете **сломать** некоторые из программ, которые поставлялись вместе с вашей операционной системой.
## Куда устанавливаются пакеты?
## Куда устанавливаются пакеты
Когда вы устанавливаете Python, то на вашей машине создается некоторое количество директорий, содержащих некоторое количество файлов.
Когда вы устанавливаете Python, он создаёт на вашем компьютере несколько директорий с файлами.
Среди них есть каталоги, отвечающие за хранение всех устанавливаемых вами пакетов.
Некоторые из этих директорий ответственны за хранение всех устанавливаемых вами пакетов.
Когда вы запустите команду:
Когда вы запустите:
<div class="termy">
```console
// Не запускайте эту команду, это просто пример 🤓
// Не запускайте эту команду сейчас, это просто пример 🤓
$ pip install "fastapi[standard]"
---> 100%
```
</div>
То будет скачан сжатый файл, содержащий код FastAPI, обычно скачивание происходит с <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>.
Это скачает сжатый файл с кодом FastAPI, обычно с <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>.
Также будут скачаны файлы, содержащие пакеты, которые использует FastAPI.
Он также **скачает** файлы для других пакетов, от которых зависит FastAPI.
Затем все файлы будут извлечены и помещены в директорию на вашем компьютере.
Затем он **извлечёт** все эти файлы и разместит их в директории на вашем компьютере.
По умолчанию эти файлы будут загружены и извлечены в один из каталогов установки Python, т.е. в глобальную среду.
По умолчанию, он поместит эти загруженные и распакованные файлы в директорию установку Python, это и есть **глобальное окружение**.
## Что такое виртуальная среда разработки?
## Что такое виртуальное окружение
Решением проблемы размещения всех пакетов в глобальной среде будет использование отдельной виртуальной среды под каждый проект, над которым вы работаете.
Решением проблемы размещения всех пакетов в глобальной среде является использование **виртуального окружения для каждого проекта**, над которым вы работаете.
Виртуальная среда это обычная папка, очень похожая на глобальную, куда вы можете устанавливать пакеты для вашего проекта.
Виртуальное окружение — это **директория**, очень похожая на глобальную, в которой вы можете устанавливать пакеты для проекта.
Таким образом, каждый проект будет иметь свою отдельную виртуальную среду разработки (в директории `.venv`) вместе со своими пакетами.
Таким образом, у каждого проекта будет своё виртуальное окружение (директория `.venv`) с собственными пакетами.
```mermaid
flowchart TB
@ -571,9 +569,9 @@ flowchart TB
stone-project ~~~ azkaban-project
```
## Что означает активация виртуальной среды?
## Что означает активация виртуального окружения
Когда вы активируете виртуальную среду разработки, например, так:
Когда вы активируете виртуальное окружение, например:
//// tab | Linux, macOS
@ -601,7 +599,7 @@ $ .venv\Scripts\Activate.ps1
//// tab | Windows Bash
Или если вы воспользуетесь Bash под Windows (напр. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
Или если вы используете Bash для Windows (например, <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
@ -613,20 +611,19 @@ $ source .venv/Scripts/activate
////
Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд.
Одной из таких переменных является `PATH`.
Одна из этих переменных называется `PATH`.
/// tip | Подсказка
Вы можете узнать больше о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
Вы можете больше узнать о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
///
При активации виртуальной среды путь `.venv/bin` (для Linux и macOS) или `.venv\Scripts` (для Windows) добавляется в переменную окружения `PATH`.
Активация виртуального окружения добавляет его путь `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) к переменной окружения `PATH`.
Предположим, что до активации виртуальной среды переменная `PATH` выглядела так:
Предположим, что до активации окружения переменная `PATH` выглядела так:
//// tab | Linux, macOS
@ -634,7 +631,7 @@ $ source .venv/Scripts/activate
/usr/bin:/bin:/usr/sbin:/sbin
```
Это означает, что система ищет программы в следующих каталогах:
Это означает, что система будет искать программы в:
* `/usr/bin`
* `/bin`
@ -649,13 +646,13 @@ $ source .venv/Scripts/activate
C:\Windows\System32
```
Это означает, что система ищет программы в:
Это означает, что система будет искать программы в:
* `C:\Windows\System32`
////
После активации виртуальной среды переменная окружение `PATH` будет выглядеть примерно так:
После активации виртуального окружения переменная окружения `PATH` будет выглядеть примерно так:
//// tab | Linux, macOS
@ -663,21 +660,21 @@ C:\Windows\System32
/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
Это означает, что система теперь будет искать программы в:
Это означает, что система теперь будет в первую очередь искать программы в:
```plaintext
/home/user/code/awesome-project/.venv/bin
```
прежде чем начать искать в других каталогах.
прежде чем искать в других директориях.
Таким образом, когда вы введете в консоль `python`, система будет искать Python в
Так что, когда вы вводите `python` в терминале, система найдет программу Python в
```plaintext
/home/user/code/awesome-project/.venv/bin/python
```
и будет использовать именно его.
и использует именно её.
////
@ -687,31 +684,31 @@ C:\Windows\System32
C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
```
Это означает, что система в первую очередь начнет искать программы в:
Это означает, что система теперь будет в первую очередь искать программы в:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts
```
прежде чем начать искать в других директориях.
прежде чем искать в других директориях.
Таким образом, если вы введете в консоль команду `python`, то система найдет Python в:
Так что, когда вы вводите `python` в терминале, система найдет программу Python в
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
и использует его.
и использует именно её.
////
Очень важной деталью является то, что путь к виртуальной среде будет помещен в самое начало переменной `PATH`. Система обнаружит данный путь к Python раньше, чем какой-либо другой. Таким образом, при запуске команды `python`, будет использован именно Python из виртуальной среды разработки, а не какой-нибудь другой (например, Python из глобальной среды)
Важная деталь заключается в том, что путь к виртуальному окружению будет помещён в самое **начало** переменной `PATH`. Система найдет его **до** обнаружения любого другого доступного Python. Таким образом, когда вы запускаете `python`, он будет использовать **Python из виртуального окружения**, а не какой-либо другой `python` (например, `python` из глобального окружения).
Активация виртуальной среды разработки также меняет и несколько других вещей, но данная функция является основной.
Активация виртуального окружения также изменяет несколько других вещей, но это одна из самых важных вещей, которые она делает.
## Проверка виртуальной среды
## Проверка виртуального окружения
Когда вы проверяете активна ли виртуальная среда разработки, например, так:
Когда вы проверяете, активировано ли виртуальное окружение, например:
//// tab | Linux, macOS, Windows Bash
@ -741,31 +738,31 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
////
Это означает, что будет использоваться `python` **из виртуальной среды разработки**.
Это означает, что программа `python`, которая будет использована, — это та, что находится **в виртуальной среде разработки**.
Вы используете `which` для Linux и macOS и `Get-Command` для Windows PowerShell.
Вы используете `which` на Linux и macOS и `Get-Command` на Windows PowerShell.
Эта команда работает следующим образом: она проверяет переменную окружения `PATH`, проходя по очереди каждый указанный путь в поисках программы под названием `python`. И когда она её находит, то возвращает путь к данной программе.
Способ работы этой команды заключается в том, что она пойдёт и проверит переменную окружения `PATH`, проходя **каждый путь по порядку**, в поисках программы под названием `python`. Как только она её найдет, она **покажет вам путь** к этой программе.
Основной момент при вызове команды `python` состоит в том, какой именно "`python`" будет запущен.
Самое важное тут в том, что когда вы вызываете `python`, именно этот "`python`" будет выполнен.
Таким образом, вы можете убедиться, что используете правильную виртуальную среду разработки.
Таким образом, вы можете убедиться, что используете верное виртуальное окружение.
/// tip | Подсказка
Легко активировать одну виртуальную среду, вызвать один Python и **перейти к следующему проекту**.
Легко активировать одно виртуальное окружение, получить одного Python, а затем **перейти к другому проекту**.
И следующий проект не будет работать потому, что вы используете **неправильный Python** из виртуальной среды другого проекта.
И второе проект **не будет работать**, потому что вы используете **неправильный Python** из виртуального окружения для другого проекта.
Так что, будет нелишним проверить, какой `python` вы используете. 🤓
Это очень полезно уметь проверять, какой `python` используется. 🤓
///
## Зачем деактивируют виртуальную среду?
## Почему деактивировать виртуальное окружение
Предположим, что вы работаете над проектом `philosophers-stone`, **активируете виртуальную среду разработки**, устанавливаете пакеты и работаете с данной средой.
Например, вы можете работать над проектом `philosophers-stone`, **активировать это виртуальное окружение**, установить пакеты и работать с этой средой.
И позже вам понадобилось поработать с **другим проектом** `prisoner-of-azkaban`.
И затем вы хотите работать над **другим проектом** `prisoner-of-azkaban`.
Вы переходите к этому проекту:
@ -777,7 +774,7 @@ $ cd ~/code/prisoner-of-azkaban
</div>
Если вы не деактивировали виртуальное окружение проекта `philosophers-stone`, то при запуске `python` через консоль будет вызван Python из `philosophers-stone`
Если вы не деактивируете виртуальное окружение для `philosophers-stone`, когда вы запускаете `python` в терминале, оно будет пытаться использовать Python из `philosophers-stone`.
<div class="termy">
@ -786,7 +783,7 @@ $ cd ~/code/prisoner-of-azkaban
$ python main.py
// Error importing sirius, it's not installed 😱
// Ошибка импорта sirius, он не установлен 😱
Traceback (most recent call last):
File "main.py", line 1, in <module>
import sirius
@ -794,46 +791,46 @@ Traceback (most recent call last):
</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
Я торжественно клянусь в этом! 🐺
Я торжественно клянусь 🐺
```
</div>
## Альтернативы
Это простое руководство поможет вам начать работу и научит тому, как всё работает **изнутри**.
Это простое руководство поможет вам начать и научит тому, как все работает **изнутри**.
Существует много альтернативных решений для работы с виртуальными средами разработки, с программными зависимостями, а также с проектами.
Существует множество **альтернатив** для управления виртуальными окружениями, зависимостями пакетов (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` может очень многое. Он умеет:
`uv` может делать много вещей, может:
* **Устанавливать Python**, включая установку различных версий
* Управлять средой виртуального окружения вашего проекта
* **Устанавливать Python** для вас, включая различные версии
* Управлять **виртуальным окружением** для ваших проектов
* Устанавливать **пакеты**
* Управлять пакетами и их версиями внутри вашего проекта
* Удостовериться, что вы используете **точный** набор пакетов и версий при установке, включая зависимости. Таким образом, вы можете быть уверенны, что проект, запускается в production, точно также, как и при разработке, этот механизм называется *locking*
* Многие другие вещи
* Управлять **зависимостями и версиями** пакетов для вашего проекта
* Убедиться, что у вас есть **точный** набор пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что вы сможете запустить ваш проект в production точно так же, как на вашем компьютере, когда разрабатываете, это называется **locking**
* И многое другое
## Заключение
Если вы прочитали и поняли всё это, то теперь вы знаете **гораздо больше** о виртуальных средах разработки, чем многие другие разработчики. 🤓
Если вы прочитали и поняли все это, то теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие другие разработчики. 🤓
Скорее всего, знание этих деталей будет полезно вам в будущем. Когда вы будете отлаживать что-то, кажущееся сложным, вы будете знать, **как это работает под капотом**. 😎
Знание этих деталей, скорее всего, будет полезно вам в будущем, когда вы будете отлаживать что-то, что кажется сложным, потому что вы будете знать, **как все работает изнутри**. 😎

Loading…
Cancel
Save