Browse Source

Update translations with new prompts 2

pull/13935/head
Yurii Motov 2 days ago
parent
commit
52b8966c6e
  1. 310
      docs/ru/docs/async.md
  2. 36
      docs/ru/docs/benchmarks.md
  3. 68
      docs/ru/docs/deployment/manually.md
  4. 232
      docs/ru/docs/help-fastapi.md
  5. 178
      docs/ru/docs/index.md
  6. 28
      docs/ru/docs/project-generation.md
  7. 66
      docs/ru/docs/tutorial/body-multiple-params.md
  8. 61
      docs/ru/docs/tutorial/cors.md
  9. 104
      docs/ru/docs/tutorial/extra-models.md
  10. 154
      docs/ru/docs/tutorial/first-steps.md
  11. 24
      docs/ru/docs/tutorial/handling-errors.md
  12. 34
      docs/ru/docs/tutorial/index.md
  13. 62
      docs/ru/docs/tutorial/middleware.md
  14. 248
      docs/ru/docs/tutorial/query-params-str-validations.md
  15. 72
      docs/ru/docs/tutorial/response-status-code.md
  16. 225
      docs/ru/docs/tutorial/sql-databases.md
  17. 310
      docs/ru/docs/virtual-environments.md

310
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('/')
@ -23,13 +23,13 @@ async def read_results():
/// note | Примечание
Вы можете использовать `await` только внутри функций, созданных с помощью `async def`.
`await` можно использовать только внутри функций, созданных с использованием `async def`.
///
---
Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует (с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await` (что относится сейчас к большинству библиотек для работы с базами данных), то объявляйте *функции-обработчики пути* обычным образом с помощью `def`, например:
Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т. д.) и не поддерживает использование `await`, (это в настоящее время относится к большинству библиотек для работы с базами данных), тогда объявляйте ваши *функции-обработчики пути* обычным образом, с `def`, например:
```Python hl_lines="2"
@app.get('/')
@ -40,25 +40,25 @@ def results():
---
Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно, ожидать ответа, используйте `async def`, даже если внутри нет необходимости в `await`.
Если вашему приложению (каким-то образом) не нужно ни с чем взаимодействовать и ждать ответа, используйте `async def`, даже если внутри не нужно использовать `await`.
---
Если вы не знаете, используйте обычный `def`.
Если вы просто не знаете, используйте обычный `def`.
---
**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях-обработчиках пути* и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно.
**Примечание**: Вы можете смешивать `def` и `async def` в ваших *функциях-обработчиках пути* так, как вам нужно, и определять каждую с использованием наилучшего варианта для вас. FastAPI сделает с ними всё, что нужно.
В любом случае, в любой из упомянутых выше ситуаций, FastAPI всё равно будет работать асинхронно и с высокой скоростью.
В любом случае, в любой из описанных выше ситуаций, FastAPI всё равно будет работать асинхронно и будет чрезвычайно быстро.
Но, следуя указанным выше шагам, он сможет оптимизировать производительность.
Но, следуя указанным шагам, можно будет достичь некоторой оптимизации производительности.
## Технические подробности
Современные версии Python поддерживают **"асинхронный код"** с использованием чего-то, называемого **"сопрограммами"**, с синтаксисом **`async` и `await`**.
Современные версии Python поддерживают **"асинхронный код"**, используя что-то под названием **"сопрограммы"**, со **синтаксисом `async` и `await`**.
Давайте рассмотрим эту фразу по частям в следующих разделах:
Давайте разберём эту фразу по частям в следующих разделах:
* **Асинхронный код**
* **`async` и `await`**
@ -66,269 +66,257 @@ def results():
## Асинхронный код
Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖, что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝.
Асинхронный код просто означает, что в языке 💬 есть способ указать компьютеру / программе 🤖, что в определённый момент кода, он 🤖 должен будет дождаться, пока *что-то ещё* завершится где-то ещё. Допустим, это *что-то ещё* называется "медленный файл" 📝.
Так что, в это время, компьютер может выполнять какую-то другую работу, пока "медленный файл" 📝 заканчивается.
Итак, в это время компьютер может заниматься чем-то другим, пока "медленный файл" 📝 завершает работу.
Потом компьютер / программа 🤖 будет возвращаться каждый раз, когда у него будет шанс, потому что он снова ждет, или когда он 🤖 закончит всю работу, которую у него была к тому моменту. И он 🤖 проверит, не завершилась ли какая-либо из задач, чтобы выполнить то, что нужно.
Затем компьютер / программа 🤖 возвращается каждый раз, когда у него появляется возможность, потому что он снова что-то ожидает, или вся выполняемая работа на данный момент завершена. Он 🤖 проверяет, не завершена ли какая-нибудь из ожидаемых задач, и выполняет необходимые действия.
Затем он 🤖 берёт первую задачу, которая завершилась (например, наш "медленный файл" 📝) и продолжает выполнение того, что ему надо было сделать.
Далее 🤖 берёт первую завершённую задачу (допустим наш "медленный файл" 📝) и продолжает действия, которые он должен был выполнить с ней.
Этот "ожидать чего-то ещё" обычно относится к операциям <abbr title="Ввод и вывод">I/O</abbr>, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например:
То "ожидание чего-то ещё", как правило, относится к операциям <abbr title="Ввод и вывод">I/O</abbr>, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например:
* ожидание данных от клиента, отправленных через сеть
* ожидание, когда данные, отправленные программой, будут получены клиентом через сеть
* ожидание, когда содержимое файла на диске будет прочитано системой и передано вашей программе
* ожидание, когда данные, которые ваша программа передала системе, будут записаны на диск
* данные от клиента по сети
* данные, отправленные вашей программой клиенту через сеть
* содержимое файла на диске передано системе и дано вашей программе
* содержимое вашей программы передано системе для записи на диск
* удалённая операция API
* ожидание завершения операции с базой данных
* ожидание, когда запрос к базе данных вернёт результаты
* операция с базой данных завершается
* выполнение запроса к базе данных возвращает результаты
* и т. д.
Поскольку в основном время тратится на ожидание выполнения операций <abbr title="Ввода-вывода">I/O</abbr>, их обычно называют операциями, <abbr title="I/O bound">ограниченными скоростью ввода-вывода</abbr>.
Поскольку в основном время выполнения тратится на ожидание операций <abbr title="Ввод и вывод">I/O</abbr>, это называют "операциями, ограниченными скоростью ввода-вывода".
Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и, будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу.
Они называются "асинхронными", поскольку компьютеру / программе не нужно быть "синхронизированными" с медленной задачей и сидеть в ожидании момента её завершения, чтобы забрать результаты и продолжить работу.
Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд), пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться, забрать результаты выполнения и начать их обрабатывать.
Вместо этого, в "асинхронной" системе задача, оказавшись завершённой, может немного подождать в очереди (некоторые микросекунды), пока компьютер / программа завершит то, что выполнял, и затем вернуться, чтобы забрать результаты и продолжить работу с ними.
"Синхронное" исполнение (в противовес "асинхронному") также называют <abbr title="sequential">"последовательным"</abbr>, потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче, даже если в процессе приходится ждать.
Для "синхронного" (в противоположность "асинхронному") они часто также используют термин "последовательный", потому что компьютер / программа следует всем шагам в последовательности, прежде чем переключиться на другую задачу, даже если эти шаги включают ожидание.
### Конкурентность и бургеры
Эту идею **асинхронного** кода, описанную выше, иногда также называют **"конкурентностью"**. Это отличается от **"параллелизма"**.
Эта концепция **асинхронного** кода, описанного выше, также иногда называется **"конкурентностью"**. Она отличается от **"параллелизма"**.
**Конкурентность** и **параллелизм** оба подразумевают, что "разные вещи происходят более или менее в одно время".
**Конкурентность** и **параллелизм** оба связаны с "разными вещами, происходящими более-менее одновременно".
Но детали между *конкурентностью* и *параллелизмом* достаточно разные.
Но детали между *конкурентностью* и *параллелизмом* весьма различны.
Чтобы увидеть разницу, представьте следующую историю о бургерах:
Чтобы увидеть разницу, представьте следующую историю про бургеры:
### Конкурентные бургеры
Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами.
Вы идёте со своей возлюбленной 😍 в фастфуд, становитесь в очередь, в это время кассир принимает заказы у посетителей перед вами.
<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-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">Ketrina Thompson</a>. 🎨
Красивые иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Кетрины Томпсон</a>. 🎨
///
---
А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖.
Представьте, что в этой истории вы компьютер / программа 🤖.
В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете. Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного.
Когда вы в очереди, вы просто ждёте своей очереди, не делая ничего особо "производительного". Но очередь движется быстро, потому что кассир только принимает заказы (не готовит их), так что это нормально.
Затем, когда наступает ваша очередь, вы делаете настоящую "продуктивную" работу, обрабатываете меню, решаете, что хотите, узнаёте выбор вашей возлюбленной, оплачиваете, проверяете, что даёте правильную сумму или карту, проверяете, правильно ли с вас взяли оплату, содержится ли в заказе всё, что нужно, и так далее.
Когда приходит ваша очередь, вы делаете фактически "производительную" работу: просматриваете меню, выбираете, что хотите, узнаёте, что хочет ваша возлюбленная, платите, проверяете, что отдали правильную банкноту или карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д.
И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸, поскольку теперь нужно ждать 🕙, когда заказ приготовят.
Но даже если вы пока не получили свои бургеры, ваша работа с кассиром "на паузе" ⏸, потому что вам нужно ждать, пока они будут готовы.
Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень "продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍.
Но, отойдя с номерком от прилавка, вы садитесь за столик и можете переключить внимание 🔀 на свою возлюбленную и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень "производительны" 🤓, мило болтаете вдвоём и всё такое 😍.
Кассир 💁 говорит "я закончил делать бургеры" через показ номера вашего заказа на табло, но вы не вскакиваете, как сумасшедший, когда отображаемый номер меняется на номер вашей очереди. Вы знаете, что никто не украдёт у вас бургеры, потому что у вас есть номер вашего заказа, а у других — свои.
Кассир 🏽 говорит "Я закончил с приготовлением бургеров" выставив номер вашей очереди на дисплей прилавка, но вы не прыгаете как безумный только увидев, как номер на дисплее поменялся на ваш. Вы уверены, что ваши бургеры никто не утащит, ведь у вас свой номерок, а у других свой.
Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓) и мило улыбнувшись, скажете, что идёте забирать заказ.
Таким образом, вы ждёте, пока история вашей возлюбленной не будет рассказана (завершена текущая работа ⏯ / задача 🤓), мило улыбаетесь и говорите, что идёте забирать заказ.
И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹. В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
Тогда вы идёте к прилавку 🔀, чтобы закончить начальную задачу ⏯, берете бургеры, и говорите спасибо, забираете их к столу. На этом заканчивается этап / задача взаимодействия с прилавком ⏹. Это в свою очередь, создаёт новую задачу "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
### Параллельные бургеры
Теперь представим, что это не "Конкурентные бургеры", а "Параллельные бургеры".
Теперь представьте, что это не "Конкурентные бургеры", а "Параллельные бургеры".
Вы идёте с вашей возлюбленной попробовать параллельный фастфуд.
Вы идёте со своей возлюбленной за параллельным фастфудом.
Вы становитесь в очередь, пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами.
Вы становитесь в очередь, в то время как несколько (скажем 8) кассиров, которые одновременно являются поварами, принимают заказы у клиентов перед вами.
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ.
Каждый перед вами клиент ждёт, когда прилавок будет готов отпускать их бургеры, прежде чем отойти от прилавка потому что каждый из 8 кассиров идёт и сразу готовит бургер, перед тем как принять следующий заказ.
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
Затем, наконец, наступает ваша очередь, вы заказываете 2 очень вкусных бургера для вашей возлюбленной и вас.
Ни о чём не жалея, расплачиваетесь 💸.
Наконец подходит ваша очередь, вы заказываете 2 очень навороченные бургера для вашей возлюбленной и себя.
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
Вы платите 💸.
<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-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">
Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик.
Вы берете ваши бургеры и идёте за столик вместе со своей возлюбленной.
Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹.
Вы просто едите их, и всё. ⏹
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞.
Разговоров и флирта было немного, поскольку большую часть времени пришлось провести у прилавка. 😞
/// info | Информация
Прекрасные иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
Красивые иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Кетрины Томпсон</a>. 🎨
///
---
В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍), на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе".
В этой истории о параллельных бургерах вы компьютер / программа 🤖 с двумя "процессорами" (вы и ваша возлюбленная 😍), оба ждут 🕙 и уделяют все своё внимание ⏯, чтобы стоять "на кассе" долгое время.
В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳.
Фастфуд имеет 8 "процессоров" (кассиров/поваров). В то время как в магазине конкурентных бургеров, возможно, их было всего 2 (один кассир и один повар).
Но всё же, окончательный опыт не самый лучший. 😞
Но все равно итоговый опыт не из лучших. 😞
---
Это была бы параллельная аналогичная история для бургеров. 🍔
Для более "реального" примера этого, представьте банк.
До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинная очередь 🕙🕙🕙🕙🕙🕙🕙🕙.
Это была бы параллельная история для бургеров. 🍔
Все кассиры занимались каждым клиентом один за другим 👨‍💼⏯.
Для более "реалистичного" примера этого представьте себе банк.
И вам долгое время приходилось ждать 🕙 в очереди, иначе потеряете свою очередь.
До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙.
Скорее всего, вам бы не захотелось брать вашу возлюбленную 😍 с собой для быстрого похода в банк 🏦.
Кассиры выполняют всю работу для клиента один за другим 👨‍💼⏯.
### Заключение о бургерах
А вам приходится долго стоять в очереди 🕙 или вы пропустите свою очередь.
В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙, поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯.
Вы вряд ли хотели бы взять свою возлюбленную 😍 в банк 🏦 оплачивать налоги.
И это и есть случай для большинства веб-приложений.
### Выводы о бургерах
Много, много пользователей, но ваш сервер ожидает 🕙, чтобы они отправили свои запросы через своё не очень хорошее соединение.
В этой истории с "фастфудом и бургером с вашей возлюбленной", так как много времени тратится на ожидание 🕙, имеет смысл иметь конкурентную систему ⏸🔀⏯.
И потом снова ждёт 🕙, чтобы ответы вернулись.
Это случай для большинства веб-приложений.
Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени.
Много-много пользователей, но ваш сервер ждёт 🕙 их не самого лучшего соединения, чтобы отправить их запросы.
Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API.
И ждёт снова 🕙, пока их ответы вернутся.
Большинство популярных фреймворков (включая Flask и Django) создавались до появления в Python новых возможностей асинхронного программирования. Поэтому их можно разворачивать с поддержкой параллельного исполнения или асинхронного программирования старого типа, которое не настолько эффективно.
Это "ожидание" 🕙 измеряется в микросекундах, но всё равно, складывая, это в итоге много времени ожидания.
При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером (<a href="https://asgi.readthedocs.io" class="external-link" target="_blank">ASGI</a>) была разработана командой Django для внедрения поддержки веб-сокетов.
Вот почему так важно использовать асинхронный код для веб-API.
Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный), и в этом преимущество Go как языка программирования.
Такая асинхронность сделала NodeJS популярным (несмотря на то, что NodeJS не параллелен) и в этом сила Go как языка программирования.
И это тот же уровень производительности, который вы получаете с **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>.
И, поскольку вы можете использовать параллелизм и асинхронность вместе, вы достигнете большей производительности, чем у большинства протестированных фреймворков 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> (когда несколько процессов работают параллельно), если рабочая нагрузка предполагает **ограничение по процессору**, как, например, в системах машинного обучения.
Тем не менее, вы можете также использовать преимущества параллелизма и многопроцессорности (несколько процессов, работающих параллельно) для рабочих нагрузок, ограниченных по процессору, таких как в Машинное обучение.
Необходимо также отметить, что Python является главным языком в области **дата-сайенс** (наука о данных), машинного обучения и, особенно, глубокого обучения. Всё это делает 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`. Оно сообщает Python, что необходимо дождаться ⏸ выполнения `get_burgers(2)` 🕙 прежде чем сохранять результат в `burgers`. Python понимает, что может переключиться на выполнение других задач 🔀 ⏯ (например, получение следующего запроса).
Ключевой момент здесь - `await`. Он говорит интерпретатору Python, что нужно дождаться ⏸ выполнения `get_burgers(2)`, прежде чем сохранить результаты в `burgers`. С этим Python будет знать, что он может заняться чем-то другим 🔀 ⏯, пока ждет (например, принять другой запрос).
Для работы `await`, оно должно находиться внутри функции, поддерживающей асинхронность. Это достигается объявлением с `async def`:
Чтобы `await` сработал, оно должно находиться внутри функции, которая поддерживает эту асинхронность. Для этого просто объявите её с `async def`:
```Python hl_lines="1"
async def get_burgers(number: int):
# Выполняем некоторые асинхронные действия, чтобы создать бургеры
# Готовим бургеры по специальному асинхронному рецепту
return burgers
```
@ -337,22 +325,22 @@ async def get_burgers(number: int):
```Python hl_lines="2"
# Это не асинхронный код
def get_sequential_burgers(number: int):
# Выполняем последовательные действия, чтобы создать бургеры
# Готовим бургеры последовательно по шагам
return burgers
```
`async def` указывает интерпретатору на наличие ожидания `await` в функции, с возможностью "паузы" ⏸ и переключения на другие задачи 🔀 до возврата в исходное место.
Объявляя `async def`, интерпретатор Python знает, что внутри этой функции нужно быть внимательным к выражениям `await`, и что он может "поставить на паузу" ⏸ выполнение этой функции и выполнить что-то ещё 🔀 прежде, чем вернуться.
Если требуется вызвать `async def` функцию, нужно "ожидать" её. Поэтому такое не сработает:
Когда вы хотите вызвать функцию с `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')
@ -361,96 +349,96 @@ async def read_burgers():
return burgers
```
### Более технические подробности
### Технические подробности
Вы могли заметить, что `await` может применяться только в функциях, объявленных с использованием `async def`.
Вы могли заметить, что `await` можно использовать только внутри функций, определённых с помощью `async def`.
Но выполнение такой функции необходимо "ожидать" через `await`. Это означает, что её можно вызвать только из другой функции, также объявленной с `async def`.
Но одновременно функции, определённые с `async def`, должны быть "ожидание" с помощью `await`. Так что функции с `async def` можно вызывать только внутри функций, которые тоже определены с `async def`.
Итак, как же появилась первая *курица*? В смысле... как нам вызвать первую асинхронную функцию?
Так как же тогда появилась первая <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>.
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>. Это будет особенно полезно, если вам нужно **комбинировать асинхронный код с обычным** (блокирующим/синхронным) кодом.
Я создал ещё одну библиотеку на базе AnyIO, как тонкий слой сверху, чтобы немного улучшить аннотации типов и получить лучшее **автозавершение кода**, **встроенные ошибки** и т. д. У неё также есть дружественное введение и руководство, чтобы помочь вам **понять** и написать **свой асинхронный код**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. Она будет особенно полезна, если вам нужно **объединить асинхронный код с обычным** (блокирующимся/синхронным) кодом.
### Другие формы асинхронного кода
### Другие формы асинхронного программирования
Этот стиль использования `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>. Но код при этом становился намного сложнее для понимания, отладки и мышления.
В предыдущих версиях NodeJS/JavaScript использовали "обратные вызовы", что приводило к <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>.
## Сопрограммы
**Корутина** — это крутое словечко для именования той сущности, которая возвращается функцией `async def`. Python знает, что это что-то наподобие функции, что её можно запустить и она закончится в какой-то момент, но что её выполнение может быть остановлено ⏸ внутренне с помощью `await`.
<abbr title="сопрограмма">**Сопрограмма**</abbr> - это просто высокопарный термин для обозначения той вещи, которую функция `async def` возвращает. Интерпретатор Python знает, что это нечто вроде функции, что она может быть запущена и завершена в какой-то момент, но она также может быть поставлена на паузу ⏸, даже когда внутри неё есть `await`.
Вся функциональность асинхронного программирования с использованием `async` и `await` обобщается под термином "корутины". Они схожи с ключевой особенностью Go — "горутинами".
Но вся эта функциональность использования асинхронного кода с `async` и `await` во многих случаях обобщается как использование "сопрограмм". Это сопоставимо с ключевой отличительной особенностью языка Go, "горутины".
## Заключение
Давайте увидим ту же фразу сверху:
Давайте ещё раз вспомним ту фразу изначально:
> Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**.
> Современные версии Python поддерживают **"асинхронный код"**, используя что-то под названием **"сопрограммы"** с **синтаксисом `async` и `await`**.
Теперь это должно звучать более понятно. ✨
Теперь это должно звучать понятнее. ✨
На этом основана работа FastAPI (посредством Starlette), и именно это обеспечивает его высокую производительность.
Именно это в основном работает в FastAPI (через Starlette) и придаёт ему такую впечатляющую производительность.
## Очень технические подробности
/// 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>.
Если вы пришли из другого асинхронного фреймворка, который не работает так, как описано выше, и вы привыкли определять простые вычислительные *функции* с помощью обычного `def` ради микроскопического прироста производительности (порядка 100 наносекунд), обратите внимание, что в **FastAPI** эффект будет совершенно противоположный. В этих случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, который выполняет блокирующий <abbr title="Ввод/вывод: чтение и запись на диск, сетевые соединения.">I/O</abbr>.
Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](index.md#performance){.internal-link target=_blank}, чем (или хотя бы на уровне с) ваш предыдущий фреймворк.
Тем не менее, несмотря на это, велика вероятность, что **FastAPI** [будет быстрее](index.md#performance){.internal-link target=_blank} (или по крайней мере сравнимо с) вашим предыдущим фреймворком
### Зависимости
То же самое относится и к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость объявлена с использованием стандартной функции `def`, она будет запущена во внешнем пуле потоков.
То же самое применимо и к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость оформлена как стандартная `def` функция вместо `async def`, она выполняется в внешнем пуле потоков.
### Подзависимости
Вы можете объявить множество ссылающихся друг на друга зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (в виде параметров при определении функции). Какие-то будут созданы с помощью `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`, вызывая её в вашем коде.
---
Теперь, когда у вас есть представление о больших технических подробностях, это может быть полезно, если вы специально их искали.
Ещё раз, эти технические подробности, вероятно, будут полезны, только если вы специально их искали.
В противном случае просто ознакомьтесь с основными принципами в разделе выше: <a href="#in-a-hurry">Нет времени?</a>.
В противном случае, ознакомьтесь со сводкой из раздела выше: <a href="#in-a-hurry">Нет времени?</a>.

36
docs/ru/docs/benchmarks.md

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

68
docs/ru/docs/deployment/manually.md

@ -1,8 +1,8 @@
# Ручной запуск сервера
# Запуск сервера вручную
## Используйте команду `fastapi run`
Вкратце, используйте `fastapi run` для запуска вашего приложения FastAPI:
Кратко говоря, используйте `fastapi run` для запуска вашего приложения FastAPI:
<div class="termy">
@ -38,45 +38,45 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
</div>
Это подходящий вариант для большинства случаев. 😎
Это подойдет для большинства случаев. 😎
Вы можете использовать эту команду, чтобы, например, запустить ваше приложение **FastAPI** в контейнере, на сервере и т. д.
Вы можете использовать эту команду, например, для запуска вашего приложения **FastAPI** в контейнере, на сервере и т. д.
## ASGI-серверы
Давайте углубимся в детали.
FastAPI использует стандарт для создания веб-фреймворков и серверов в Python, называемый <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr>. FastAPI — это ASGI веб-фреймворк.
FastAPI использует стандарт для создания веб-фреймворков и серверов на Python под названием <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr>. FastAPI — это веб-фреймворк на основе ASGI.
Основное, что вам нужно для запуска приложения **FastAPI** (или любого другого ASGI приложения) на удалённой серверной машине — это программа сервера ASGI, такая как **Uvicorn**, которая поставляется по умолчанию с командой `fastapi`.
Основное, что вам требуется для запуска приложения **FastAPI** (или любого другого приложения на основе ASGI) на удаленной серверной машине — это программа ASGI-сервера, такая как **Uvicorn**, именно она используется по умолчанию в команде `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://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>: лёгкая и универсальная среда выполнения веб-приложений.
* <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 — легковесная и универсальная среда выполнения веб-приложений.
## Сервер как машина и сервер как программа
Есть небольшой нюанс в терминологии, который стоит помнить. 💡
Есть небольшая деталь в названиях, о которой стоит помнить. 💡
Слово "**сервер**" часто используется для обозначения как удалённого/облачного компьютера (физической или виртуальной машины), так и программы, работающей на этой машине (например, Uvicorn).
Слово "**сервер**" обычно используется для обозначения как удаленного/облачного компьютера (физической или виртуальной машины), так и программы, которая на этой машине работает (например, Uvicorn).
Просто держите в уме, что, когда вы видите слово "сервер", это может относиться к одному из этих двух понятий.
Просто имейте в виду, что когда вы видите "сервер", это может относиться к одному из этих двух значений.
Когда говорят о удалённой машине, часто упоминают просто **сервер**, но также могут называть его **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают какой-то тип удалённого компьютера, обычно с операционной системой Linux, на котором вы запускаете программы.
Когда речь идет о удаленной машине, часто используется термин **сервер**, но также можно встретить **машина**, **ВМ** (виртуальная машина), **нода**. Все это обозначает какую-то удаленную машину, обычно под управлением Linux, на которой вы запускаете программы.
## Установка программы сервера
## Установка программного сервера
При установке FastAPI, он поставляется с продакшн-сервером, Uvicorn, и вы можете запустить его с командой `fastapi run`.
При установке FastAPI он поставляется с продакшн-сервером Uvicorn, и его можно запустить с помощью команды `fastapi run`.
Но вы также можете установить ASGI-сервер вручную.
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и затем вы можете установить серверное приложение.
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем вы можете установить приложение сервера.
Например, чтобы установить Uvicorn:
Например, для установки Uvicorn:
<div class="termy">
@ -88,21 +88,21 @@ $ pip install "uvicorn[standard]"
</div>
Аналогичный процесс применим и к любой другой программе ASGI-сервера.
Схожий процесс применим к любым другим программам ASGI-серверов.
/// tip | Подсказка
Добавив `standard`, Uvicorn установит и будет использовать некоторые рекомендуемые дополнительные зависимости.
Добавляя `standard`, Uvicorn установит и будет использовать некоторые рекомендованные дополнительные зависимости.
В их числе `uvloop`, высокопроизводительная замена `asyncio`, которая обеспечивает ощутимый прирост скорости обработки запросов с большими объемами данных.
Сюда входит `uvloop`, высокопроизводительная замена для `asyncio`, которая дает значительное ускорение производительности асинхронных программ.
Когда вы устанавливаете FastAPI с чем-то вроде `pip install "fastapi[standard]"`, вы уже получаете `uvicorn[standard]`.
Когда вы устанавливаете FastAPI подобно `pip install "fastapi[standard]"`, вы уже получаете `uvicorn[standard]`.
///
## Запуск программы сервера
Если вы установили ASGI-сервер вручную, вам обычно потребуется указать строку для импорта в специальном формате, чтобы он мог импортировать ваше FastAPI-приложение:
Если вы установили ASGI-сервер вручную, обычно вам нужно передать импортную строку в специальном формате, чтобы он импортировал ваше FastAPI приложение:
<div class="termy">
@ -116,10 +116,10 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
/// note | Примечание
Команда `uvicorn main:app` обозначает:
Команда `uvicorn main:app` относится к:
* `main`: файл `main.py` (модуль Python).
* `app`: объект, созданный внутри `main.py` строкой `app = FastAPI()`.
* `main`: файл `main.py` (Python "модуль").
* `app`: объект, созданный внутри `main.py` с помощью строки `app = FastAPI()`.
Это эквивалентно:
@ -129,29 +129,29 @@ from main import app
///
Каждая из альтернатив программ ASGI-сервера будет иметь схожую команду, вы можете узнать больше в их документации.
Каждая из альтернативных программ ASGI-серверов будет иметь аналогичную команду, вы можете узнать больше в их документации.
/// warning | Предупреждение
Uvicorn и другие серверы поддерживают опцию `--reload`, которая полезна в процессе разработки.
Опция `--reload` потребляет намного больше ресурсов, она менее стабильна и так далее.
Опция `--reload` потребляет гораздо больше ресурсов, более нестабильна и т. д.
Она очень помогает во время **разработки**, но **не рекомендуется** использовать её в **продакшн**.
Она очень помогает во время **разработки**, но **не следует** использовать её в **продакшне**.
///
## Концепции развёртывания
Эти примеры запускают серверные программы (например, Uvicorn), начиная с **одного процесса**, слушающего все IP-адреса (`0.0.0.0`) на определенном порту (например, `80`).
Эти примеры запускают программное обеспечение сервера (например, Uvicorn), начиная **один процесс**, слушающий все IP (`0.0.0.0`) на заранее определенном порту (например, `80`).
Это основная идея. Но вы, вероятно, захотите позаботиться о некоторых дополнительных вещах, таких как:
Это основная идея. Но, вероятно, вам захочется позаботиться о некоторых дополнительных вещах, таких как:
* Безопасность - HTTPS
* Запуск при старте системы
* Запуск при старте
* Перезапуски
* Репликация (количество запущенных процессов)
* Память
* Предыдущие шаги перед запуском
* Предварительные действия перед запуском
Я расскажу вам больше о каждой из этих концепций, о том, как их воспринимать, и дам конкретные примеры стратегий для работы с ними в следующих главах. 🚀
Я расскажу вам больше о каждой из этих концепций, как о них думать и приведу конкретные примеры со стратегиями их решения в следующих главах. 🚀

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

@ -1,258 +1,256 @@
# Помочь 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
<a href="https://twitter.com/fastapi" class="external-link" target="_blank">Подписывайтесь на @fastapi в **Twitter**</a>, чтобы получать последние новости о **FastAPI**. 🐦
<a href="https://twitter.com/fastapi" class="external-link" target="_blank">Подписаться на @fastapi в **Twitter**</a> для получения наисвежайших новостей о **FastAPI**. 🐦
## Добавить звезду **FastAPI** на GitHub
## Добавить **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
## Отслеживать свежие выпуски в репозитории на 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".
Таким образом, вы будете получать уведомления (на ваш email) каждый раз, когда будет выходить новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми функциями.
Таким образом вы будете получать уведомления (по электронной почте) каждый раз, когда будет выпускаться новая версия **FastAPI** с исправлениями ошибок и новыми возможностями.
## Связаться с автором
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себаcтиян Рамирез / `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> (это отдельный аккаунт).
* Поделиться со мной, как вы используете 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 🤷‍♂).
* Читайте мои статьи (или подпишитесь на меня) на <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**
## Оставить сообщение в 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">Напишите твит о **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/about/" 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://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Сообщите, что используете **FastAPI** на StackShare</a>.
## Помочь другим с их вопросами на GitHub
## Помочь другим с вопросами на GitHub
Вы можете помочь другим с их вопросами:
Вы можете попробовать помочь другим с их вопросами на:
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
* <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-people.md#fastapi-experts){.internal-link target=_blank}. 🎉
Если вы будете много помогать людям с их вопросами, вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉
Просто помните, самое важное: старайтесь быть добрыми. Люди приходят со своими разочарованиями и часто не задают вопросы так, как следовало бы, но старайтесь быть как можно добрее. 🤗
Только помните, самое важное — старайтесь быть добрыми. Люди приходят со своими разочарованиями и в большинстве случаев не задают вопросы лучшим образом, но старайтесь проявить максимум доброты. 🤗
Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимным. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
Идея сообщества **FastAPI** заключается в доброжелательности и гостеприимстве. В то же время не допускайте издевательств или неуважительного поведения к другим. Мы должны заботиться друг о друге.
---
Как помочь другим с их вопросами (в обсуждениях или issues):
Как помочь другим с вопросами (в обсуждениях или в вопросах):
### Понять вопрос
* Убедитесь, что вы поняли, какова **цель** и заслуга человека, задающего вопрос.
* Удостоверьтесь, что понимаете **цель** и обстоятельства задающего вопрос.
* Затем убедитесь, что вопрос (в большинстве случаев это вопрос) **ясен**.
* Затем удостоверьтесь, что вопрос (в подавляющем большинстве случаев это именно вопрос) для вас **ясен**.
* Во многих случаях вопрос касается выдуманного решения пользователя, но существует **лучшее** решение. Если вы сможете понять основную проблему и контекст лучше, вы сможете предложить альтернативное **решение**.
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и **лучше**. Если вы поймете проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
* Если вопрос вам не ясен, попросите больше **деталей**.
* Если вопрос вам непонятен, запросите больше **деталей**.
### Воспроизведите проблему
### Воспроизвести проблему
В большинстве случаев и вопросов что-то связано с **исходным кодом** пользователя.
Для большинства случаев и большинства вопросов существует что-то связанное с **исходным кодом** того, кто задает вопрос.
В большинстве случаев и по большинству вопросов есть что-то связанное с **исходным кодом** вопрошающего.
Во многих случаях они будут копировать только фрагмент кода, но этого недостаточно для **воспроизведения проблемы**.
* Вы можете попросить их предоставить <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: **закрыть** тикет.
* Если вопрос решен, попросите их:
* В 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/discussions/new?category=questions" 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, например, чтобы:
* Задать **вопрос** или попросить помощи в решении **проблемы**.
* Задать **вопрос** или спросить о **проблеме**.
* Предложить новую **возможность**.
**Заметка**: если Вы создаёте подобные вопросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉
**Заметка**: если вы это сделаете, я попрошу вас также помочь другим. 😉
## Проверять пулл-реквесты
## Проверять пул-реквесты
Вы можете помочь мне проверять пулл-реквесты других участников.
Вы можете помочь мне проверять пул-реквесты от других участников.
Снова повторяю, пожалуйста, старайтесь быть добрыми. 🤗
И повторюсь, постарайтесь быть добрыми. 🤗
---
О том, что нужно иметь в виду при проверке пулл-реквестов:
Вот что стоит иметь в виду при проверке пул-реквестов:
### Понять проблему
* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение в GitHub Discussion или ticket.
* Во-первых, убедитесь, что **понимаете проблему**, которую пул-реквест пытается решить. Возможно, это будет сделано через более длинное обсуждение в 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#translations){.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} на ваш язык.
* Вы также можете помочь проверять переводы, сделанные другими.
* Предложить новые разделы документации.
* Исправить существующую проблему/баг.
* Исправить существующую проблему/ошибку.
* Убедитесь, что добавили тесты.
* Чтобы добавить новую возможность.
* Добавить новую возможность.
* Убедитесь, что добавили тесты.
* Убедитесь, что добавили документацию, если это необходимо.
* Убедитесь, что добавили документацию, если она необходима.
## Помогите поддерживать FastAPI
## Помочь поддерживать FastAPI
Помогите мне поддержать **FastAPI**! 🤓
Помогите мне поддерживать **FastAPI**! 🤓
Есть много работы, и большую часть из неё **ВЫ** можете сделать.
Предстоит еще много работы, и в большей части из нее **вы** можете помочь.
Основные задачи, которые вы можете сделать прямо сейчас:
Основные задачи, которые вы можете сделать сейчас:
* [Помочь другим с их вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (смотрите вышестоящую секцию).
* [Проверить пул-реквесты](#review-pull-requests){.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/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>, там больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.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 я могу быть уверен, что всегда отвечаю на все, даже если это займет время. Я не могу сделать то же самое в чатах. 😅
Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только вопросы решаемые на GitHub учитываются в получении титула [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
Общение в чатах не так легко ищется, как на GitHub, поэтому вопросы и ответы могут затеряться в разговоре. И только запросы на GitHub учитываются для получения звания [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, поэтому, вероятнее всего, вы получите больше внимания на GitHub.
С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время trouver кого-то, с кем можно поговорить. 😄
С другой стороны в чатах тысячи пользователей, поэтому вы с большой вероятностью найдете кого-то, с кем можно поговорить, почти в любое время. 😄
## Спонсировать автора
## Спонсорство для автора
Если ваш **продукт/компания** зависит от или связан с **FastAPI** и вы хотите донести до его пользователей, вы можете спонсировать автора (меня) через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>. В зависимости от уровня, вы можете получать некоторые дополнительные преимущества, такие как значок в документации. 🎁
Если ваш **продукт/компания** зависят от **FastAPI** или связаны с ним, и вы хотите донести до пользователей, вы можете также спонсировать автора (меня) через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>. В зависимости от уровня поддержки, вы можете получить дополнительные преимущества, такие как знак в документации. 🎁
---
Благодарствую! 🚀
Благодарю! 🚀

178
docs/ru/docs/index.md

@ -8,7 +8,7 @@
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>Фреймворк FastAPI: высокая производительность, простота освоения, быстрая разработка, готов к использованию в производстве</em>
<em>Готовый к внедрению высокопроизводительный фреймворк, простой в изучении и разработке.</em>
</p>
<p align="center">
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
@ -33,7 +33,7 @@
---
FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API, использующий Python и стандартные аннотации типов Python.
FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API используя Python, в основе которого лежит стандартная аннотация типов Python.
Ключевые особенности:
@ -46,7 +46,7 @@ FastAPI — это современный, быстрый (высокопрои
* **Надежность**: Получите готовый к работе код. С автоматической интерактивной документацией.
* **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (ранее известном как Swagger) и <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* оценка на основе тестов внутренней команды разработчиков, создающих продакшн приложения.</small>
<small>* оценка на основе тестов внутренней команды разработчиков, создающих производственные приложения.</small>
## Спонсоры
@ -67,74 +67,68 @@ FastAPI — это современный, быстрый (высокопрои
## Отзывы
"_[...] В последнее время я много использую **FastAPI**. [...] На самом деле, я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._"
"_В последнее время я много где использую **FastAPI**. [...] На самом деле я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._"
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
---
"_Мы приняли библиотеку **FastAPI** для создания сервера **REST**, к которому можно обращаться для получения **прогнозов**. [для Ludwig]_"
"_Мы использовали библиотеку **FastAPI** для создания сервера **REST**, к которому можно делать запросы для получения **прогнозов**. [для Ludwig]_"
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
---
"_**Netflix** рада объявить о выпуске фреймворка для оркестрации **кризисного управления**: **Dispatch**! [создан с использованием **FastAPI**]_"
"_**Netflix** рада объявить о выпуске опенсорсного фреймворка для оркестровки **антикризисного управления**: **Dispatch**! [создана с помощью **FastAPI**]_"
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
---
"_Меня невероятно радует **FastAPI**. Это так весело!_"
"_Я в полном восторге от **FastAPI**. Это так весело!_"
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> ведущий подкаста</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"_Честно говоря, то, что вы создали, выглядит очень солидно и отшлифовано. В многих отношениях это то, чем я хотел, чтобы было **Hug** — это действительно вдохновляет, когда кто-то создает такое._"
"_Честно говоря, то, что вы создали, выглядит очень солидно и отполировано. Во многих смыслах я хотел, чтобы **Hug** был именно таким — это действительно вдохновляет, когда кто-то создаёт такое._"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> создатель</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания REST API, ознакомьтесь с **FastAPI** [...] Это быстрый, простой в использовании и в изучении фреймворк [...]_"
"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания REST API, ознакомьтесь с **FastAPI** [...] Он быстрый, лёгкий и простой в изучении [...]_"
"_Мы перешли на **FastAPI** для наших **API** [...] Думаю, он вам понравится [...]_"
"_Мы перешли на **FastAPI** для наших **API** [...] Я думаю, вам тоже понравится [...]_"
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
---
"_Если кто-то хочет создать продакшн Python API, я бы настоятельно рекомендовал **FastAPI**. Он **прекрасно разработан**, **прост в использовании** и **высокомасштабируем**, он стал **ключевым компонентом** нашей стратегии разработки API-first и управляет множеством автоматизаций и сервисов, таких как наш виртуальный инженер TAC._"
"_Если кто-то хочет построить продакшн 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>
---
"_Если кто-то хочет создать производственный Python API, я бы очень рекомендовал **FastAPI**. Он **замечательно спроектирован**, **прост в использовании** и **очень масштабируем**, он стал **ключевым компонентом** в нашей стратегии разработки API. Благодаря нему автоматизация и сервисы, такие как наш Виртуальный Инженер 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 для CLI
## **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>
Если вы создаете приложение для <abbr title="Command Line Interface">CLI</abbr>, используемое в терминале вместо веб API, ознакомьтесь с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
Если вы создаете приложение <abbr title="Интерфейс командной строки">CLI</abbr> для использования в терминале вместо веб-API, ознакомьтесь с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** — младший брат FastAPI. Он предназначен быть **FastAPI для CLI**. ⌨️ 🚀
**Typer** — младший брат FastAPI. И он предназначен для использования в качестве **интерфейса командной строки для FastAPI**. ⌨️ 🚀
## Требования
## Зависимости
FastAPI опирается на гигантов:
FastAPI стоит на плечах гигантов:
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> для веб-компонентов.
* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> для работы с данными.
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> для части связанной с вебом.
* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> для части связанной с данными.
## Установка
Создайте и активируйте <a href="https://fastapi.tiangolo.com/virtual-environments/" class="external-link" target="_blank">виртуальное окружение</a>, а затем установите FastAPI:
Создайте и активируйте <a href="https://fastapi.tiangolo.com/virtual-environments/" class="external-link" target="_blank">виртуальное окружение</a>, затем установите FastAPI:
<div class="termy">
@ -146,13 +140,13 @@ $ pip install "fastapi[standard]"
</div>
**Примечание**: Убедитесь, что вы используете кавычки для `"fastapi[standard]"`, чтобы обеспечить его работу во всех терминалах.
**Примечание**: Убедитесь, что вы взяли в кавычки `"fastapi[standard]"`, чтобы это работало во всех терминалах.
## Пример
### Создание
Создайте файл `main.py` с:
Создайте файл `main.py` со следующим содержимым:
```Python
from typing import Union
@ -197,7 +191,7 @@ async def read_item(item_id: int, q: Union[str, None] = None):
**Примечание**:
Если вы не знаете, проверьте раздел _"Нет времени?"_ <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">в документации об `async` и `await`</a>.
Если вы не знаете, проверьте раздел _"Торопитесь?"_ <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">в документации об `async` и `await`</a>.
</details>
@ -235,9 +229,9 @@ INFO: Application startup complete.
<details markdown="1">
<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>.
Команда `fastapi dev` читает ваш файл `main.py`, обнаруживает приложение **FastAPI** в нем и запускает сервер с использованием <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>.
По умолчанию `fastapi dev` запускает приложение с включенной авто-перезагрузкой для локальной разработки.
По умолчанию `fastapi dev` запускается с включенной авто-перезагрузкой для локальной разработки.
Вы можете узнать больше об этом в <a href="https://fastapi.tiangolo.com/fastapi-cli/" target="_blank">документации FastAPI CLI</a>.
@ -245,7 +239,7 @@ INFO: Application startup complete.
### Проверка
Откройте ваш браузер на <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Откройте браузер на <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Вы увидите следующий JSON ответ:
@ -255,10 +249,10 @@ INFO: Application startup complete.
Вы уже создали API, который:
* Получает HTTP-запросы в _пути_ `/` и `/items/{item_id}`.
* Оба _пути_ принимают операции `GET` <em>(также известные как HTTP методы)</em>.
* _Путь_ `/items/{item_id}` принимает _параметр пути_ `item_id`, который должен быть `int`.
* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.
* И первый и второй _путь_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
* _путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
* _путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
### Интерактивная документация по API
@ -276,11 +270,11 @@ INFO: Application startup complete.
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Обновление примера
## Пример обновления
Теперь измените файл `main.py`, чтобы получать тело из `PUT` запроса.
Теперь измените файл `main.py`, чтобы получить тело ответа из `PUT` запроса.
Объявите тело, используя стандартную типизацию Python, благодаря Pydantic.
Объявите тело, используя стандартную типизацию Python, спасибо Pydantic.
```Python hl_lines="4 9-12 25-27"
from typing import Union
@ -312,41 +306,41 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
Сервер `fastapi dev` должен автоматически перезагрузиться.
Сервер должен перезагрузиться автоматически.
### Обновление интерактивной документации по API
### Интерактивное обновление документации API
Теперь перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* Интерактивная документация API обновится автоматически, включая новое тело:
* Интерактивная документация API будет автоматически обновляться, включая новое тело:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Нажмите кнопку "Try it out", чтобы заполнить параметры и напрямую взаимодействовать с API:
* Нажмите на кнопку "Try it out", это позволит вам заполнить параметры и напрямую взаимодействовать с API:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* Затем нажмите кнопку "Execute", интерфейс свяжется с вашим API, отправит параметры, получит результаты и покажет их на экране:
* Затем нажмите кнопку "Execute", пользовательский интерфейс свяжется с вашим API, отправит параметры, получит результаты и отобразит их на экране:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Обновление альтернативной документации по API
### Альтернативное обновление документации API
А теперь перейдите на <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* Альтернативная документация также отразит новый параметр запроса и тело:
* Альтернативная документация также будет отражать новый параметр и тело запроса:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Итоги
### Подведём итоги
Подводя итоги, вы объявляете **один раз** типы параметров, тела и т. д. в качестве параметров функции.
Таким образом, вы объявляете **один раз** типы параметров, тело и т. д. в качестве параметров функции.
Вы делаете это с использованием стандартной современной типизации Python.
Вы делаете это используя стандартную современную типизацию Python.
Вам не нужно изучать новый синтаксис, методы или классы конкретной библиотеки и т. д.
Просто стандартный **Python**.
Только стандартный **Python**.
Например, для `int`:
@ -360,24 +354,24 @@ item_id: int
item: Item
```
...и с этим единственным объявлением вы получаете:
... и с этим единственным объявлением вы получаете:
* Поддержку редактора, включая:
* Поддержка редактора, в том числе:
* Автозавершение.
* Проверку типов.
* Валидацию данных:
* Автоматические и чёткие ошибки, когда данные недействительны.
* Валидацию даже для глубоко вложенных объектов JSON.
* <abbr title="также известна как: сериализация, синтаксический анализ, маршаллинг">Преобразование</abbr> входных данных: поступающих из сети в данные и типы Python. Чтение из:
* Проверка типов.
* Валидация данных:
* Автоматические и четкие ошибки, когда данные недействительны.
* Проверка даже для глубоко вложенных объектов JSON.
* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> входных данных: поступающие из сети в объекты Python с соблюдением типов. Чтение из:
* JSON.
* Параметров пути.
* Параметров запроса.
* Cookies.
* Заголовков.
* HTTP-заголовков.
* Форм.
* Файлов.
* <abbr title="также известна как: сериализация, синтаксический анализ, маршаллинг">Преобразование</abbr> выходных данных: преобразование данных и типов Python в данные сети (например JSON):
* Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т. д.).
* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> выходных данных: преобразование объектов Python в данные передаваемые по сети интернет (такие как JSON):
* Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т.д.).
* Объекты `datetime`.
* Объекты `UUID`.
* Модели баз данных.
@ -390,28 +384,28 @@ item: Item
Возвращаясь к предыдущему примеру кода, **FastAPI** будет:
* Проверять, что в пути есть `item_id` для `GET` и `PUT` запросов.
* Проверять, что `item_id` имеет тип `int` для `GET` и `PUT` запросов.
* Если это не так, клиент увидит полезную, чёткую ошибку.
* Проверять наличие `item_id` в пути для запросов `GET` и `PUT`.
* Проверять, что `item_id` имеет тип `int` для запросов `GET` и `PUT`.
* Если это не так, клиент увидит полезную чёткую ошибку.
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` запросов.
* Поскольку параметр `q` объявлен с `= None`, он является необязательным.
* Без `None` он бы был обязательным (как тело в случае с `PUT`).
* Без `None` он был бы необходим (как тело в случае с `PUT`).
* Для `PUT` запросов к `/items/{item_id}` читать тело как JSON:
* Проверять, что у него есть обязательное свойство `name`, которое должно быть `str`.
* Проверять, что у него есть обязательное свойство `price`, которое должно быть `float`.
* Проверять, что у него есть необязательное свойство `is_offer`, которое должно быть `bool`, если оно присутствует.
* Всё это также будет работать для глубоко вложенных объектов JSON.
* Проверять, что у него есть обязательный атрибут `name`, который должен быть `str`.
* Проверять, что у него есть обязательный атрибут `price`, который должен быть `float`.
* Проверять, что у него есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.
* Все это также будет работать для глубоко вложенных объектов JSON.
* Преобразовывать из и в JSON автоматически.
* Документировать всё с помощью OpenAPI, что можно использовать:
* Документировать с помощью OpenAPI все, что может быть использовано:
* Системы интерактивной документации.
* Автоматические системы генерации клиентского кода для многих языков.
* Предоставлять 2 интерактивных веб-интерфейса документации напрямую.
* Системы автоматической генерации клиентского кода для многих языков.
* Обеспечит 2 интерактивных веб-интерфейса документации напрямую.
---
Мы только немного поверхностно ознакомились, но вы уже поняли, как все это работает.
Мы только немного копнули поверхность, но вы уже поняли, как все это работает.
Попробуйте изменить строку:
Попробуйте изменить строку с помощью:
```Python
return {"item_name": item.name, "item_id": item_id}
@ -429,30 +423,30 @@ item: Item
... "item_price": item.price ...
```
...и посмотрите, как ваш редактор автоматически завершает атрибуты и знает их типы:
... и посмотрите, как ваш редактор будет автоматически заполнять атрибуты и узнавать их типы:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
Более полный пример с дополнительными функциями см. в <a href="https://fastapi.tiangolo.com/tutorial/">Учебное руководство - Руководство пользователя</a>.
**Внимание, спойлер**: учебное руководство - Руководство пользователя включает:
**Осторожно, спойлер**: руководство пользователя включает в себя:
* Объявление **параметров** из других мест, таких как: **заголовки**, **cookies**, **поля формы** и **файлы**.
* Как установить **ограничительные проверки** такие как `maximum_length` или `regex`.
* Очень мощная и простая в использовании система **<abbr title="также известная как компоненты, ресурсы, провайдеры, услуги, инъекции">Внедрение Зависимостей</abbr>**.
* Безопасность и аутентификация, включая поддержку **OAuth2** с **токенами JWT** и **HTTP Basic** авторизация.
* Более продвинутые (но столь же простые) методы объявления **глубоко вложенных моделей JSON** (благодаря Pydantic).
* Очень мощная и простая в использовании система **<abbr title="также известная как компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
* Безопасность и аутентификация, включая поддержку **OAuth2** с **токенами JWT** и **HTTP Basic** аутентификацию.
* Более продвинутые (но столь же простые) методы объявления **глубоко вложенных моделей JSON** (спасибо Pydantic).
* **GraphQL** интеграция с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
* Много дополнительных функций (благодаря Starlette), как например:
* **WebSockets**
* невероятно простые тесты, основанные на HTTPX и `pytest`
* Множество дополнительных функций (благодаря Starlette), таких как:
* **Веб-сокеты**
* очень простые тесты на основе HTTPX и `pytest`
* **CORS**
* **Сессии с использованием Cookie**
* **Сессии с использованием cookie**
* ...и многое другое.
## Производительность
Независимые бенчмарки 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). (*)
Чтобы узнать больше об этом, см. раздел <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Тесты производительности</a>.
@ -462,7 +456,7 @@ FastAPI зависит от Pydantic и Starlette.
### Зависимости `standard`
Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он включает группу зависимостей `standard`:
Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он поставляется с группой необязательных зависимостей `standard`:
Используется Pydantic:
@ -476,26 +470,26 @@ FastAPI зависит от Pydantic и Starlette.
Используется FastAPI:
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - для сервера, который загружает и обслуживает ваше приложение. Это включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), необходимые для высокопроизводительного обслуживания.
* <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>.
* Включает `fastapi-cloud-cli`, который позволяет развернуть ваше приложение FastAPI в <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
### Без зависимостей `standard`
Если вы не хотите включать необязательные зависимости `standard`, вы можете установить FastAPI с помощью `pip install fastapi` вместо `pip install "fastapi[standard]"`.
Если вы не хотите включать необязательные зависимости `standard`, вы можете установить с `pip install fastapi` вместо `pip install "fastapi[standard]"`.
### Без `fastapi-cloud-cli`
Если вы хотите установить FastAPI с стандартными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с помощью `pip install "fastapi[standard-no-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.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - для дополнительных типов, которые можно использовать с Pydantic.
Дополнительные необязательные зависимости FastAPI:

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

@ -1,28 +1,28 @@
# Full Stack FastAPI Шаблон
Шаблоны обычно идут с определенной настройкой, но они разработаны гибкими и настраиваемыми. Это позволяет вам модифицировать и адаптировать их в соответствии с требованиями вашего проекта, превращая их в отличную отправную точку. 🏁
Шаблоны, хотя и содержат определённые настройки, разработаны для гибкости и настраиваемости. Это позволяет вам модифицировать и адаптировать их в соответствии с требованиями вашего проекта, делая их отличной отправной точкой. 🏁
Вы можете использовать этот шаблон, чтобы начать, так как он включает множество начальных настроек, безопасности, базу данных и некоторые API эндпоинты уже готовы.
Вы можете использовать этот шаблон, чтобы быстрее начать работу, так как он включает в себя множество начальных настроек, функции безопасности, баз данных и несколько эндпоинтов API.
Репозиторий на GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
Репозиторий GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
## Full Stack FastAPI Шаблон - Технологии и Особенности
## Full Stack FastAPI Шаблон - Технологический стек и функциональные возможности
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python бэкенда API.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия Python с SQL базой данных (ORM).
- ⚡ [**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 базы данных.
- 💾 [PostgreSQL](https://www.postgresql.org) как SQL база данных.
- 🚀 [React](https://react.dev) для фронтенда.
- 💃 Использование TypeScript, hooks, [Vite](https://vitejs.dev), и других компонентов современного стека фронтенда.
- 🎨 [Chakra UI](https://chakra-ui.com) для компонентов фронтенда.
- 🤖 Автоматически сгенерированный фронтенд клиент.
- 💃 Использование 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 токенов.
- 🔒 Безопасное хэширование паролей по умолчанию.
- 🔑 Аутентификация на основе JWT токенов.
- 📫 Восстановление пароля через email.
- ✅ Тесты с использованием [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) в качестве реверс-прокси / балансировщика нагрузки.
- 🚢 Инструкции по развёртыванию с Docker Compose, включая настройку фронтенд прокси Traefik для автоматического управления HTTPS сертификатами.
- 🚢 Инструкции по развертыванию с использованием Docker Compose, включая настройку фронтенд-прокси Traefik для автоматической обработки HTTPS-сертификатов.
- 🏭 CI (непрерывная интеграция) и CD (непрерывное развёртывание) на базе GitHub Actions.

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

@ -1,24 +1,24 @@
# Тело запроса - Множество параметров
# Body - Множество параметров
Теперь, когда мы увидели, как использовать `Path` и `Query`, давайте рассмотрим более продвинутые примеры объявления тела запроса.
## Объединение `Path`, `Query` и параметров тела запроса
Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления параметров тела запроса, и **FastAPI** автоматически поймёт, что с ними делать.
Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления тела запроса, и **FastAPI** автоматически определит, что с ними делать.
Вы также можете объявлять параметры тела как необязательные, установив значение по умолчанию `None`:
Вы также можете объявить параметры тела запроса как необязательные, установив значение по умолчанию, равное `None`:
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
/// note | Заметка
Заметьте, что в данном случае параметр `item`, который будет взят из тела запроса, необязателен. Так как у него установлено значение `None` по умолчанию.
Заметьте, что в данном случае параметр `item`, который будет взят из тела запроса, необязателен. Так как было установлено значение `None` по умолчанию.
///
## Множественные параметры тела
## Несколько параметров тела запроса
В предыдущем примере, *операции пути* ожидали JSON-тело с атрибутами `Item`, например:
В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON с параметрами, соответствующими атрибутам `Item`, например:
```JSON
{
@ -29,13 +29,13 @@
}
```
Но вы также можете объявить множество параметров тела запроса, например параметры `item` и `user`:
Но вы также можете объявить множество параметров тела запроса, например `item` и `user`:
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
В этом случае **FastAPI** заметит, что в функции больше одного параметра тела (два параметра, которые являются моделями Pydantic).
В этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются моделями Pydantic).
Таким образом, в теле запроса будут использоваться имена параметров в качестве ключей (имен полей), и будет ожидаться запрос следующего формата:
Таким образом, имена параметров будут использоваться в качестве ключей (имён полей) в теле запроса, и будет ожидаться запрос следующего формата:
```JSON
{
@ -52,29 +52,29 @@
}
```
/// note | Заметка
/// note | Внимание
Обратите внимание, что хотя параметр `item` был объявлен таким же образом, как и раньше, теперь предполагается, что он находится внутри тела запроса с ключом `item`.
Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`.
///
**FastAPI** сделает автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с параметром `user`.
**FastAPI** выполнит автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с `user`.
Он выполнит проверку составных данных и задокументирует это в схеме OpenAPI и автоматической документации.
Произойдет проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах.
## Отдельные значения в теле
## Отдельные значения в теле запроса
Так же, как существуют `Query` и `Path` для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет эквивалент для тела - `Body`.
Точно так же, как `Query` и `Path` используются для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет аналогичный инструмент - `Body`.
Например, расширяя предыдущую модель, вы можете решить, что вам нужен ещё один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`.
Например, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`.
Если вы объявите его как есть, поскольку это простой тип данных, **FastAPI** будет считать, что это query-параметр.
Если вы объявите его без указания, какой именно объект (Path, Query, Body и т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать его query-параметром.
Но вы можете указать **FastAPI** обрабатывать его как ещё один ключ тела запроса, используя `Body`:
Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`:
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
В этом случае **FastAPI** будет ожидать тело такого вида:
В этом случае, **FastAPI** будет ожидать тело запроса в формате:
```JSON
{
@ -92,13 +92,13 @@
}
```
И снова, он преобразует типы данных, проверит, задокументирует и т.д.
И все будет работать так же: преобразование типов данных, валидация, документирование и т.д.
## Множество body-параметров и query
## Множество body и query параметров
Конечно, вы также можете объявлять дополнительные query-параметры в любое время, дополнительно к любым body-параметрам.
Конечно, вы также можете объявлять дополнительные query-параметры в любое время, в дополнение к любым body-параметрам.
Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
Поскольку по умолчанию отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
```Python
q: Union[str, None] = None
@ -120,19 +120,19 @@ q: str | None = None
///
## Встраивание одного параметра тела
## Добавление одного body-параметра
Предположим, у вас есть только один параметр тела `item` из модели Pydantic `Item`.
Предположим, у вас есть только один body-параметр `item` из Pydantic-модели `Item`.
По умолчанию **FastAPI** ожидает получить тело запроса напрямую.
По умолчанию, **FastAPI** ожидает получить тело запроса напрямую.
Но если вы хотите, чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`:
Но если вы хотите, чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, также как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`:
```Python
item: Item = Body(embed=True)
```
как в этом примере:
так же, как в этом примере:
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
@ -149,7 +149,7 @@ item: Item = Body(embed=True)
}
```
вместо:
вместо этого:
```JSON
{
@ -162,10 +162,10 @@ item: Item = Body(embed=True)
## Резюме
Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря на то, что запрос может содержать только одно тело.
Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря даже на то, что запрос может содержать только одно тело.
Но **FastAPI** справится с этим, предоставит вам правильные данные в вашей функции, а также выполнит валидацию и документирование правильной схемы *операции пути*.
Но **FastAPI** справится с этим, предоставит правильные данные в вашей функции, а также сделает валидацию и документацию правильной схемы *операции пути*.
Вы также можете объявлять отдельные значения для получения в рамках тела запроса.
Вы также можете объявить отдельные значения для получения в рамках тела запроса.
И вы можете настроить **FastAPI** так, чтобы включить тело запроса в ключ, даже если объявлен только один параметр.
И вы можете настроить **FastAPI** таким образом, чтобы включить тело запроса в ключ, даже если объявлен только один параметр.

61
docs/ru/docs/tutorial/cors.md

@ -1,54 +1,54 @@
# CORS (Cross-Origin Resource Sharing)
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS или "Cross-Origin Resource Sharing"</a> относится к ситуациям, когда фронтенд, работающий в браузере, использует JavaScript-код для взаимодействия с бэкендом, который находится в другом "источнике" по сравнению с фронтендом.
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Понятие CORS или "Cross-Origin Resource Sharing"</a> относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом "источнике" ("origin").
## Источник
Источник - это сочетание протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`).
Источник - это совокупность протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`).
Таким образом, все это различные источники:
Поэтому это три разных источника:
* `http://localhost`
* `https://localhost`
* `http://localhost:8080`
Даже если они все находятся на `localhost`, они используют разные протоколы или порты, следовательно, это разные "источники".
Даже если они все расположены в `localhost`, они используют разные протоколы и порты, а значит, являются разными источниками.
## Шаги
Предположим, у вас есть фронтенд, работающий в вашем браузере по адресу `http://localhost:8080`, и его JavaScript пытается взаимодействовать с бэкендом, работающим по адресу `http://localhost` (так как порт не указан, браузер предполагает использование порта `80`).
Допустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`).
Затем браузер отправит HTTP-запрос `OPTIONS` на бэкенд на порту `80`, и если бэкенд отправит соответствующие заголовки, разрешающие взаимодействие с этого отличающегося источника (`http://localhost:8080`), тогда браузер на порту `8080` позволит JavaScript на фронтенде отправить свой запрос на бэкенд на порту `80`.
Затем браузер отправит бэкенду HTTP-запрос `OPTIONS`, и если бэкенд вернёт соответствующие HTTP-заголовки для авторизации взаимодействия с другим источником (`http://localhost:8080`), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд.
Чтобы это воплотилось, бэкенд на порту `80` должен иметь список "разрешённых источников".
Чтобы это работало, у бэкенда должен быть список "разрешённых источников" ("allowed origins").
В данном случае список должен содержать `http://localhost:8080`, чтобы фронтенд на порту `8080` работал корректно.
В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд работал корректно.
## Подстановочные символы
Можно указать список, используя подстановочный символ `"*"`, чтобы разрешить любые источники.
В качестве списка источников можно указать подстановочный символ `"*"` ("wildcard"), чтобы разрешить любые источники.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё, что связано с учётными данными: куки, заголовки Authorization с токенами Bearer и т.п.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, HTTP-заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п.
Поэтому, чтобы всё функционировало правильно, лучше явно указывать разрешённые источники.
Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.
## Использование `CORSMiddleware`
Вы можете настроить это в вашем приложении **FastAPI** с помощью `CORSMiddleware`.
Вы можете настроить этот механизм в вашем **FastAPI** приложении, используя `CORSMiddleware`.
* Импортируйте `CORSMiddleware`.
* Создайте список разрешённых источников (как строки).
* Добавьте его как "middleware" к вашему приложению **FastAPI**.
* Создайте список разрешённых источников (в виде строк).
* Добавьте его как "middleware" к вашему **FastAPI** приложению.
Вы также можете указать, позволяет ли ваш бэкенд использовать:
Вы также можете указать, разрешает ли ваш бэкенд использование:
* Учётные данные (заголовки Authorization, куки и т.п.).
* Специфические HTTP-методы (`POST`, `PUT`) или все из них с помощью подстановочного символа `"*"`.
* Специфические HTTP-заголовки или все из них с помощью подстановочного символа `"*"`.
* Учётных данных (включая HTTP-заголовки Authorization, куки и т.п.).
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
{* ../../docs_src/cors/tutorial001.py hl[2,6:12,14:20] *} <!-- Updated highlighting lines as '13:19' changed to '14:20' in the new code block -->
{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
По умолчанию параметры, используемые в реализации `CORSMiddleware`, имеют ограничительные значения, поэтому вам необходимо явно разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
`CORSMiddleware` использует для параметров "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
Поддерживаются следующие аргументы:
@ -56,30 +56,33 @@
* `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\.example\.org'`.
* `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию равно `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы.
* `allow_headers` - Список HTTP-заголовков, которые должны поддерживаться при кросс-доменных запросах. По умолчанию равно `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">простых CORS-запросов</a>.
* `allow_credentials` - Указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. Ни один из параметров `allow_origins`, `allow_methods` и `allow_headers` не может быть установлен в `['*']`, если `allow_credentials` установлен в `True`. Все они должны быть <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">явно указаны</a>.
* `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`.
* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию равно `600`.
Middleware отвечает на два определённых типа HTTP-запросов...
`CORSMiddleware` отвечает на два типа HTTP-запросов...
### CORS-запросы с предварительной проверкой
Это любые `OPTIONS` запросы с заголовками `Origin` и `Access-Control-Request-Method`.
Это любые `OPTIONS` запросы с HTTP-заголовками `Origin` и `Access-Control-Request-Method`.
В этом случае middleware перехватывает входящий запрос и отправляет соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` для информационных целей.
В этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` в информационных целях.
### Простые запросы
Любые запросы с заголовком `Origin`. В этом случае middleware пропускает запрос дальше, как обычно, но добавляет соответствующие CORS-заголовки к ответу.
Любые запросы с заголовком `Origin`. В этом случае middleware передаст запрос дальше как обычно, но добавит соответствующие CORS-заголовки к ответу.
## Дополнительная информация
## Больше информации
Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">документации CORS от Mozilla</a>.
Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Документации CORS от Mozilla</a>.
/// note | Технические детали
Вы также можете использовать `from starlette.middleware.cors import CORSMiddleware`.
**FastAPI** предоставляет несколько middleware в `fastapi.middleware` исключительно для вашего удобства как разработчика. Но большинство доступных middleware непосредственно поступают из Starlette.
**FastAPI** предоставляет несколько middleware в `fastapi.middleware` только для вашего удобства как разработчика. Но большинство доступных middleware взяты напрямую из Starlette.
///

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

@ -1,57 +1,56 @@
# Дополнительные модели
Продолжая с предыдущим примером, будет обычным явлением иметь более одной связанной модели.
В продолжение прошлого примера, будет обычным делом иметь несколько связанных между собой моделей.
Это особенно применимо в случае пользовательских моделей, потому что:
Это особенно касается моделей пользователя, потому что:
* **Модель для ввода** должна иметь возможность включать пароль.
* **Модель для ввода** должна иметь возможность содержать пароль.
* **Модель для вывода** не должна содержать пароль.
* **Модель для базы данных** вероятно должна включать хэшированный пароль.
* **Модель для базы данных**, вероятно, должна содержать хэшированный пароль.
/// danger | Опасность
/// 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] *}
/// info | Информация
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был устаревшим (но всё ещё поддерживается) и переименован в `.model_dump()`.
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он устарел (но все еще поддерживается) и был переименован в `.model_dump()`.
В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, следует использовать `.model_dump()`.
В приведенных примерах используется `.dict()` для совместимости с Pydantic v1, но вам следует использовать `.model_dump()`, если вы можете использовать Pydantic v2.
///
### Про `**user_in.dict()`
### О `**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")
```
а затем вызовем:
и затем вызовем:
```Python
user_dict = user_in.dict()
```
теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic- модели).
то теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic модели).
И если мы вызовем:
@ -59,7 +58,7 @@ user_dict = user_in.dict()
print(user_dict)
```
мы получим Python `dict` с:
мы бы получили Python `dict` с:
```Python
{
@ -72,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(
@ -91,7 +90,7 @@ UserInDB(
)
```
Или более точно, используя `user_dict` напрямую, с любым потенциальным содержимым:
Или, более точно, используя `user_dict` напрямую с любым потенциальным содержимым:
```Python
UserInDB(
@ -102,7 +101,7 @@ UserInDB(
)
```
#### Pydantic-модель из содержимого другой модели
#### Pydantic модель из содержимого другой модели
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
@ -111,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(
@ -143,78 +142,81 @@ UserInDB(
/// warning | Предупреждение
Используемые в примере вспомогательные функции `fake_password_hasher` и `fake_save_user` служат лишь для демонстрации возможного потока данных, но, конечно, они не обеспечивают настоящую безопасность.
Используемые в примере вспомогательные функции `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` вместо того, чтобы интерпретировать это как аннотацию типа.
## Список моделей
Аналогичным образом вы можете объявить ответы как списки объектов.
Аналогично, вы можете объявить ответы в виде списков объектов.
Для этого используйте стандартный Python `typing.List` (или просто `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` и без пароля.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.

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

@ -1,12 +1,12 @@
# Первые шаги
Самый простой файл FastAPI может выглядеть следующим образом:
Самый простой FastAPI файл может выглядеть так:
{* ../../docs_src/first_steps/tutorial001.py *}
Скопируйте это в файл `main.py`.
Скопируйте в файл `main.py`.
Запустите live сервер:
Запустите сервер в режиме разработки:
<div class="termy">
@ -51,16 +51,16 @@ $ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid
В окне вывода появится следующая строка:
```hl_lines="4"
INFO: Uvicorn запущен по адресу http://127.0.0.1:8000 (нажмите CTRL+C для завершения)
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Эта строка показывает URL, по которому ваше приложение доступно на локальной машине.
Эта строка показывает URL-адрес, по которому приложение доступно на локальной машине.
### Проверьте это
### Проверьте
Откройте браузер по адресу <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
Откройте браузер по адресу: <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
Вы увидите JSON-ответ, который выглядит следующим образом:
Вы увидите JSON-ответ следующего вида:
```JSON
{"message": "Hello World"}
@ -68,51 +68,51 @@ INFO: Uvicorn запущен по адресу http://127.0.0.1:8000 (наж
### Интерактивная документация API
Теперь перейдите по адресу <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Перейдите по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Вы увидите автоматическую интерактивную документацию API (предоставленную <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
Вы увидите автоматически сгенерированную, интерактивную документацию по API (предоставленную <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Альтернативная документация API
И теперь перейдите по адресу <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Теперь перейдите по адресу <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Вы увидите альтернативную автоматическую документацию (предоставленную <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
Вы увидите альтернативную автоматически сгенерированную документацию (предоставленную <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
### OpenAPI
**FastAPI** генерирует "схему" всего вашего API, используя стандарт **OpenAPI** для определения API.
**FastAPI** генерирует "схему" всего API, используя стандарт **OpenAPI**.
#### "Схема"
"Схема" это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание.
"Схема" - это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание.
#### "Схема" API
#### API "схема"
В данном случае, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> это спецификация, которая определяет, как описывать схему API.
<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> - это спецификация, которая определяет, как описывать схему API.
Это определение схемы включает в себя пути вашего API, возможные параметры, которые они принимают, и т.д.
Определение схемы содержит пути (paths) API, их параметры и т.п.
#### "Схема" данных
Термин "схема" также может относиться к формату данных, например, к содержимому JSON.
Термин "схема" также может относиться к формату или структуре некоторых данных, например, JSON.
В этом случае это будет означать атрибуты JSON и типы данных, которые они имеют, и т.д.
Тогда, подразумеваются атрибуты JSON, их типы данных и т.п.
#### OpenAPI и JSON Schema
OpenAPI определяет схему API для вашего API. А эта схема включает в себя определения (или "схемы") данных, отправляемых и получаемых вашим API, используя **JSON Schema**, стандарт для схем данных JSON.
OpenAPI описывает схему API. Эта схема содержит определения (или "схемы") данных, отправляемых и получаемых API. Для описания структуры данных в JSON используется стандарт **JSON Schema**.
#### Посмотрите `openapi.json`
#### Рассмотрим `openapi.json`
Если вам интересно, как выглядит необработанная схема OpenAPI, FastAPI автоматически генерирует JSON (схему) с описаниями всего вашего API.
Если Вас интересует, как выглядит исходная схема OpenAPI, то FastAPI автоматически генерирует JSON-схему со всеми описаниями API.
Вы можете увидеть её непосредственно по адресу: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
Можете посмотреть здесь: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
Она покажет JSON, начинающийся примерно так:
Вы увидите примерно такой JSON:
```JSON
{
@ -137,11 +137,11 @@ OpenAPI определяет схему API для вашего API. А эта
#### Для чего нужен OpenAPI
Схема OpenAPI обеспечивает работу двух включенных систем интерактивной документации.
Схема OpenAPI является основой для обеих систем интерактивной документации.
Существуют десятки альтернатив, все они основываются на OpenAPI. Вы можете легко добавить любую из этих альтернатив к своему приложению на **FastAPI**.
Существуют десятки альтернативных инструментов, основанных на OpenAPI. Вы можете легко добавить любой из них к **FastAPI** приложению.
Вы также можете использовать её для автоматической генерации кода для клиентов, которые взаимодействуют с вашим API. Например, для фронтенд-, мобильных или IoT-приложений.
Вы также можете использовать OpenAPI для автоматической генерации кода для клиентов, которые взаимодействуют с API. Например, для фронтенд-, мобильных или IoT-приложений.
## Рассмотрим поэтапно
@ -149,99 +149,97 @@ OpenAPI определяет схему API для вашего API. А эта
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
`FastAPI` это класс Python, который предоставляет всю функциональность для вашего API.
`FastAPI` это класс в Python, который предоставляет всю функциональность для API.
/// note | Технические детали
`FastAPI` это класс, который наследуется напрямую от `Starlette`.
`FastAPI` это класс, который наследуется непосредственно от `Starlette`.
Вы можете использовать всю функциональность <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> с `FastAPI`.
Вы можете использовать всю функциональность <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> в `FastAPI`.
///
### Шаг 2: создайте "экземпляр" `FastAPI`
### Шаг 2: создайте экземпляр `FastAPI`
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
Здесь переменная `app` будет "экземпляром" класса `FastAPI`.
Переменная `app` является экземпляром класса `FastAPI`.
Это единая точка входа для создания и взаимодействия с API.
### Шаг 3: определите *операцию пути (path operation)*
### Шаг 3: создайте *операцию пути*
#### Путь (path)
#### Путь
"Путь" это часть URL, после первого символа `/`, следующего за именем домена.
Здесь "путь" относится к последней части URL, начиная с первого `/`.
Таким образом, в URL типа:
Для URL:
```
https://example.com/items/foo
```
...путь будет:
...путь выглядит так:
```
/items/foo
```
/// info
/// info | Дополнительная информация
"Путь" также часто называют "endpoint" или "route".
Термин "path" также часто называется "endpoint" или "route".
///
При создании API "путь" является основным способом отделения "задач" и "ресурсов".
При создании API, "путь" является основным способом разделения "задач" и "ресурсов".
#### Операция
#### Операция (operation)
Здесь "операция" относится к одному из HTTP "методов".
"Операция" это один из "методов" HTTP.
Одному из:
Таких, как:
* `POST`
* `GET`
* `PUT`
* `DELETE`
...и более экзотическим:
...и более экзотических:
* `OPTIONS`
* `HEAD`
* `PATCH`
* `TRACE`
По протоколу HTTP вы можете взаимодействовать с каждым путем, используя один (или более) из этих "методов".
По протоколу HTTP можно обращаться к каждому пути, используя один (или несколько) из этих "методов".
---
При создании API вы обычно используете эти конкретные HTTP методы для выполнения определенных действий.
При создании API принято использовать конкретные HTTP-методы для выполнения определенных действий.
Обычно вы используете:
Обычно используют:
* `POST`: для создания данных.
* `GET`: для чтения данных.
* `PUT`: для обновления данных.
* `DELETE`: для удаления данных.
* `POST`: создать данные.
* `GET`: прочитать.
* `PUT`: изменить (обновить).
* `DELETE`: удалить.
Таким образом, в OpenAPI каждый из HTTP методов называется "операцией".
В OpenAPI каждый HTTP метод называется "**операция**".
Мы также будем называть их "**операциями**".
Мы также будем придерживаться этого термина.
#### Определите *декоратор операции пути*
#### Определите *декоратор операции пути (path operation decorator)*
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
`@app.get("/")` сообщает **FastAPI**, что функция, расположенная прямо под ним, отвечает за обработку запросов, поступающих по адресу:
Декоратор `@app.get("/")` указывает **FastAPI**, что функция, прямо под ним, отвечает за обработку запросов, поступающих по адресу:
* путь `/`
* использующих операцию <abbr title="HTTP GET метод"><code>get</code></abbr>
* использующих <abbr title="HTTP GET метод"><code>get</code> операцию</abbr>
/// info | `@decorator` Информация
/// info | `@decorator` Info
Синтаксис `@something` в Python называется "декоратор".
Вы располагаете его над функцией. Подобно декоративной шляпе (вероятно, отсюда и происходит этот термин).
Вы помещаете его над функцией. Как красивую декоративную шляпу (думаю, что оттуда и происходит этот термин).
"Декоратор" принимает функцию ниже и выполняет с ней какое-то действие.
@ -251,7 +249,7 @@ https://example.com/items/foo
///
Вы также можете использовать другие операции:
Можно также использовать операции:
* `@app.post()`
* `@app.put()`
@ -266,53 +264,53 @@ https://example.com/items/foo
/// tip | Подсказка
Вы можете использовать каждую операцию (HTTP метод) по своему усмотрению.
Вы можете использовать каждую операцию (HTTP-метод) по своему усмотрению.
**FastAPI** не навязывает какого-либо специфического значения.
**FastAPI** не навязывает определенного значения для каждого метода.
Информация здесь представлена в качестве рекомендации, а не требования.
Информация здесь представлена как рекомендация, а не требование.
Например, при использовании GraphQL обычно все действия выполняются только с помощью `POST` операций.
Например, при использовании GraphQL обычно все действия выполняются только с помощью POST операций.
///
### Шаг 4: определите **функцию операции пути**
Это наша "**функция операции пути**":
Вот "**функция операции пути**":
* **путь**: это `/`.
* **операция**: это `get`.
* **функция**: это функция под "декоратором" (под `@app.get("/")`).
* **путь**: `/`.
* **операция**: `get`.
* **функция**: функция ниже "декоратора" (ниже `@app.get("/")`).
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
Это нормальная функция Python.
Это обычная Python функция.
Она будет вызываться **FastAPI** каждый раз, когда будет получен запрос к URL "`/`" с использованием операции `GET`.
**FastAPI** будет вызывать её каждый раз при получении `GET` запроса к URL "`/`".
В данном случае она является асинхронной функцией.
В данном случае это асинхронная функция.
---
Вы также можете определить её как обычную функцию вместо `async def`:
Вы также можете определить ее как обычную функцию вместо `async def`:
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note
Если вы не знаете разницы, посмотрите [Асинхронность: *"В торопях?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
Если не знаете в чём разница, посмотрите [Асинхронность: *"Нет времени?"*](../async.md#_1){.internal-link target=_blank}.
///
### Шаг 5: верните содержимое
### Шаг 5: верните результат
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.
Также вы можете вернуть модели Pydantic (вы узнаете об этом позже).
Также можно вернуть модели Pydantic (рассмотрим это позже).
Множество других объектов и моделей будут автоматически преобразованы в JSON (включая ORM и т.п.). Попробуйте использовать ваши любимые — они с большой вероятностью уже поддерживаются.
Многие объекты и модели будут автоматически преобразованы в JSON (включая ORM). Пробуйте использовать другие объекты, которые предпочтительней для Вас, вероятно, они уже поддерживаются.
## Резюме
@ -320,4 +318,4 @@ https://example.com/items/foo
* Создаём экземпляр `app`.
* Пишем **декоратор операции пути** (такой как `@app.get("/")`).
* Пишем **функцию операции пути** (`def root(): ...`).
* Запускаем сервер в режиме разработки (`fastapi dev`).
* Запускаем сервер в режиме разработки с использованием команды `fastapi dev`.

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

@ -17,27 +17,27 @@
Четырёхсотые статус-коды означают, что ошибка произошла по вине клиента.
Помните ли ошибки **"404 Not Found"** (и шутки)?
Помните ли ошибки **"404 Not Found "** (и шутки) ?
## Использование `HTTPException`
Для возврата HTTP-ответов с ошибками клиенту используется `HTTPException`.
Для возврата клиенту HTTP-ответов с ошибками используется `HTTPException`.
### Импортируйте `HTTPException`
{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
### Вызовите `HTTPException` в своём коде
### Вызовите `HTTPException` в своем коде
`HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API.
Поскольку это исключение Python, то его не `возвращают`, а `вызывают`.
Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы вызываете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту.
Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы поднимаете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту.
Польза от `вызова` исключения, а не `возврата` значения, станет очевидной в разделе, посвящённом зависимостям и безопасности.
О том, насколько выгоднее `вызывать` исключение, чем `возвращать` значение, будет рассказано в разделе, посвященном зависимостям и безопасности.
В этом примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
@ -91,7 +91,7 @@
{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *}
Здесь, если вы запросите `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`.
Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`.
Но оно будет обработано `unicorn_exception_handler`.
@ -230,13 +230,11 @@ path -> item_id
**FastAPI** имеет собственный `HTTPException`.
И класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`.
Класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`.
Единственное отличие заключается в том, что `HTTPException` от **FastAPI** позволяет добавлять заголовки, которые будут включены в ответ.
Единственное отличие заключается в том, что исключение **FastAPI** `HTTPException` принимает любые данные, преобразуемые в JSON, в поле `detail`, в то время как исключение Starlette `HTTPException` принимает только строки.
Он необходим/используется внутри системы для OAuth 2.0 и некоторых утилит безопасности.
Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своём коде.
Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своем коде.
Но когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette.
@ -254,4 +252,4 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *}
В этом примере вы просто выводите в терминал ошибку с очень выразительным сообщением, но вы поняли основную идею. Вы можете использовать исключение и затем просто повторно использовать стандартные обработчики исключений.
В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.

34
docs/ru/docs/tutorial/index.md

@ -1,16 +1,18 @@
# Учебник - Руководство пользователя
Этот учебник показывает вам, как использовать **FastAPI** с большинством его функций, шаг за шагом.
В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций.
Каждый раздел постепенно основан на предыдущих, но он структурирован по отдельным темам, чтобы вы могли перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API.
Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API.
Этот учебник также предназначен для использования в качестве справочника в будущем, так что вы можете вернуться и посмотреть именно то, что вам нужно.
Он также создан для использования в качестве будущего справочника.
Все блоки кода можно копировать и использовать напрямую (это действительно проверенные файлы Python).
Так что вы можете вернуться и посмотреть именно то, что вам нужно.
## Запустите код
Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python).
Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с:
Чтобы запустить любой из примеров, скопируйте код в файл `main.py`, и запустите `fastapi dev` с:
<div class="termy">
@ -52,9 +54,9 @@ $ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid
</div>
**Настоятельно рекомендуется** написать или скопировать код, отредактировать его и запустить локально.
**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально.
Использование его в вашем редакторе показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автозавершение и т.д.
Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д.
---
@ -62,7 +64,7 @@ $ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid
Первый шаг — установить FastAPI.
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем **установили FastAPI**:
Убедитесь, что вы создаете [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируете его и затем **устанавливаете FastAPI**:
<div class="termy">
@ -74,22 +76,22 @@ $ pip install "fastapi[standard]"
</div>
/// note | Примечание
/// note | Технические детали
Если вы устанавливаете с помощью `pip install "fastapi[standard]"`, это включает в себя некоторые стандартные необязательные зависимости, включая `fastapi-cloud-cli`, который позволяет развернуть на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
Когда вы устанавливаете с помощью `pip install "fastapi[standard]"`, это включает некоторые стандартные необязательные зависимости, включая `fastapi-cloud-cli`, который позволяет развернуть приложение на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
Если вы не хотите иметь эти необязательные зависимости, можно установить `pip install fastapi`.
Если вы не хотите иметь эти необязательные зависимости, вы можете вместо этого выполнить установку с помощью `pip install fastapi`.
Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, установите с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, вы можете установить их с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
///
## Продвинутое руководство пользователя
Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после **Учебника - Руководства пользователя**.
Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**.
**Продвинутое руководство пользователя** основывается на этом, использует те же концепции и учит вас некоторым дополнительным функциям.
**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям.
Но сначала вы должны прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
Он разработан таким образом, чтобы вы могли создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**.
Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**.

62
docs/ru/docs/tutorial/middleware.md

@ -1,43 +1,43 @@
# Middleware (Промежуточное ПО)
# Middleware (Промежуточный слой)
Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
Вы можете добавить middleware (промежуточный слой) в **FastAPI** приложение.
"Middleware" это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением.
* Оно обрабатывает каждый **запрос**, поступающий в ваше приложение.
* Может что-то сделать с этим **запросом** или выполнить любой необходимый код.
* Затем передает **запрос** для дальнейшей обработки остальным приложением (какой-либо *операцией пути*).
* Затем оно обрабатывает **ответ**, сгенерированный приложением (какой-либо *операцией пути*).
* Может что-то сделать с этим **ответом** или выполнить любой необходимый код.
* Затем возвращает **ответ**.
* Она принимает каждый поступающий **запрос**.
* Может что-то сделать с этим **запросом** или выполнить любой нужный код.
* Затем передает **запрос** для последующей обработки (какой-либо *операцией пути*).
* Получает **ответ** (от *операции пути*).
* Может что-то сделать с этим **ответом** или выполнить любой нужный код.
* И возвращает **ответ**.
/// note | Технические детали
Если у вас есть зависимости с `yield`, код выхода выполнится *после* промежуточного ПО.
Если у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware.
Если есть какие-либо фоновые задачи (рассматриваемые в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}, вы увидите это позже), они будут выполнены *после* всего промежуточного ПО.
Если у вас имеются некие фоновые задачи (рассмотренные в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}), они будут запущены *после* всех middleware.
///
## Создание middleware
Для создания middleware используйте декоратор `@app.middleware("http")` над функцией.
Для создания middleware используйте декоратор `@app.middleware("http")` перед функцией.
Функция промежуточного ПО получает:
Функция middleware получает:
* `request` (запрос).
* Функцию `call_next`, которая получит `request` в качестве параметра.
* Эта функция передаст `request` соответствующей *операции пути*.
* Затем она возвратит `response`, сгенерированный соответствующей *операцией пути*.
* Вы можете дополнительно изменить `response`, прежде чем вернуть его.
* `request` (объект запроса).
* Функцию `call_next`, которая принимает `request` в качестве параметра.
* Эта функция передает `request` соответствующей *операции пути*.
* Затем она возвращает ответ `response`, сгенерированный *операцией пути*.
* Также имеется возможность видоизменить `response`, перед тем как его вернуть.
{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
/// tip | Совет
/// 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">документации по CORS Starlette</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>.
///
@ -45,33 +45,33 @@
Вы также можете использовать `from starlette.requests import Request`.
**FastAPI** предоставляет это для удобства разработчиков. Но, на самом деле, это `Request` из библиотеки Starlette.
**FastAPI** предоставляет это для удобства разработчиков. Но на самом деле это `Request` из Starlette.
///
### До и после `response`
Вы можете добавить код, который будет выполнен с `request`, до того как какая-либо *операция пути* его получит.
Вы можете добавить код, использующий `request` до передачи его какой-либо *операцией пути*.
А также после формирования `response`, до его возврата.
А также после формирования `response`, до того, как вы его вернёте.
Например, вы можете добавить пользовательский заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и формирования ответа:
Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа:
{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
/// 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 с использованием декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, формируя стек. Последнее добавленное middleware становится самым *внешним*, а первое — самым *внутренним*.
На этапе запроса сначала выполняется *внешнее* middleware.
На пути **запроса**, самое *внешнее* middleware выполняется первым.
На этапе ответа оно выполняется последним.
На пути **ответа** оно выполняется последним.
Например:
@ -80,16 +80,16 @@ app.add_middleware(MiddlewareA)
app.add_middleware(MiddlewareB)
```
Это приведет к следующему порядку выполнения:
Это приводит к следующему порядку выполнения:
* **Запрос**: MiddlewareB → MiddlewareA → маршрут
* **Ответ**: маршрут → MiddlewareA → MiddlewareB
Такое поведение стека обеспечивает выполнение middleware в предсказуемом и контролируемом порядке.
Такое поведение с упаковкой обеспечивает выполнение middleware в предсказуемом и контролируемом порядке.
## Другие middleware
О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
В следующем разделе вы узнаете, как настроить <abbr title="Cross-Origin Resource Sharing">CORS</abbr> с помощью промежуточного ПО.
В следующем разделе вы можете прочитать, как настроить <abbr title="Cross-Origin Resource Sharing">CORS</abbr> с помощью middleware.

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

@ -1,51 +1,49 @@
# Query-параметры и валидация строк
**FastAPI** позволяет объявлять дополнительную информацию и валидацию для ваших параметров.
**FastAPI** позволяет определять дополнительную информацию и валидацию для ваших параметров.
Рассмотрим этот пример приложения:
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
Query-параметр `q` имеет тип `str | None`. Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный.
Query-параметр `q` имеет тип `str | None`, что означает, что он имеет тип `str`, но также может быть `None`, и по умолчанию его значение `None`, так что FastAPI будет знать, что он не является обязательным.
/// note | Технические детали
FastAPI определит, что значение `q` не является обязательным благодаря значению по умолчанию `= None`.
FastAPI определяет, что значение `q` не является обязательным благодаря значению по умолчанию `= None`.
`str | None` позволит редактору кода оказать вам лучшую поддержку и найти ошибки.
`str | None` позволяет вашему редактору кода предоставлять лучшую поддержку и обнаруживать ошибки.
///
## Дополнительная валидация
Добавим дополнительное условие валидации параметра `q`**длина строки не более 50 символов**.
Мы собираемся обеспечить, что даже если `q` является необязательным, в случаях, когда он предоставлен, **его длина не превышает 50 символов**.
### Импорт `Query` и `Annotated`
Для этого сначала импортируйте:
Чтобы достигнуть этой цели, сначала импортируйте:
* `Query` из пакета `fastapi`
* `Annotated` из пакета `typing`
* `Query` из `fastapi`
* `Annotated` из `typing`
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
/// info | Дополнительная информация
FastAPI добавил поддержку `Annotated` (и начал рекомендовать его) в версии 0.95.0.
FastAPI добавил поддержку `Annotated` (и начал рекомендовать его использование) в версии 0.95.0.
Если у вас более старая версия, вы получите ошибки при попытке использовать `Annotated`.
Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`.
Если у вас более старая версия, при попытке использования `Annotated` вы получите ошибки. Убедитесь, что вы [Обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`.
///
## Использование `Annotated` в типе для параметра `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+
@ -63,7 +61,7 @@ q: Union[str, None] = None
////
Теперь мы обернем это в `Annotated`, чтобы получить:
Что мы сделаем: обернём это в `Annotated`, таким образом:
//// tab | Python 3.10+
@ -81,47 +79,47 @@ q: Annotated[Union[str, None]] = None
////
Обе эти версии означают одно и то же. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`.
Обе этих версии означают одно и то же, `q` это параметр, который может быть `str` или `None`, и по умолчанию он будет `None`.
Теперь перейдем к самому интересному. 🎉
Теперь перейдём к интересному. 🎉
## Добавим `Query` в `Annotated` для параметра `q`
Теперь, когда у нас есть `Annotated`, где мы можем поместить больше информации (в данном случае дополнительную валидацию), добавим `Query` внутрь `Annotated` и установим параметр `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, что мы хотим иметь **дополнительные условия валидации** для этого значения, чтобы его длина не превышала 50 символов. 😎
Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим иметь **дополнительную валидацию** для этого значения, мы хотим, чтобы оно содержало максимум 50 символов. 😎
/// tip | Подсказка
Здесь мы используем `Query()`, так как это **query-параметр**. Позже мы увидим другие параметры, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают те же аргументы, что и `Query()`.
Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают такие же аргументы, как и `Query()`.
///
Теперь FastAPI:
Теперь FastAPI будет:
* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов
* Показывает **понятную ошибку** для клиента в случаях, когда данные не валидны
* **Документирует** параметр в схему OpenAPI *операции пути* (что отображается в **UI автоматической документации**)
* **Валидировать** данные, удостоверяясь, что максимальная длина составляет 50 символов
* Показать **четкую ошибку** клиенту, когда данные не валидны
* **Документировать** параметр в схеме OpenAPI операции пути (таким образом, он будет отображаться в **UI автоматической документации**)
## Альтернативный (устаревший) способ: `Query` как значение по умолчанию
В предыдущих версиях FastAPI (до <abbr title="ранее 2023-03">0.95.0</abbr>) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню.
До версии <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(default=None)`, это служит той же цели определения значения по умолчанию (по крайней мере для FastAPI).
Так как в этом случае (без использования `Annotated`) нам приходится заменять значение по умолчанию `None` в функции на `Query()`, теперь нам нужно установить значение по умолчанию с параметром `Query(default=None)`, это выполняет ту же цель, как определение значения по умолчанию (по крайней мере, для FastAPI).
Таким образом:
@ -129,44 +127,44 @@ q: Annotated[Union[str, None]] = None
q: str | None = Query(default=None)
```
...делает параметр необязательным, со значением по умолчанию `None`, то же самое, что и:
...делает параметр необязательным со значением по умолчанию `None`, чем эквивалентен:
```Python
q: str | None = None
```
Но версия с `Query` объявляет его как query-параметр.
Но версия `Query` явно объявляет его как query-параметр.
Теперь, мы можем указать больше параметров для `Query`. В данном случае, параметр `max_length` применяется к строкам:
Затем, мы можем передать больше параметров в `Query`. В данном случае, это параметр `max_length`, который применяется к строкам:
```Python
q: str | None = Query(default=None, max_length=50)
```
Входные данные будут проверены. Если данные недействительны, тогда будет указано на ошибку в запросе. Параметр также будет задокументирован в схеме OpenAPI данной *операции пути*.
Это позволит валидировать данные, показать четкую ошибку когда данные не валидны, и задокументировать параметр в операции пути схемы OpenAPI.
### `Query` как значение по умолчанию или в `Annotated`
### Использование `Query` как значения по умолчанию или в `Annotated`
Имейте в виду, что при использовании `Query` внутри `Annotated` вы не можете использовать параметр `default` у `Query`.
Имейте в виду, что при использовании `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")
@ -174,43 +172,43 @@ 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> `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
Это регулярное выражение проверяет, что полученное значение параметра:
Это конкретное регулярное выражение проверяет, что полученное значение параметра:
* `^`: начинается с следующих символов, не имеет символов перед.
* `fixedquery`: в точности содержит строку `fixedquery`.
* `$`: заканчивается там, где `fixedquery`, не имеет символов после.
* `^`: начинается с следующих символов, не имеет символов перед этим.
* `fixedquery`: содержит точное значение `fixedquery`.
* `$`: заканчивается здесь, не имеет символов после `fixedquery`.
Если вам сложно дается концепция **"регулярные выражения"**, не беспокойтесь. Для многих людей это трудная тема. Вы можете делать множество вещей, не прибегая к регулярным выражениям.
Если вас пугает тема **"регулярных выражений"**, не переживайте. Это сложная тема для многих людей. Вы можете реализовать множество вещей без использования регулярных выражений.
Теперь вы знаете, что, когда вам понадобятся регулярные выражения, вы сможете использовать их в **FastAPI**.
Теперь вы знаете, что когда они вам понадобятся, вы можете использовать их в **FastAPI**.
### `regex` в Pydantic v1 вместо `pattern`
### Pydantic v1 `regex` вместо `pattern`
До версии Pydantic 2 и FastAPI 0.100.0, параметр назывался `regex` вместо `pattern`, но сейчас он считается устаревшим.
До версии Pydantic 2 и FastAPI 0.100.0, параметр назывался `regex`, а не `pattern`, но теперь он устарел.
Вы всё ещё можете встретить код, использующий его:
Всё ещё можно увидеть код, где это используется:
//// tab | Pydantic v1
@ -218,25 +216,25 @@ q: str = Query(default="rick")
////
Однако знайте, что это устарело и стоит обновить используемый параметр на `pattern`. 🤓
Но это устаревший метод и его нужно обновить для использования нового параметра `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`, делает параметр необязательным (не требуется).
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.
///
## Обязательный параметр
## Обязательные параметры
Когда вам не требуется дополнительная валидация или другие метаданные для параметра запроса, вы можете сделать параметр `q` обязательным просто не указывая значения по умолчанию. Например:
Когда нам не требуется указывать дополнительные валидации или метаданные, мы можем сделать query-параметр `q` обязательным, просто не указывая значение по умолчанию, например:
```Python
q: str
@ -248,7 +246,7 @@ q: str
q: str | None = None
```
Но в настоящее время мы определяем его через `Query`. Например:
Но мы определяем его с помощью `Query`, например, так:
//// tab | Annotated
@ -258,35 +256,35 @@ 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` как валидный тип для параметра запроса, но не указывать значение по умолчанию:
Для этого вы можете объявить, что `None` является допустимым типом, но просто не указывайте значение по умолчанию:
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
## Множество значений для 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
```
вы получите несколько значений *query-параметра* `q` (`foo` и `bar`) в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
вы получите множество значений *query-параметров* `q` (`foo` и `bar`) в виде `list` Python внутри вашей *функции обработки пути*, в *функциональном параметре* `q`.
Так что ответ на этот URL будет:
Таким образом, ответ на этот URL будет:
```JSON
{
@ -299,27 +297,27 @@ http://localhost:8000/items/?q=foo&q=bar
/// tip | Подсказка
Чтобы объявить query-параметр типа `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
Чтобы объявить query-параметр типом `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
///
Интерактивная документация 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
{
@ -330,7 +328,7 @@ http://localhost:8000/items/
}
```
#### Использование только `list`
#### Использование `list`
Вы также можете использовать `list` напрямую вместо `list[str]`:
@ -338,27 +336,27 @@ http://localhost:8000/items/
/// note | Технические детали
Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.
Имейте в виду, что в таком случае, FastAPI не будет проверять содержимое списка.
Например, для List[int] список будет валидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
Например, `list[int]` проверяет (и документирует), что содержимое списка - целые числа. Но просто `list` такую проверку не проводит.
///
## Объявление дополнительных метаданных
## Больше метаданных
Вы можете добавить больше информации о параметре.
Эта информация будет включена в генерируемую OpenAPI и использована интерфейсами документации и внешними инструментами.
Эта информация будет включена в сгенерированный OpenAPI и использована интерфейсами документации и внешними инструментами.
/// note | Технические детали
Имейте в виду, что разные инструменты могут иметь разный уровень поддержки OpenAPI.
Имейте в виду, что разные инструменты могут иметь различные уровни поддержки OpenAPI.
Некоторые из них могут не отображать всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
Некоторые из них могут все еще не показывать всю дополнительную информацию, хотя в большинстве случаев, недостающая функция уже запланирована к разработке.
///
Вы можете добавить название query-параметра, используя параметр `title`:
Вы можете добавить `title`:
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
@ -368,109 +366,109 @@ http://localhost:8000/items/
## Псевдонимы параметров
Представьте, что вы хотите, чтобы параметр был `item-query`.
Представьте, что вы хотите использовать параметр с названием `item-query`.
Как в:
Как в следующем примере:
```
http://127.0.0.1:8000/items/?item-query=foobaritems
```
Но `item-query` не является допустимым именем переменной в Python.
Но `item-query` является невалидным именем переменной в Python.
Ближайшее к нему было бы `item_query`.
Наиболее похожее валидное имя `item_query`.
Но вам все еще нужно, чтобы он был именно `item-query`...
Но вам всё равно необходимо использовать `item-query`
Тогда вы можете объявить `псевдоним`, и этот псевдоним будет использоваться для поиска значения параметра:
Тогда вы можете объявить `псевдоним`, и именно он будет использован для поиска значения параметра:
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
## Устаревшие параметры
Теперь предположим, вам больше не нравится этот параметр.
Теперь допустим, что вам больше не нравится этот параметр.
Вы должны оставить его на некоторое время, потому что клиенты все еще его используют, но вы хотите, чтобы в документации он явно отображался как <abbr title="устарело, не рекомендуется использовать">устаревший</abbr>.
Вы должны оставить его на некоторое время, поскольку есть клиенты, которые его используют, но вы хотите, чтобы в документации он ясно показывался как <abbr title="устарел, рекомендуется избегать его использования">устаревший</abbr>.
Затем передайте параметр `deprecated=True` в `Query`:
Тогда передайте параметр `deprecated=True` метод `Query`:
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
Документация будет отображать это так:
В документации это будет отображено следующим образом:
<img src="/img/tutorial/query-params-str-validations/image01.png">
## Исключение параметров из OpenAPI
Чтобы исключить query-параметр из сгенерированной схемы OpenAPI (и, следовательно, из системы автоматической документации), установите параметр `include_in_schema` для `Query` в `False`:
Чтобы исключить query-параметр из сгенерированной схемы OpenAPI (и таким образом, из системы автоматической документации), установите параметр `include_in_schema` в `Query` равным `False`:
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Кастомная валидация
## Пользовательская валидация
Могут быть случаи, когда вам нужно исполнить **кастомную валидацию**, которую нельзя выполнить с использованием только параметров, описанных выше.
Могут быть случаи, когда вам нужно сделать какую-либо **пользовательскую валидацию**, которую нельзя осуществить с помощью вышеуказанных параметров.
В таких сценариях, вы можете использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки значения на совпадение с `str`).
В этих случаях вы можете использовать **функцию пользовательского валидатора**, которая будет применяться после нормальной валидации (например, после проверки, что значение `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> и другие. 🤓
Pydantic также предоставляет <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> и другие. 🤓
///
Например, следующий кастомный валидатор проверяет, начинается ли ID статьи с `isbn-` (для международного стандартного номера книги ISBN) или с `imdb-` (для URL-идентификатора фильма на IMDb):
Например, этот пользовательский валидатор проверяет, что 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 | Дополнительная информация
/// info | Информация
Это доступно начиная с версии Pydantic 2 или выше. 😎
Это доступно в версии Pydantic 2 или выше. 😎
///
/// tip | Подсказка
Если вам нужно выполнить валидацию, которая требует связи с **внешним компонентом**, например с базой данных или другим API, используйте **FastAPI Dependencies**. Вы узнаете о них позже.
Если вам нужно выполнить какую-либо валидацию, которая требует связи с каким-либо **внешним компонентом**, например, базой данных или другим API, вам следует вместо этого использовать **FastAPI Dependencies**, вы узнаете о них позже.
Эти кастомные валидаторы предназначены для выполнения проверок, которые можно осуществить, используя **исключительно** **те же данные**, переданные в запросе.
Эти пользовательские валидаторы предназначены для вещей, которые можно проверить только с использованием **тех же данных**, предоставленных в запросе.
///
### Понимание кода
### Понять этот код
Основное — это использование **`AfterValidator` с функцией внутри `Annotated`**. Если вы хотите, вы можете пропустить эту часть. 🤸
Основным пунктом является использование **`AfterValidator` с функцией внутри `Annotated`**. Не стесняйтесь пропустить эту часть. 🤸
---
Но если вам интересно или вы всё ещё намерены продолжить, вот несколько дополнительных подробностей.
Но если вам интересно рассмотреть этот пример кода, который все еще вызывает интерес, вот несколько дополнительных деталей.
#### Строка с `value.startswith()`
Обратили внимание? строка, использующая `value.startswith()`, может принять кортеж, и она проверит каждое значение в кортеже:
Заметили? Строка, использующая `value.startswith()`, может принимать кортеж, и проверит каждое значение в кортеже:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
#### Случайный предмет
#### Случайный элемент
С `data.items()` мы получаем <abbr title="Что-то, что можно итерировать в цикле for, например, список, множества и т.д.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
С `data.items()` мы получаем <abbr title="Что-то, что можно использовать в цикле for, как например, list, set и так далее.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
Мы преобразуем этот итерируемый объект в обычный `list` с помощью `list(data.items())`.
Мы преобразуем этот итерируемый объект в настоящий `list` с `list(data.items())`.
Затем через `random.choice()` мы можем получить **случайное значение** из списка, это будет кортеж `(id, name)`. Пример: `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
Тогда, с помощью `random.choice()` можем получить **случайное значение** из списка, так мы получаем кортеж `(id, name)`. Он будет чем-то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
Потом мы **присваиваем эти два значения** из кортежа переменным `id` и `name`.
Затем мы **присваиваем эти два значения** из кортежа переменным `id` и `name`.
Так, если пользователь не передал ID элемента, они всё равно получат случайное предложение.
Так что, если пользователь не предоставил ID элемента, они получат случайную рекомендацию.
...всё это выполняется в одной **простой строке**. 🤯 Разве вы не любите Python? 🐍
...мы выполняем все это в **одной простой строке**. 🤯 Разве Python не потрясающий? 🐍
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
## Резюме
Вы можете объявлять дополнительные правила валидации и метаданные для ваших параметров.
Вы можете объявлять дополнительные валидации и метаданные для ваших параметров.
Общие валидации и метаданные:
@ -479,14 +477,14 @@ Pydantic также имеет <a href="https://docs.pydantic.dev/latest/concept
* `description`
* `deprecated`
Валидации, специфичные для строк:
Валидации специфичны для строк:
* `min_length`
* `max_length`
* `pattern`
Кастомная валидация с использованием `AfterValidator`.
Пользовательские валидации с использованием `AfterValidator`.
В этих примерах вы увидели, как объявлять валидации для значений типа `str`.
В этих примерах вы видели, как объявлять валидации для значений `str`.
В следующих главах вы увидите, как объявлять правила валидации для других типов (например, чисел).
Смотрите следующие главы, чтобы узнать, как объявлять валидации для других типов, таких как числа.

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

@ -1,101 +1,101 @@
# Статус-код ответа
# HTTP коды статуса ответа
Так же, как вы можете указать модель ответа, вы также можете задать HTTP статус-код, используемый для ответа, с помощью параметра `status_code` в любой из *операций пути*:
Вы можете задать HTTP код статуса ответа с помощью параметра `status_code` подобно тому, как вы определяете схему ответа в любой из *операций пути*:
* `@app.get()`
* `@app.post()`
* `@app.put()`
* `@app.delete()`
* и т.д.
* и других.
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
/// note | Примечание
Обратите внимание, что `status_code` является параметром метода-декоратора (`get`, `post` и т.д.), а не вашей *функции-обработчика пути*, как все остальные параметры и тело.
Обратите внимание, что `status_code` является атрибутом метода-декоратора (`get`, `post` и т.д.), а не *функции-обработчика пути* в отличие от всех остальных параметров и тела запроса.
///
Параметр `status_code` принимает число, обозначающее HTTP статус-код.
Параметр `status_code` принимает число, обозначающее HTTP код статуса ответа.
/// info | Информация
В качестве значения параметра `status_code` может также использоваться `IntEnum`, например, из библиотеки Python <a href="https://docs.python.org/3/library/http.html#http.HTTPStatus" class="external-link" target="_blank">`http.HTTPStatus`</a>.
В качестве значения параметра `status_code` также может использоваться `IntEnum`, например, из библиотеки <a href="https://docs.python.org/3/library/http.html#http.HTTPStatus" class="external-link" target="_blank">`http.HTTPStatus`</a> в Python.
///
Это позволит:
* Возвращать указанный код статуса в ответе.
* Документировать его как таковой в OpenAPI схеме (а значит, и в пользовательском интерфейсе):
* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательском интерфейсе):
<img src="/img/tutorial/response-status-code/image01.png">
/// note | Примечание
Некоторые коды ответа (см. следующий раздел) указывают, что ответа с телом не будет.
Некоторые коды статуса ответа (см. следующий раздел) указывают на то, что ответ не имеет тела.
FastAPI знает об этом и создаст документацию OpenAPI, которая укажет, что тело ответа отсутствует.
FastAPI знает об этом и создаст документацию OpenAPI, в которой будет указано, что тело ответа отсутствует.
///
## Об HTTP статус-кодах
## Об HTTP кодах статуса ответа
/// note | Примечание
Если вы уже знаете, что такое HTTP статус-коды, можете пропустить этот раздел.
Если вы уже знаете, что представляют собой HTTP коды статуса ответа, можете перейти к следующему разделу.
///
В HTTP вы отправляете числовой код состояния из 3 цифр как часть ответа.
В протоколе HTTP числовой код состояния из 3 цифр отправляется как часть ответа.
У этих кодов статуса есть связанные с ними названия для их распознавания, но важна именно числовая часть.
У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
Кратко о значениях:
Кратко о значениях кодов:
* `100 - 199` — это информационные коды. Вы редко используете их напрямую. Ответы с этими кодами не должны содержать тело.
* **`200 - 299`** — это успешные ответы. Эти вы будете использовать чаще всего.
* `200` — это код по умолчанию, который означает, что все прошло "OK".
* Другой пример — `201`, "Created". Он часто используется после создания новой записи в базе данных.
* Особый случай `204`, "No Content". Этот ответ используется, когда нет содержимого для возврата клиенту, и поэтому тело отсутствует.
* **`300 - 399`** — это коды перенаправлений. Ответы с этими кодами статуса могут, а могут и не иметь тело, за исключением `304`, "Not Modified", у которого его не должно быть.
* **`400 - 499`** — это ошибки клиента. Это вторая группа, которую вы, вероятно, будете использовать чаще всего.
* Пример `404`, для ответа "Not Found".
* Для общих ошибок клиента можно использовать просто `400`.
* `500 - 599` — это ошибки сервера. Вы почти никогда не используете их напрямую. Когда что-то идет не так в коде вашего приложения или на сервере, он автоматически возвращает один из этих кодов.
* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
* `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
* Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
* Особый случай `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
* Пример – код `404` для статуса "Not Found".
* Для общих ошибок со стороны клиента можно просто использовать код `400`.
* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов.
/// tip | Совет
/// tip | Подсказка
Чтобы узнать больше о каждом статус-коде и для чего он предназначен, ознакомьтесь с <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>.
///
## Удобные сокращения для запоминания названий
## Краткие обозначения для запоминания названий кодов
Давайте еще раз рассмотрим предыдущий пример:
Рассмотрим предыдущий пример еще раз:
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
`201` это код статуса "Создано".
`201` это код статуса "Создано".
Но вам не обязательно запоминать значение каждого из этих кодов.
Но вам не обязательно запоминать, что означает каждый из этих кодов.
Вы можете использовать удобные переменные из `fastapi.status`.
Для удобства вы можете использовать переменные из `fastapi.status`.
{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
Они содержат те же числовые значения, но позволяют использовать авто-завершение редактора для выбора кода статуса:
Они содержат те же числовые значения, но позволяют использовать подсказки редактора для выбора кода статуса:
<img src="/img/tutorial/response-status-code/image02.png">
/// note | Технические детали
Вы также можете использовать `from starlette import status`.
Вы также можете использовать `from starlette import status` вместо `from fastapi import status`.
**FastAPI** предоставляет `starlette.status` как `fastapi.status` исключительно для удобства разработчиков. Однако он поставляется непосредственно из Starlette.
**FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette.
///
## Изменение кода по умолчанию
## Изменение кода статуса по умолчанию
Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP код статуса, отличный от используемого здесь кода по умолчанию.
Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP коды статуса, отличные от используемого здесь кода статуса по умолчанию.

225
docs/ru/docs/tutorial/sql-databases.md

@ -1,40 +1,40 @@
# SQL (реляционные) базы данных
**FastAPI** не требует от вас использования реляционной базы данных. Но вы можете использовать **любую базу данных**, которую захотите.
**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которой хотите.
Здесь мы увидим пример, использующий <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>.
В этом разделе мы продемонстрируем, как работать с <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>.
**SQLModel** построен на основе <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a> и Pydantic. Он был создан автором **FastAPI** и является идеальным выбором для приложений FastAPI, которые нуждаются в реляционных базах данных.
Библиотека **SQLModel** построена на основе <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a> и Pydantic. Она была разработана автором **FastAPI** специально для приложений на основе FastAPI, которые используют **реляционные базы данных**.
/// tip | Совет
/// tip | Подсказка
Вы можете использовать любую другую библиотеку для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных, в некоторых случаях называемую <abbr title="ORM = Object Relational Mapper, это библиотека, где классы представляют SQL-таблицы, а экземпляры классов представляют строки в этих таблицах.">"ORMs"</abbr>. FastAPI не заставляет вас использовать что-то конкретное. 😎
Вы можете воспользоваться любой библиотекой для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных. (Их ещё называют <abbr title="ORM = Object Relational Mapper, этот термин для библиотеки, в которой классы представляют SQL-таблицы, а экземпляры классов представляют строки в этих таблицах.">**ORM**</abbr> библиотеками). FastAPI не принуждает вас к использованию чего-либо конкретного. 😎
///
Поскольку SQLModel основан на SQLAlchemy, вы можете легко использовать **любую базу данных, поддерживаемую** SQLAlchemy (соответственно поддерживаемую SQLModel), например:
В основе SQLModel лежит SQLAlchemy, поэтому вы спокойно можете использовать любую базу данных, поддерживаемую SQLAlchemy (и, соответственно, поддерживаемую SQLModel), например:
* PostgreSQL
* MySQL
* SQLite
* Oracle
* Microsoft SQL Server и т. д.
* Microsoft SQL Server, и т.д.
В этом примере мы будем использовать базу данных **SQLite**, потому что она использует один файл, и поддержка Python встроена. Таким образом, вы можете скопировать этот пример и запустить его как есть.
В данном примере мы будем использовать базу данных **SQLite**, т.к. она состоит из единственного файла и поддерживается встроенными библиотеками Python. Таким образом, вы сможете скопировать данный пример и запустить его как он есть.
В дальнейшем, для продакшн-версии вашего приложения, возможно, вам стоит использовать серверную базу данных, такую как **PostgreSQL**.
В дальнейшем, для продакшн-версии вашего приложения, возможно, вам стоит использовать серверную базу данных, например, **PostgreSQL**.
/// tip | Совет
/// tip | Подсказка
Существует официальный генератор проектов с **FastAPI** и **PostgreSQL**, включая frontend и другие инструменты: <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
Существует официальный генератор проектов на **FastAPI** и **PostgreSQL**, который также включает frontend и дополнительные инструменты <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
///
Это очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, об SQL или более продвинутых возможностях, обратитесь к <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">документации SQLModel</a>.
Это очень простое и короткое руководство, поэтому, если вы хотите узнать о базах данных в целом, об SQL, разобраться с более продвинутым функционалом, то воспользуйтесь <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">документацией SQLModel</a>.
## Установка `SQLModel`
Сначала убедитесь, что вы создали свое [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили `sqlmodel`:
Создайте виртуальное окружение [virtual environment](../virtual-environments.md){.internal-link target=_blank}, активируйте его и установите `sqlmodel`:
<div class="termy">
@ -45,11 +45,11 @@ $ pip install sqlmodel
</div>
## Создание приложения с одной моделью
## Создание приложения с единственной моделью
Мы сначала создадим самую простую версию приложения с одной моделью **SQLModel**.
Мы начнем с создания наиболее простой первой версии нашего приложения с одной единственной моделью **SQLModel**.
Позже мы улучшим его, повысив безопасность и универсальность за счет **нескольких моделей** ниже. 🤓
В дальнейшем с помощью **дополнительных моделей** мы его улучшим и сделаем более безопасным и универсальным. 🤓
### Создание моделей
@ -57,97 +57,98 @@ $ pip install sqlmodel
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
Класс `Hero` очень похож на модель Pydantic (по сути, под капотом, это действительно *модель Pydantic*).
Класс `Hero` очень напоминает модель Pydantic (фактически, под капотом, *это и есть модель Pydantic*).
Но есть несколько различий:
Но есть и некоторые различия
* `table=True` говорит SQLModel, что это *модель таблицы*, она должна представлять **таблицу** в реляционной базе данных, это не просто *модель данных* (в отличие от обычного класса Pydantic).
* `table=True` для SQLModel означает, что это *модель-таблица*, которая должна представлять **таблицу** в реляционной базе данных. Это не просто *модель данных* (в отличие от обычного класса в Pydantic).
* `Field(primary_key=True)` говорит SQLModel, что `id` является **первичным ключом** в базе данных SQL (более подробно о первичных ключах SQL можно узнать в документации SQLModel).
* `Field(primary_key=True)` для SQLModel означает, что поле `id` является первичным ключом в таблице базы данных (вы можете подробнее узнать о первичных ключах баз данных в документации по SQLModel).
Тип `int | None` сообщает SQLModel, что этот столбец должен быть `INTEGER` в базе данных SQL и что он должен быть `NULLABLE`.
Тип `int | None` сигнализирует для SQLModel, что столбец таблицы базы данных должен иметь тип `INTEGER`, или иметь пустое значение `NULL`.
* `Field(index=True)` говорит SQLModel, что он должен создать **SQL индекс** для этого столбца, что позволит ускорить поиск в базе данных при чтении данных, отфильтрованных по этому столбцу.
* `Field(index=True)` для SQLModel означает, что нужно создать **SQL индекс** для данного столбца. Это обеспечит более быстрый поиск при чтении данных, отфильтрованных по данному столбцу.
SQLModel будет знать, что нечто объявленное как `str` будет SQL-столбцом типа `TEXT` (или `VARCHAR`, в зависимости от базы данных).
SQLModel будет знать, что данные типа `str`, будут представлены в базе данных как `TEXT` (или `VARCHAR`, в зависимости от типа базы данных).
### Создание подключения
### Создание соединения с базой данных (Engine)
Объект `engine` в SQLModel (по сути это `Engine` из SQLAlchemy) **удерживает соединения** с базой данных.
В SQLModel объект соединения `engine` (по сути это `Engine` из SQLAlchemy) **содержит пул соединений** к базе данных.
Для обеспечения всех подключений приложения к одной базе данных существует **единственный объект `engine`**.
Для обеспечения всех подключений приложения к одной базе данных нужен только один объект соединения `engine`.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
Использование `check_same_thread=False` позволяет FastAPI использовать одну и ту же SQLite базу данных в различных потоках. Это необходимо, так как **один запрос** может использовать **более одного потока** (например, в зависимостях).
Использование настройки `check_same_thread=False` позволяет FastAPI использовать одну и ту же SQLite базу данных в различных потоках (threads). Это необходимо, когда **один запрос** использует **более одного потока** (например, в зависимостях).
Не беспокойтесь, с такой структурой кода, мы позаботимся о том, чтобы использовать **отдельную *сессию* SQLModel для каждого запроса** позже, именно это и пытается достичь `check_same_thread`.
Не беспокойтесь, учитывая структуру кода, мы позже позаботимся о том, чтобы использовать **отдельную SQLModel-сессию на каждый отдельный запрос**, это как раз то, что пытается обеспечить `check_same_thread`.
### Создание таблиц
Далее мы добавляем функцию, использующую `SQLModel.metadata.create_all(engine)`, для того чтобы создать **таблицы** для всех **моделей таблиц**.
Далее мы добавляем функцию, использующую `SQLModel.metadata.create_all(engine)`, для того, чтобы создать **таблицы** для каждой из **моделей таблицы**.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
### Создание зависимости Session
Сессия базы данных (**`Session`**) хранит **объекты в памяти** и отслеживает любые изменения в данных, затем она **использует `engine`** для связи с базой данных.
Сессия базы данных (**`Session`**) хранит **объекты в памяти** и отслеживает любые необходимые изменения в данных, а затем **использует `engine`** для коммуникации с базой данных.
Мы создадим зависимость FastAPI с использованием `yield`, которая будет предоставлять новую `Session` для каждого запроса. Это именно то, что обеспечит использование отдельной сессии для каждого запроса. 🤓
Мы создадим FastAPI-**зависимость** с помощью `yield`, которая будет создавать новую сессию (Session) для каждого запроса. Это как раз и обеспечит использование отдельной сессии на каждый отдельный запрос. 🤓
Затем мы создадим объявленную зависимость `SessionDep`, чтобы упростить остальной код, который будет использовать эту зависимость.
Затем мы создадим объявленную (`Annotated`) зависимость `SessionDep`. Мы сделаем это для того, чтобы упростить остальной код, который будет использовать эту зависимость.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
### Создание таблиц базы данных при старте приложения
### Создание таблиц базы данных при запуске приложения
Мы создадим таблицы базы данных при запуске приложения.
Мы будем создавать таблицы базы данных при запуске приложения.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
Здесь мы создаём таблицы на событии начала работы приложения.
В данном примере мы создаем таблицы при наступлении события запуска приложения.
Для продакшн-версии вы, вероятно, будете использовать скрипт миграции базы данных, который выполняется перед запуском вашего приложения. 🤓
В продуктовом приложении вы, скорее всего, будете использовать скрипт для миграции базы данных, который выполняется перед запуском приложения. 🤓
/// tip | Совет
/// tip | Подсказка
В SQLModel будут включены утилиты для миграции на основе Alembic, но пока вы можете использовать <a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a> напрямую.
В SQLModel будут включены утилиты миграции, входящие в состав Alembic, но на данный момент вы просто можете использовать
<a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a> напрямую.
///
### Создание героя
### Создание героя (Hero)
Поскольку каждая модель в SQLModel также является моделью Pydantic, вы можете использовать её в тех же **аннотациях типов**, что и модели Pydantic.
Каждая модель в SQLModel является также моделью Pydantic, поэтому вы можете использовать её при **объявлении типов**, точно также, как и модели Pydantic.
Например, если вы объявите параметр типа `Hero`, он будет прочитан из **тела JSON**.
Например, при объявлении параметра типа `Hero`, она будет считана из **тела JSON**.
Точно так же, вы можете объявить его как **возвращаемый тип функции**, и тогда форма данных будет отображаться в интерфейсе автоматической документации API.
Точно также, вы можете использовать её при объявлении типа значения, возвращаемого функцией, и тогда структурированные данные будут отображены через пользовательский интерфейс автоматически сгенерированной документации FastAPI.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
Здесь мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их.
Мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их.
### Чтение данных героев
### Чтение данных о героях
Мы можем **читать** данных героев из базы данных, используя `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов.
Мы можем **читать** данные героев из базы данных с помощью `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
### Чтение данных одного героя
### Чтение данных отдельного героя
Мы можем **читать** данные одного героя.
Мы можем прочитать данные отдельного героя (`Hero`).
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
### Удаление героя
### Удаление данных героя
Мы можем также **удалить** героя.
Мы также можем удалить героя `Hero` из базы данных.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
### Запуск приложения
Вы можете запустить приложение:
Вы можете запустить приложение следующим образом:
<div class="termy">
@ -159,49 +160,49 @@ $ fastapi dev main.py
</div>
Затем перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также для **сериализации** и **проверки** данных.
Далее перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует модели для создания документации API. Эти же модели используются для сериализации и проверки данных.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image01.png">
</div>
## Обновление приложения с несколькими моделями
## Добавление в приложение дополнительных (вспомогательных) моделей
Теперь давайте немного **отрефакторим** это приложение, чтобы повысить его **безопасность** и **универсальность**.
Теперь давайте проведём **рефакторинг** нашего приложения, чтобы сделать его более безопасным и более универсальным.
Если вы посмотрите на предыдущее приложение, в UI вы увидите, что до сих пор оно позволяет клиенту задавать `id` создаваемого героя (`Hero`). 😱
Обратите внимание, что на данном этапе наше приложение позволяет на уровне клиента определять `id` создаваемого героя (`Hero`). 😱
Нам нельзя допускать этого, так как они могут перезаписать `id`, который у нас уже есть в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда** или **на уровне базы данных**, **не на уровне клиента**.
Мы не можем этого допустить, т.к. существует риск переписать уже присвоенные `id` в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда (backend)** или **на уровне базы данных**, но никак **не на уровне клиента**.
Кроме того, мы создаём `secret_name` для героя, но на данный момент мы возвращаем его везде, и это не очень **секретно**... 😅
Кроме того, мы создаем секретное имя `secret_name` для героя, но пока что, мы возвращаем его повсеместно, и это слабо напоминает **секретность**... 😅
Мы исправим это, добавив несколько **дополнительных моделей**. Вот где SQLModel действительно засияет. ✨
Мы поправим это с помощью нескольких дополнительных (вспомогательных) моделей. Вот где SQLModel по-настоящему покажет себя. ✨
### Создание нескольких моделей
### Создание дополнительных моделей
В **SQLModel** любая модель класса, содержащая `table=True`, является **моделью таблицы**.
В **SQLModel**, любая модель с параметром `table=True` является **моделью таблицы**.
А любая модель класса без `table=True` является **моделью данных**, они на самом деле представляют собой модели Pydantic (с несколькими небольшими дополнительными возможностями). 🤓
Любая модель, не содержащая `table=True` является **моделью данных**, это по сути обычные модели Pydantic (с несколько расширенным функционалом). 🤓
С помощью SQLModel мы можем использовать **наследование**, чтобы **избежать дублирования** всех полей во всех случаях.
С помощью SQLModel мы можем использовать **наследование**, что поможет нам **избежать дублирования** всех полей.
#### `HeroBase` - базовый класс
#### Базовый класс `HeroBase`
Начнем с модели `HeroBase`, которая имеет все **общие поля** для всех моделей:
Давайте начнём с модели `HeroBase`, которая содержит поля, общие для всех моделей:
* `name`
* `age`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
#### `Hero` - *модель таблицы*
#### Модель таблицы `Hero`
Затем создадим `Hero`, это фактическая *модель таблицы*, с **дополнительными полями**, которых может не быть в других моделях:
Далее давайте создадим **модель таблицы** `Hero` с дополнительными полями, которых может не быть в других моделях:
* `id`
* `secret_name`
Так как `Hero` наследует от `HeroBase`, он **также** содержит **поля**, объявленные в `HeroBase`, так что все поля для `Hero` следующие:
Модель `Hero` наследует от `HeroBase`, и поэтому включает также поля из `HeroBase`. Таким образом, все поля, содержащиеся в `Hero`, будут следующими:
* `id`
* `name`
@ -210,25 +211,25 @@ $ fastapi dev main.py
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
#### `HeroPublic` - публичная *модель данных*
#### Публичная модель данных `HeroPublic`
Далее создаём модель `HeroPublic`, это модель, которая будет **возвращаться** клиентам API.
Далее мы создадим модель `HeroPublic`. Мы будем возвращать её клиентам API.
Она имеет те же поля, что и `HeroBase`, поэтому не будет включать `secret_name`.
Она включает в себя те же поля, что и `HeroBase`, и, соответственно, поле `secret_name` в ней отсутствует.
Наконец-то личности наших героев защищены! 🥷
Наконец-то личность наших героев защищена! 🥷
Также она повторном объявляет `id: int`. Таким образом мы устанавливаем **договоренность** с клиентами API, что они всегда могут ожидать наличие `id` и то, что это будет `int` (оно никогда не будет `None`).
В модели `HeroPublic` также объявляется поле `id: int`. Мы как бы заключаем договоренность с API клиентом, на то, что передаваемые данные всегда должны содержать поле `id`, и это поле должно содержать целое число (и никогда не содержать `None`).
/// tip | Совет
/// tip | Подсказка
Наличие в модели возврата гарантии того, что значение всегда будет доступно и будет `int` (не `None`), очень полезно для API-клиентов, они могут писать более простой код с этой уверенностью.
Модель ответа, гарантирующая наличие поля со значением типа `int` (не `None`), очень полезна при разработке API клиентов. Определенность в передаваемых данных может обеспечить написание более простого кода.
Кроме того, автоматически сгенерированные клиенты будут иметь более простые интерфейсы, так что разработчикам, работающим с вашим API, будет значительно проще. 😎
Также **автоматически генерируемые клиенты** будут иметь более простой интерфейс. И в результате жизнь разработчиков, использующих ваш API, станет значительно легче. 😎
///
Все поля в `HeroPublic` такие же, как в `HeroBase`, с `id`, объявленным как `int` (не `None`):
`HeroPublic` содержит все поля `HeroBase`, а также поле `id`, объявленное как `int` (не `None`):
* `id`
* `name`
@ -236,23 +237,23 @@ $ fastapi dev main.py
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
#### `HeroCreate` - *модель данных* для создания героя
#### Модель для создания героя `HeroCreate`
Сейчас мы создаём модель `HeroCreate`. Это модель, которая будет **проверять** данные от клиентов.
Сейчас мы создадим модель `HeroCreate`. Эта модель будет использоваться для проверки данных, переданных клиентом.
Она содержит те же поля, что и `HeroBase`, а также `secret_name`.
Она содержит те же поля, что и `HeroBase`, а также поле `secret_name`.
Теперь, когда клиенты **создают нового героя**, они отправят `secret_name`, он будет сохранён в базе данных, но эти секретные имена не будут возвращаться в API клиентам.
Теперь, при создании нового героя, клиенты будут передавать секретное имя `secret_name`, которое будет сохранено в базе данных, но не будет возвращено в ответе API клиентам.
/// tip | Совет
/// tip | Подсказка
Это то, как вы должны обрабатывать **пароли**: получайте их, но не возвращайте их в API.
Вот как нужно работать с **паролями**: получайте их, но не возвращайте их через API.
Также **хешируйте** значения паролей перед их сохранением, **никогда не храните их в открытом виде**.
Также хэшируйте значения паролей перед тем, как их сохранить. Ни в коем случае не храните пароли в открытом виде, как обычный текст.
///
Поля `HeroCreate`:
Поля модели `HeroCreate`:
* `name`
* `age`
@ -260,15 +261,15 @@ $ fastapi dev main.py
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
#### Модель для обновления героя `HeroUpdate`
#### Модель для обновления данных героя `HeroUpdate`
В предыдущих версиях нашего приложения у нас не было способа **обновить героя**, но теперь с **несколькими моделями** мы можем это сделать. 🎉
В предыдущих версиях нашей программы мы не могли обновить данные героя, теперь, воспользовавшись дополнительными моделями, мы сможем это сделать. 🎉
*Данные модели* `HeroUpdate` несколько особенные, у них есть **все те же поля**, которые потребуются для создания нового героя, но все поля **необязательны** (они все имеют значение по умолчанию). Таким образом, при обновлении героя вы можете отправить только те поля, которые хотите обновить.
Модель данных `HeroUpdate` в некотором смысле особенная. Она содержит все те же поля, что и модель создания героя, но все поля модели являются **необязательными**. (Все они имеют значение по умолчанию.) Таким образом, при обновлении данных героя, вам достаточно передать только те поля, которые требуют изменения.
Поскольку **все поля фактически изменяются** (тип теперь включает `None` и теперь у них значение по умолчанию `None`), мы должны их **объявить заново**.
Поскольку **все поля по сути меняются** (теперь тип каждого поля допускает значение `None` и значение по умолчанию `None`), мы должны их **объявить заново**.
Нам не нужно наследовать от `HeroBase` потому что мы все равно повторном объявляем все поля. Я оставлю наследование просто для поддержания общего стиля, но это необязательно. Это скорее дело вкуса. 🤷
Фактически, нам не нужно наследоваться от `HeroBase`, потому что мы будем заново объявлять все поля. Я оставлю наследование просто для поддержания общего стиля, но оно (наследование) здесь необязательно. 🤷
Поля `HeroUpdate`:
@ -278,59 +279,59 @@ $ fastapi dev main.py
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
### Создание с помощью `HeroCreate` и возврат `HeroPublic`
### Создание героя с помощью `HeroCreate` и возвращение результатов с помощью `HeroPublic`
Теперь, когда у нас есть **несколько моделей**, мы можем обновить части приложения, которые их используют.
Теперь, когда у нас есть дополнительные модели, мы можем обновить те части приложения, которые их используют.
Мы получаем в запросе модель данных `HeroCreate`, и из нее создаём модель таблицы `Hero`.
Вместе c запросом на создание героя мы получаем объект данных `HeroCreate`, и создаем на его основе объект модели таблицы `Hero`.
Эта новая модель таблицы `Hero` будет иметь поля, отправленные клиентом, а также `id`, сгенерированное базой данных.
Созданный объект *модели таблицы* `Hero` будет иметь все поля, переданные клиентом, а также поле `id`, сгенерированное базой данных.
Затем возвращаем ту же модель таблицы `Hero` как есть из функции. Но так как мы объявляем `response_model` с моделью данных `HeroPublic`, **FastAPI** будет использовать `HeroPublic` для проверки и сериализации данных.
Далее функция вернёт объект *модели таблицы* `Hero`. Но поскольку, мы объявили `HeroPublic` как модель ответа, то **FastAPI** будет использовать именно её для проверки и сериализации данных.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
/// tip | Совет
/// tip | Подсказка
Теперь мы используем `response_model=HeroPublic` вместо аннотации **возвращаемого типа** `-> HeroPublic`, потому что значение, которое мы возвращаем, **на самом деле не** `HeroPublic`.
Теперь мы используем модель ответа `response_model=HeroPublic`, вместо того, чтобы объявить тип возвращаемого значения как `-> HeroPublic`. Мы это делаем потому, что тип возвращаемого значения не относится к `HeroPublic`.
Если бы мы объявили `-> HeroPublic`, ваш редактор и линтер бы пожаловались (и справедливо), что вы возвращаете `Hero`, а не `HeroPublic`.
Если бы мы объявили тип возвращаемого значения как `-> HeroPublic`, то редактор и линтер начали бы ругаться (и вполне справедливо), что возвращаемое значение принадлежит типу `Hero`, а совсем не `HeroPublic`.
Объявляя это в `response_model`, мы говорим **FastAPI** делать свое дело, не вмешиваясь в аннотации типов и не полагаясь на помощь редактора и других инструментов.
Объявляя модель ответа в `response_model`, мы как бы говорим **FastAPI**: делай свое дело, не вмешиваясь в аннотацию типов и не полагаясь на помощь редактора или других инструментов.
///
### Чтение героев с `HeroPublic`
### Чтение данных героев с помощью `HeroPublic`
Мы можем сделать то же самое, как и раньше для **чтения** данных героев, используя `response_model=list[HeroPublic]`, чтобы обеспечить правильную валидацию и сериализацию данных.
Мы можем проделать то же самое **для чтения данных** героев. Мы применим модель ответа `response_model=list[HeroPublic]`, и тем самым обеспечим правильную проверку и сериализацию данных.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
### Чтение данных одного героя с `HeroPublic`
### Чтение данных отдельного героя с помощью `HeroPublic`
Мы можем **читать** данные одного героя:
Мы можем **прочитать** данные отдельного героя:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
### Обновление героя с помощью `HeroUpdate`
### Обновление данных героя с помощью `HeroUpdate`
Мы можем **обновить героя**. Для этого мы используем HTTP-операцию `PATCH`.
Мы можем **обновить данные героя**. Для этого мы воспользуемся HTTP методом `PATCH`.
И в коде мы получаем объект `dict` со всеми данными, отправленными клиентом, содержанием **только данных, отправленных клиентом**, исключая любые значения, которые могут быть там только как значения по умолчанию. Для этого мы используем `exclude_unset=True`. Это главный трюк. 🪄
В коде мы получаем объект словаря `dict` с данными, переданными клиентом (т.е. **только c данными, переданными клиентом**, исключая любые значения, которые могли бы быть там только потому, что они являются значениями по умолчанию). Для того чтобы сделать это, мы воспользуемся опцией `exclude_unset=True`. В этом главная хитрость. 🪄
Затем используем `hero_db.sqlmodel_update(hero_data)`, чтобы обновить `hero_db` данными из `hero_data`.
Затем мы применим `hero_db.sqlmodel_update(hero_data)`, и обновим `hero_db`, использовав данные `hero_data`.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
### Удаление героя снова
### Удалим героя ещё раз
Операция **удаления** героя остаётся практически неизменной.
Операция **удаления** героя практически не меняется.
В этом случае желание *`отрефакторить всё`* остаётся неудовлетворённым. 😅
В данном случае желание *`отрефакторить всё`* остаётся неудовлетворенным. 😅
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
### Снова запуск приложения
### Снова запустим приложение
Вы можете снова запустить приложение:
@ -344,7 +345,7 @@ $ fastapi dev main.py
</div>
Если вы пойдете в пользовательский интерфейс API `/docs`, вы увидите, что он обновлен и больше не ожидает получение параметра `id` от клиента при создании нового героя и т.д.
Если вы перейдете в пользовательский интерфейс API `/docs`, то вы увидите, что он был обновлен, и больше не принимает параметра `id` от клиента при создании нового героя, и т.д.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image02.png">
@ -352,6 +353,6 @@ $ fastapi dev main.py
## Резюме
Вы можете использовать <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> для взаимодействия с реляционной базой данных и упрощения кода с *моделями данных* и *моделями таблиц*.
Вы можете использовать <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> для взаимодействия с реляционными базами данных, а также для упрощения работы с **моделями данных** и **моделями таблиц**.
Вы можете узнать гораздо больше в документации **SQLModel**, там есть более длительное мини <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">руководство по использованию SQLModel с **FastAPI**</a>. 🚀
Вы можете узнать гораздо больше информации в документации по **SQLModel**. Там вы найдете более подробное <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">мини-руководство по использованию SQLModel с **FastAPI**</a>. 🚀

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

@ -1,28 +1,28 @@
# Виртуальное окружение
Когда вы работаете с проектами на Python, вероятно, вам стоит использовать **виртуальное окружение** (или аналогичный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта.
Когда вы работаете с проектами на Python, рекомендуется использовать **виртуальное окружение** (или подобный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта.
/// info | Информация
/// info | Дополнительная информация
Если вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓
///
/// tip | Совет
/// tip | Подсказка
**Виртуальное окружение** отличается от **переменной окружения**.
**Переменная окружения** — это системная переменная, которую могут использовать программы.
**Переменная окружения** — это переменная в системе, которую могут использовать программы.
**Виртуальное окружение** — это директория с файлами.
///
/// info | Информация
/// info | Дополнительная информация
Этот раздел научит вас использовать **виртуальные окружения** и как они работают.
Если вы готовы начать использовать **инструмент, который управляет всем** за вас (включая установку 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>.
///
@ -30,22 +30,22 @@
Сначала создайте директорию для вашего проекта.
Обычно я создаю директорию с именем `code` внутри моего домашнего каталога.
Обычно я создаю директорию, названную `code`, внутри моего домашнего каталога `/home/user`.
И внутри этой директории создаю одну папку для каждого проекта.
Затем, внутри этой директории, я создаю отдельную папку для каждого проекта.
<div class="termy">
```console
// Перейти в домашний каталог
// Перейдите в домашний каталог
$ cd
// Создайте директорию для всех ваших проектов с кодом
// Создайте отдельную папку под всё ваше программное обеспечение (code)
$ mkdir code
// Войдите в указанную директорию
// Войдите в директорию code
$ cd code
// Создайте директорию для этого проекта
// Создайте директорию для данного проекта
$ mkdir awesome-project
// Перейдите в эту директорию проекта
// Перейдите в созданную директорию проекта
$ cd awesome-project
```
@ -53,17 +53,17 @@ $ cd awesome-project
## Создание виртуального окружения
Когда вы начинаете работать над Python-проектом **в первый раз**, создайте виртуальное окружение **<abbr title="существуют и другие варианты, это простое руководство">внутри вашего проекта</abbr>**.
Когда вы начинаете работать над Python-проектом **впервые**, создайте виртуальное окружение **<abbr title="существуют и другие опции, это простая инструкция">внутри вашего проекта</abbr>**.
/// tip | Совет
/// tip | Подсказка
Вы должны сделать это **один раз на проект**, а не каждый раз, когда работаете.
Это нужно сделать **один раз для каждого проекта**, а не каждый раз, когда вы начинаете работу.
///
//// tab | `venv`
Чтобы создать виртуальное окружение, вы можете использовать модуль `venv`, который входит в комплект поставки Python.
Для создания виртуального окружения можно использовать модуль `venv`, который встроен в Python.
<div class="termy">
@ -73,10 +73,10 @@ $ python -m venv .venv
</div>
/// details | Что делает эта команда
/// details | Что делает эта команда?
* `python`: использовать программу `python`
* `-m`: вызвать модуль как сценарий, далее укажем, какой модуль использовать
* `python`: использовать программу под именем `python`
* `-m`: вызывать модуль как скрипт, в следующей инструкции мы укажем, какой модуль вызвать
* `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python
* `.venv`: создать виртуальное окружение в новой директории `.venv`
@ -86,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">
@ -96,9 +96,9 @@ $ uv venv
</div>
/// tip | Совет
/// tip | Подсказка
По умолчанию `uv` создаст виртуальное окружение в директории под названием `.venv`.
По умолчанию `uv` создаст виртуальное окружение в папке под названием `.venv`.
Но вы можете изменить это, передав дополнительный аргумент с именем директории.
@ -106,21 +106,21 @@ $ uv venv
////
Эта команда создаст новое виртуальное окружение в директории `.venv`.
Эта команда создаст новое виртуальное окружение в папке `.venv`.
/// details | `.venv` или другое имя
/// details | `.venv` или другое имя?
Вы можете создать виртуальное окружение в другой директории, но принято называть его `.venv`.
Вы можете создать виртуальное окружение в другой директории, но традиционное (конвенциональное) название — `.venv`.
///
## Активация виртуального окружения
Активируйте новое виртуальное окружение, чтобы любая команда Python, которую вы запускаете, или пакет, который вы устанавливаете, использовала его.
Активируйте виртуальное окружение, чтобы любая запускаемая команда Python или устанавливаемый пакет использовали его.
/// tip | Совет
/// tip | Подсказка
Делайте это **каждый раз**, начиная **новую сессию терминала** для работы над проектом.
Делайте это **каждый раз**, когда начинаете **новую сессию в терминале**, чтобы работать над проектом.
///
@ -150,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">
@ -162,29 +162,13 @@ $ source .venv/Scripts/activate
////
/// tip | Совет
Каждый раз при установке **нового пакета** в эту среду **активируйте** её снова.
Это гарантирует, что если вы используете **программу терминала (<abbr title="command line interface">CLI</abbr>)**, установленную этим пакетом, вы будете использовать её из вашей виртуальной среды, а не любую другую, установленную глобально, вероятно, с другой версией, чем вам нужно.
///
/// tip | Подсказка
Каждый раз, когда вы устанавливаете **новый пакет** в этой среде, **активируйте** ее снова.
Это гарантирует, что если вы используете программу из **терминала (<abbr title="интерфейс командной строки">CLI</abbr>)**, установленную этим пакетом, вы используете ту, что в вашем виртуальном окружении, а не ту, что может быть установлена глобально, с другой версией, чем вам нужно.
///
## Проверка активации виртуального окружения
Проверьте, что виртуальное окружение активно (предыдущая команда сработала).
Проверьте, активировано ли виртуальное окружение (то есть, что предыдущая команда сработала).
/// tip | Совет
/// tip | Подсказка
Это **необязательно**, но хороший способ **убедиться**, что все работает как надо и вы используете то виртуальное окружение, которое хотели.
Эта проверка **необязательна**, но это хороший способ **убедиться**, что все работает, как ожидается, и вы используете нужное вам виртуальное окружение.
///
@ -200,7 +184,7 @@ $ which python
</div>
Если путь указывает на бинарный файл `python` в `.venv/bin/python`, внутри вашего проекта (в нашем случае это `awesome-project`), значит все сработало. 🎉
Если показывается бинарный файл `python` в `.venv/bin/python`, внутри вашего проекта (в данном случае `awesome-project`), это значит, что все сработало. 🎉
////
@ -216,29 +200,29 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
</div>
Если путь указывает на бинарный файл `python` в `.venv\Scripts\python`, внутри вашего проекта (в нашем случае это `awesome-project`), значит все сработало. 🎉
Если показывается бинарный файл `python` в `.venv\Scripts\python`, внутри вашего проекта (в данном случае `awesome-project`), это значит, что все сработало. 🎉
////
## Обновление `pip`
/// tip | Совет
/// tip | Подсказка
Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a> для установки пакетов, вам не нужно обновлять `pip`. 😎
Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, вы должны будете использовать его для установки пакетов вместо `pip`, поэтому обновлять `pip` ненужно. 😎
///
Если вы используете `pip` для установки пакетов (он идет по умолчанию вместе с Python), для начала обновите его до последней версии.
Если вы используете `pip` для установки пакетов (он устанавливается по умолчанию вместе с Python), обновите его до последней версии.
Многие экзотические ошибки при установке пакетов решаются простым обновлением `pip`.
/// tip | Совет
/// tip | Подсказка
Обычно это делается **один раз**, сразу после создания виртуального окружения.
///
Убедитесь, что виртуальное окружение активно (с помощью вышеуказанной команды), и затем запустите:
Убедитесь, что виртуальное окружение активно (при помощи команды выше) и запустите:
<div class="termy">
@ -252,17 +236,17 @@ $ python -m pip install --upgrade pip
## Добавление `.gitignore`
Если вы используете **Git** (и вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить всё из директории `.venv` из Git.
Если вы используете **Git** (и вам стоит это делать), добавьте файл `.gitignore` и исключите всё в `.venv` из Git.
/// tip | Совет
/// 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 | Совет
/// tip | Подсказка
Сделайте это **один раз**, сразу после создания виртуального окружения.
Делайте это **один раз** после создания виртуального окружения.
///
@ -274,15 +258,15 @@ $ echo "*" > .venv/.gitignore
</div>
/// details | Что значит эта команда
/// details | Что делает эта команда?
* `echo "*"`: "выведет" текст `*` в терминал (следующая часть немного это изменит)
* `>`: всё, что печатается командой слева от `>`, не должно быть выведено, а записано в файл справа от `>`
* `echo "*"`: напечатает текст `*` в терминале (следующая часть изменит это)
* `>`: всё, что будет напечатано в терминал командой с левой стороны от `>`, не печатать, а вместо этого записать в файл, который указан справа от `>`
* `.gitignore`: имя файла, в который должен быть записан текст
А `*` для Git означает "всё". То есть будут проигнорированы все содержимое директории `.venv`.
А `*` в Git означает "всё". Следовательно, будет проигнорировано всё, что содержится в директории `.venv`.
Эта команда создаст файл `.gitignore` с содержимым:
Эта команда создаст файл `.gitignore` со следующим содержимым:
```gitignore
*
@ -292,23 +276,23 @@ $ echo "*" > .venv/.gitignore
## Установка пакетов
После активации окружения вы можете устанавливать в него пакеты.
После активации окружения вы можете установить в него пакеты.
/// tip | Совет
/// tip | Подсказка
Сделайте это **один раз** при установке или обновлении пакетов, нужных вашему проекту.
Сделайте это **один раз**, при установке или обновлении пакетов, необходимых вашему проекту.
Если вам нужно обновить версию пакета или добавить новый пакет, вам нужно будет **сделать это снова**.
Если вам нужно обновить версию или добавить новый пакет, вы должны будете **сделать это снова**.
///
### Установка пакетов напрямую
Если вам срочно нужно и вы не хотите использовать файл для объявления зависимостей пакета вашего проекта, вы можете установить их напрямую.
Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, вы можете установить их напрямую.
/// tip | Совет
/// tip | Подсказка
Очень хорошей идеей будет заносить пакеты и версии, которые нужны вашей программе, в файл (например, `requirements.txt` или `pyproject.toml`).
Очень хорошая идея — указать пакеты и версии, которые нужны вашей программе, в отдельном файле (например, `requirements.txt` или `pyproject.toml`).
///
@ -328,7 +312,7 @@ $ pip install "fastapi[standard]"
//// 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">
@ -360,7 +344,7 @@ $ pip install -r requirements.txt
//// 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">
@ -375,7 +359,7 @@ $ uv pip install -r requirements.txt
/// details | `requirements.txt`
`requirements.txt` со списком некоторых пакетов может выглядеть так:
Файл `requirements.txt` с некоторыми пакетами может выглядеть так:
```requirements.txt
fastapi[standard]==0.113.0
@ -386,7 +370,7 @@ pydantic==2.8.0
## Запуск программы
После активации виртуального окружения вы можете запустить свою программу, и она будет использовать Python из вашего виртуального окружения с установленными там пакетами.
После активации виртуального окружения вы можете запустить свою программу, и она будет использовать версию Python и пакеты, установленные в этом окружении.
<div class="termy">
@ -400,22 +384,22 @@ Hello World
## Настройка редактора
Вероятно, вы будете использовать редактор кода; убедитесь, что вы настроили его для использования того же виртуального окружения, которое вы создали (вероятно, он его автоматически обнаружит), чтобы у вас были автозавершение и подсветка ошибок.
Вы, вероятно, будете использовать редактор, убедитесь, что вы настроили его на использование того же виртуального окружения, которое вы создали (скорее всего, он обнаружит это автоматически), чтобы получить автозавершение и выделение ошибок в коде.
Например:
* <a href="https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment" class="external-link" target="_blank">VS Code</a>
* <a href="https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html" class="external-link" target="_blank">PyCharm</a>
/// tip | Совет
/// tip | Подсказка
Обычно это делается **один раз**, при создании виртуального окружения.
Обычно это нужно делать только **один раз**, когда вы создаете виртуальное окружение.
///
## Деактивация виртуального окружения
Когда вы завершите работу над проектом, вы можете **деактивировать** виртуальное окружение.
Когда вы закончите работу над проектом, вы можете **деактивировать** виртуальное окружение.
<div class="termy">
@ -425,53 +409,55 @@ $ deactivate
</div>
Таким образом, когда вы запускаете `python`, он не будет пытаться запустить его из того виртуального окружения с установленными в нём пакетами.
Итак, при запуске `python` не будет попыток использовать Python из этого виртуального окружения с установленными там пакетами.
## Готовность к работе
## Все готово к работе
Теперь вы готовы начать работу над своим проектом.
/// tip | Совет
Хотите понять, что означает все вышеперечисленное?
Продолжайте чтение. 👇🤓
/// tip | Подсказка
Хотите понять, что это было выше?
Продолжайте читать. 👇🤓
///
## Зачем использовать виртуальные окружения
## Зачем нужно виртуальное окружение
Для работы с 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">
@ -481,7 +467,7 @@ $ pip install "harry==1"
</div>
И тогда у вас будет установлена версия `harry` `1` в вашем глобальном Python.
И тогда у вас будет установлен `harry` версии `1` в вашем глобальном окружении Python.
```mermaid
flowchart LR
@ -493,7 +479,7 @@ flowchart LR
end
```
Но если вы хотите запустить `prisoner-of-azkaban`, вам нужно будет удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`).
Но потом, если вы хотите запустить `prisoner-of-azkaban`, вам придется удалить `harry` версии `1` и установить `harry` версии `3` (или установка версии `3` автоматически удалит версию `1`).
<div class="termy">
@ -503,9 +489,9 @@ $ pip install "harry==3"
</div>
И затем у вас будет установлена версия `harry` `3` в вашем глобальном Python.
И тогда у вас будет установлен `harry` версии `3` в вашем глобальном окружении Python.
И если вы снова попытаетесь запустить `philosophers-stone`, есть вероятность, что он **не будет работать**, потому что ему нужен `harry` версии `1`.
И если вы попытаетесь снова запустить `philosophers-stone`, существует вероятность, что он **не будет работать**, потому что ему нужен `harry` версии `1`.
```mermaid
flowchart LR
@ -522,49 +508,49 @@ flowchart LR
end
```
/// tip | Совет
/// tip | Подсказка
В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новых версиях, но лучше перестраховаться и намеренно устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно.
В пакетах Python очень часто стараются изо всех сил **избегать внесения критических изменений** в **новые версии**, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, всё ли работает правильно.
///
Теперь представьте это с **множеством** других **пакетов**, от которых зависят все ваши **проекты**. Это очень сложно управляемо. И, вероятно, вы будете запускать некоторые проекты с некоторыми **несовместимыми версиями** пакетов и не будете знать, почему что-то не работает.
Теперь представьте, что это происходит с **многими другими** **пакетами**, от которых зависят все ваши **проекты**. Управлять этим очень трудно. И вы, вероятно, в итоге будете запускать некоторые проекты с **несовместимыми версиями** пакетов, и не будете знать, почему что-то не работает.
Кроме того, в зависимости от вашей операционной системы (например, Linux, Windows, macOS), она могла быть поставлена с уже установленным Python. И в этом случае, вероятно, были предустановлены некоторые пакеты с определёнными версиями, **нужными вашей системе**. Если вы устанавливаете пакеты в глобальной среде 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.
Затем он **извлечёт** все эти файлы и поместит их в директорию на вашем компьютере.
Затем он **извлечёт** все эти файлы и разместит их в директории на вашем компьютере.
По умолчанию, он разместит те загруженные и извлечённые файлы в директории, которая идёт с вашей установкой Python, это ваш **глобальный Python**.
По умолчанию, он поместит эти загруженные и распакованные файлы в директорию установку Python, это и есть **глобальное окружение**.
## Что такое виртуальные окружения?
## Что такое виртуальное окружение
Решением проблем того, что все пакеты находятся в глобальной среде, является использование **виртуального окружения для каждого проекта**, над которым вы работаете.
Решением проблемы размещения всех пакетов в глобальной среде является использование **виртуального окружения для каждого проекта**, над которым вы работаете.
Виртуальное окружение — это **директория**, очень похожая на глобальную, где вы можете устанавливать пакеты для проекта.
Виртуальное окружение — это **директория**, очень похожая на глобальную, в которой вы можете устанавливать пакеты для проекта.
Таким образом, каждый проект будет иметь своё собственное виртуальное окружение (директорию `.venv`) со своими пакетами.
Таким образом, у каждого проекта будет своё виртуальное окружение (директория `.venv`) с собственными пакетами.
```mermaid
flowchart TB
@ -583,9 +569,9 @@ flowchart TB
stone-project ~~~ azkaban-project
```
## Что означает активация виртуального окружения?
## Что означает активация виртуального окружения
Когда вы активируете виртуальное окружение, например, с помощью:
Когда вы активируете виртуальное окружение, например:
//// tab | Linux, macOS
@ -625,19 +611,19 @@ $ source .venv/Scripts/activate
////
Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для следующих команд.
Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд.
Одна из этих переменных — переменная `PATH`.
Одна из этих переменных называется `PATH`.
/// tip | Совет
/// 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
@ -666,7 +652,7 @@ C:\Windows\System32
////
После активации виртуального окружения переменная `PATH` будет выглядеть примерно так:
После активации виртуального окружения переменная окружения `PATH` будет выглядеть примерно так:
//// tab | Linux, macOS
@ -674,7 +660,7 @@ C:\Windows\System32
/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
Это означает, что система теперь начнёт искать программы в:
Это означает, что система теперь будет в первую очередь искать программы в:
```plaintext
/home/user/code/awesome-project/.venv/bin
@ -682,13 +668,13 @@ C:\Windows\System32
прежде чем искать в других директориях.
Таким образом, когда вы вводите `python` в терминале, система обнаружит программу Python в
Так что, когда вы вводите `python` в терминале, система найдет программу Python в
```plaintext
/home/user/code/awesome-project/.venv/bin/python
```
и будет использовать её.
и использует именно её.
////
@ -698,7 +684,7 @@ C:\Windows\System32
C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
```
Это означает, что система теперь начнёт искать программы в:
Это означает, что система теперь будет в первую очередь искать программы в:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts
@ -706,23 +692,23 @@ 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` (например, `python` из глобального окружения).
Важная деталь заключается в том, что путь к виртуальному окружению будет помещён в самое **начало** переменной `PATH`. Система найдет его **до** обнаружения любого другого доступного Python. Таким образом, когда вы запускаете `python`, он будет использовать **Python из виртуального окружения**, а не какой-либо другой `python` (например, `python` из глобального окружения).
Активация виртуального окружения также меняет несколько других вещей, но это одна из самых важных функций.
Активация виртуального окружения также изменяет несколько других вещей, но это одна из самых важных вещей, которые она делает.
## Проверка виртуального окружения
Когда вы проверяете, активно ли виртуальное окружение, например, с помощью:
Когда вы проверяете, активировано ли виртуальное окружение, например:
//// tab | Linux, macOS, Windows Bash
@ -752,33 +738,33 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
////
Это означает, что программа `python`, которая будет использоваться, — это программа **из виртуального окружения**.
Это означает, что программа `python`, которая будет использована, — это та, что находится **в виртуальной среде разработки**.
Вы используете `which` на Linux и macOS и `Get-Command` на Windows PowerShell.
Работа этой команды заключается в том, что она проверяет переменную окружения `PATH`, проходя по **каждому пути по порядку** в поисках программы под названием `python`. Как только она её находит, она **показывает вам путь** к этой программе.
Способ работы этой команды заключается в том, что она пойдёт и проверит переменную окружения `PATH`, проходя **каждый путь по порядку**, в поисках программы под названием `python`. Как только она её найдет, она **покажет вам путь** к этой программе.
Наиболее важной частью является то, что когда вы вызываете `python`, это тот самый "`python`", который будет запущен.
Самое важное тут в том, что когда вы вызываете `python`, именно этот "`python`" будет выполнен.
Таким образом, вы можете убедиться, что находитесь в правильном виртуальном окружении.
Таким образом, вы можете убедиться, что используете верное виртуальное окружение.
/// tip | Совет
/// tip | Подсказка
Легко активировать одно виртуальное окружение, а затем **перейти к другому проекту**.
Легко активировать одно виртуальное окружение, получить одного Python, а затем **перейти к другому проекту**.
И второй проект **не будет работать**, потому что вы используете **неправильный Python**, из виртуального окружения другого проекта.
И второе проект **не будет работать**, потому что вы используете **неправильный Python** из виртуального окружения для другого проекта.
Полезно уметь проверять, какой `python` используется. 🤓
Это очень полезно уметь проверять, какой `python` используется. 🤓
///
## Зачем деактивировать виртуальное окружение?
## Почему деактивировать виртуальное окружение
Например, вы можете работать над проектом `philosophers-stone`, **активировать это виртуальное окружение**, устанавливать пакеты и работать в этой среде.
Например, вы можете работать над проектом `philosophers-stone`, **активировать это виртуальное окружение**, установить пакеты и работать с этой средой.
А затем вы хотите поработать над **другим проектом** `prisoner-of-azkaban`.
И затем вы хотите работать над **другим проектом** `prisoner-of-azkaban`.
Вы переходите в этот проект:
Вы переходите к этому проекту:
<div class="termy">
@ -788,7 +774,7 @@ $ cd ~/code/prisoner-of-azkaban
</div>
Если вы не деактивируете виртуальное окружение для `philosophers-stone`, когда вы запускаете `python` в терминале, он попытается использовать Python из `philosophers-stone`.
Если вы не деактивируете виртуальное окружение для `philosophers-stone`, когда вы запускаете `python` в терминале, оно будет пытаться использовать Python из `philosophers-stone`.
<div class="termy">
@ -797,7 +783,7 @@ $ cd ~/code/prisoner-of-azkaban
$ python main.py
// Ошибка при импорте sirius, он не установлен 😱
// Ошибка импорта sirius, он не установлен 😱
Traceback (most recent call last):
File "main.py", line 1, in <module>
import sirius
@ -805,20 +791,20 @@ Traceback (most recent call last):
</div>
Но если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, то, когда вы запускаете `python`, он будет использовать 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
Я торжественно клянусь 🐺
@ -828,23 +814,23 @@ $ python main.py
## Альтернативы
Это простое руководство, чтобы начать работу и показать, как всё **работает изнутри**.
Это простое руководство поможет вам начать и научит тому, как все работает **изнутри**.
Существует много **альтернатив** для управления виртуальными окружениями, зависимостями пакетов, проектами.
Существует множество **альтернатив** для управления виртуальными окружениями, зависимостями пакетов (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** для вас, включая различные версии
* Управлять **виртуальным окружением** для ваших проектов
* Устанавливать **пакеты**
* Управлять зависимостями пакетов и версиями для вашего проекта
* Гарантировать, что у вас есть **точный** набор пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что вы можете запустить ваш проект в продакшн точно так же, как на вашем компьютере во время разработки, это называется **locking**
* И многие другие вещи
* Управлять **зависимостями и версиями** пакетов для вашего проекта
* Убедиться, что у вас есть **точный** набор пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что вы сможете запустить ваш проект в production точно так же, как на вашем компьютере, когда разрабатываете, это называется **locking**
* И многое другое
## Заключение
Если вы прочли и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие разработчики. 🤓
Если вы прочитали и поняли все это, то теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие другие разработчики. 🤓
Понимание этих деталей, вероятно, будет полезно в будущем, когда вы будете отлаживать что-то, кажущееся сложным, но вы будете знать, **как всё работает под капотом**. 😎
Знание этих деталей, скорее всего, будет полезно вам в будущем, когда вы будете отлаживать что-то, что кажется сложным, потому что вы будете знать, **как все работает изнутри**. 😎

Loading…
Cancel
Save