Browse Source

🌐Update Russian translations that were changed after the last commit

pull/13935/head
Sebastián Ramírez 7 days ago
parent
commit
634e54aa74
  1. 445
      docs/ru/docs/async.md
  2. 45
      docs/ru/docs/benchmarks.md
  3. 176
      docs/ru/docs/deployment/manually.md
  4. 255
      docs/ru/docs/help-fastapi.md
  5. 266
      docs/ru/docs/index.md
  6. 112
      docs/ru/docs/project-generation.md
  7. 72
      docs/ru/docs/tutorial/body-multiple-params.md
  8. 67
      docs/ru/docs/tutorial/cors.md
  9. 96
      docs/ru/docs/tutorial/extra-models.md
  10. 242
      docs/ru/docs/tutorial/first-steps.md
  11. 14
      docs/ru/docs/tutorial/handling-errors.md
  12. 88
      docs/ru/docs/tutorial/index.md
  13. 87
      docs/ru/docs/tutorial/middleware.md
  14. 370
      docs/ru/docs/tutorial/query-params-str-validations.md
  15. 72
      docs/ru/docs/tutorial/response-status-code.md
  16. 221
      docs/ru/docs/tutorial/sql-databases.md
  17. 345
      docs/ru/docs/virtual-environments.md

445
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="too long; didn't read"><strong>TL;DR:</strong></abbr>
Допустим, вы используете сторонюю библиотеку, которая требует вызова с ключевым словом `await`:
Если вы используете сторонние библиотеки, которые требуют вызова с ключевым словом `await`, как:
```Python
results = await some_library()
```
В этом случае *функции обработки пути* необходимо объявлять с использованием синтаксиса `async def`:
Тогда объявляйте свои *функции обработки пути* с использованием `async def`, как:
```Python hl_lines="2"
@app.get('/')
@ -21,18 +21,15 @@ async def read_results():
return results
```
/// note
/// note | Примечание
`await` можно использовать только внутри функций, объявленных с использованием `async def`.
Вы можете использовать `await` только внутри функций, созданных с помощью `async def`.
///
---
Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует
(с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await`
(что относится сейчас к большинству библиотек для работы с базами данных), то
объявляйте *функции обработки пути* обычным образом с помощью `def`, например:
Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т. д.) и не поддерживает использование `await`, (это в настоящее время относится к большинству библиотек для работы с базами данных), то объявляйте свои *функции обработки пути* как обычно, просто с `def`, как:
```Python hl_lines="2"
@app.get('/')
@ -43,27 +40,25 @@ def results():
---
Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно,
ожидать ответа, используйте `async def`.
Если вашему приложению (каким-то образом) не нужно взаимодействовать ни с чем и ждать ответа, используйте `async def`, даже если вам не нужно использовать `await` внутри.
---
Если вы не уверены, используйте обычный синтаксис `def`.
Если вы не знаете, используйте обычный `def`.
---
**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях обработки пути*
и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно.
**Примечание**: Вы можете смешивать `def` и `async def` в своих *функциях обработки пути* столько, сколько вам нужно, и определять каждую с использованием наилучшего для вас варианта. FastAPI сделает с ними всё как надо.
В любом из описанных случаев FastAPI работает асинхронно и очень быстро.
В любом случае, в любой из упомянутых выше ситуаций, FastAPI всё равно будет работать асинхронно и с высокой скоростью.
Однако придерживаясь указанных советов, можно получить дополнительную оптимизацию производительности.
Но, следуя указанным выше шагам, он сможет оптимизировать производительность.
## Технические подробности
Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**.
Современные версии Python поддерживают **"асинхронный код"** с использованием чего-то, называемого **"сопрограммами"**, с синтаксисом **`async` и `await`**.
Ниже разберём эту фразу по частям:
Давайте рассмотрим эту фразу по частям в следующих разделах:
* **Асинхронный код**
* **`async` и `await`**
@ -71,282 +66,257 @@ def results():
## Асинхронный код
Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖,
что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝.
Асинхронный код просто значит, что язык 💬 имеет способ сообщить компьютеру / программе 🤖, что в какой-то момент в коде, ему 🤖 нужно будет дождаться, пока *что-то ещё* завершится где-то ещё. Пусть это *что-то ещё* называется "медленный файл" 📝.
И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач.
Так что, в это время, компьютер может выполнять какую-то другую работу, пока "медленный файл" 📝 заканчивается.
Но при каждой возможности компьютер / программа 🤖 будет возвращаться обратно. Например, если он 🤖 опять окажется в режиме ожидания, или когда закончит всю работу. В этом случае компьютер 🤖 проверяет, не завершена ли какая-нибудь из текущих задач.
Потом компьютер / программа 🤖 будет возвращаться каждый раз, когда у него будет шанс, потому что он снова ждет, или когда он 🤖 закончит всю работу, которую у него была к тому моменту. И он 🤖 проверит, не завершилась ли какая-либо из задач, чтобы выполнить то, что нужно.
Потом он 🤖 берёт первую выполненную задачу (допустим, наш "медленный файл" 📝) и продолжает работу, производя с ней необходимые действия.
Затем он 🤖 берёт первую задачу, которая завершилась (например, наш "медленный файл" 📝) и продолжает выполнение того, что ему надо было сделать.
Вышеупомянутое "что-то ещё", завершения которого приходится ожидать, обычно относится к достаточно "медленным" операциям <abbr title="Ввода-вывода">I/O</abbr> (по сравнению со скоростью работы процессора и оперативной памяти), например:
Этот "ожидать чего-то ещё" обычно относится к операциям <abbr title="Ввод и вывод">I/O</abbr>, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например:
* отправка данных от клиента по сети
* получение клиентом данных, отправленных вашей программой по сети
* чтение системой содержимого файла с диска и передача этих данных программе
* запись на диск данных, которые программа передала системе
* обращение к удалённому API
* ожидание данных от клиента, отправленных через сеть
* ожидание, когда данные, отправленные программой, будут получены клиентом через сеть
* ожидание, когда содержимое файла на диске будет прочитано системой и передано вашей программе
* ожидание, когда данные, которые ваша программа передала системе, будут записаны на диск
* удалённая операция API
* ожидание завершения операции с базой данных
* получение результатов запроса к базе данных
* ожидание, когда запрос к базе данных вернёт результаты
* и т. д.
Поскольку в основном время тратится на ожидание выполнения операций <abbr title="Ввода-вывода">I/O</abbr>,
их обычно называют операциями, <abbr title="I/O bound">ограниченными скоростью ввода-вывода</abbr>.
Поскольку основное время выполнения тратится на ожидание операций <abbr title="Ввод и вывод">I/O</abbr>, их называют операциями, "связанными с вводом-выводом" (<abbr title="I/O bound">I/O bound</abbr>).
Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и,
будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу.
Это называется "асинхронным", потому что компьютер / программе не нужно "синхронизироваться" с медленной задачей и ожидать момент, когда задача завершится, ничего не делая, чтобы затем взять результат задачи и продолжить работу.
Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд),
пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться,
забрать результаты выполнения и начать их обрабатывать.
Вместо этого, в "асинхронной" системе завершённая задача может чуть-чуть подождать (несколько микросекунд), пока компьютер / программа завершит выполнение того, что она занималась, а потом вернуться, чтобы взять результаты и продолжить их обработку.
"Синхронное" исполнение (в противовес "асинхронному") также называют <abbr title="sequential">"последовательным"</abbr>,
потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче,
даже если в процессе приходится ждать.
Для "синхронного" (в отличие от "асинхронного") часто используют термин "последовательный", потому что компьютер / программа проходит все шаги последовательно перед переключением на другую задачу, даже если они включают в себя ожидание.
### Конкурентность и бургеры
Тот **асинхронный** код, о котором идёт речь выше, иногда называют **"конкурентностью"**. Она отличается от **"параллелизма"**.
Эту идею **асинхронного** кода, описанную выше, иногда также называют **"конкурентностью"**. Это отличается от **"параллелизма"**.
Да, **конкурентность** и **параллелизм** подразумевают, что разные вещи происходят примерно в одно время.
**Конкурентность** и **параллелизм** оба подразумевают, что "разные вещи происходят более или менее в одно время".
Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное.
Но детали между *конкурентностью* и *параллелизмом* достаточно разные.
Чтобы это понять, представьте такую картину:
Чтобы увидеть разницу, представьте следующую историю о бургерах:
### Конкурентные бургеры
<!-- The gender neutral cook emoji "🧑‍🍳" does not render well in browsers. In the meantime, I'm using a mix of male "👨‍🍳" and female "👩‍🍳" cooks. -->
Вы идёте с вашей возлюбленной в фастфуд, становитесь в очередь, пока кассир принимает заказы у людей перед вами. 😍
Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами.
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе.
Затем наступает ваша очередь, вы заказываете 2 очень вкусных бургеров для вашей возлюбленной и для вас. 🍔🍔
Отдаёте деньги 💸.
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
Кассир 💁 что-то говорит поварам на кухне 👨‍🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔
(но пока они заняты бургерами предыдущих клиентов).
Кассир что-то говорит повару на кухне, чтобы они знали, что надо приготовить ваши бургеры (даже если они в данный момент готовят бургеры для предыдущих клиентов).
Кассир 💁 отдаёт вам чек с номером заказа.
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍
(поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨).
Вы платите. 💸
Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время,
восхищаясь её великолепием, красотой и умом ✨😍✨.
Кассир даёт вам номер вашего заказа.
Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете,
какой номер горит над прилавком, и не подошла ли уже ваша очередь.
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик.
В ожидании еды, вы идёте с вашей возлюбленной выбрать столик, садитесь и долго разговариваете с вашей возлюбленной (поскольку ваши бургеры очень вкусные и их приготовление занимает некоторое время).
Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨.
Сидя за столиком с вашей возлюбленной, пока вы ждёте бургеры, вы тратите это время, чтобы восхищаться тем, насколько ваша возлюбленная замечательная, милая и умная ✨😍✨.
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
Во время ожидания и разговора с вашей возлюбленной время от времени вы проверяете номер, отображаемый на стойке, чтобы увидеть, не наступило ли ваше ожидание.
Затем в какой-то момент это наконец ваша очередь. Вы идёте к стойке, забираете свои бургеры и возвращаетесь к столу.
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
Вы и ваша возлюбленная едите бургеры и наслаждаетесь временем вместе. ✨
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
/// info | Информация
Прекрасные иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Кетрины Томпсон</a>. 🎨
///
---
А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖.
Представьте, что в этой истории вы — компьютер / программа 🤖.
В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете.
Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного.
В очереди вы бездействуете 😴, ожидая своей очереди, особо ничего "продуктивного" не делая. Но очередь быстро движется, так как кассир только берёт заказы (а не готовит их), так что это нормально.
Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д.
Затем, когда наступает ваша очередь, вы делаете настоящую "продуктивную" работу, обрабатываете меню, решаете, что хотите, узнаёте выбор вашей возлюбленной, оплачиваете, проверяете, что даёте правильную сумму или карту, проверяете, правильно ли с вас взяли оплату, содержится ли в заказе всё, что нужно, и так далее.
И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸,
поскольку теперь нужно ждать 🕙, когда заказ приготовят.
Но потом, хотя вы всё еще не получили свои бургеры, ваша работа с кассиром "на паузе" ⏸, потому что вы должны ждать 🕙, пока приготовятся ваши бургеры.
Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание
на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень
"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍.
Но уходя от стойки и садясь за столик с номером вашего заказа, вы можете переключить 🔀 своё внимание на свою возлюбленную, и "работать" ⏯ 🤓 над этим. Таким образом, вы снова делаете что-то очень "продуктивное", как флирт с вашей возлюбленной 😍.
В какой-то момент кассир 💁 поместит на табло ваш номер, подразумевая, что бургеры готовы 🍔, но вы не станете подскакивать как умалишённый, лишь только увидев на экране свою очередь. Вы уверены, что ваши бургеры 🍔 никто не утащит, ведь у вас свой номерок, а у других свой.
Кассир 💁 говорит "я закончил делать бургеры" через показ номера вашего заказа на табло, но вы не вскакиваете, как сумасшедший, когда отображаемый номер меняется на номер вашей очереди. Вы знаете, что никто не украдёт у вас бургеры, потому что у вас есть номер вашего заказа, а у других — свои.
Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓),
и мило улыбнувшись, скажете, что идёте забирать заказ ⏸.
Поэтому вы ждёте, пока ваша возлюбленная закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓), мило улыбаетесь и говорите, что идёте забирать бургеры ⏸.
И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹.
В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
Затем вы идёте к стойке 🔀, к первоначальной задаче, которая завершена ⏯, берете бургеры, говорите спасибо и возвращаетесь за столик. Это завершает эту часть / задание взаимодействия с кассиром ⏹. Это, в свою очередь, создаёт новую задачу — "есть бургеры" 🔀 ⏯, но предыдущая — "получить бургеры" завершена ⏹.
### Параллельные бургеры
Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры".
Теперь представим, что это не "Конкурентные бургеры", а "Параллельные бургеры".
И вот вы идёте со своей возлюбленной 😍 отведать параллельного фастфуда 🍔.
Вы идёте с вашей возлюбленной попробовать параллельный фастфуд.
Вы становитесь в очередь пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами.
Вы стоите в очереди, пока несколько (скажем, 8) кассиров, которые одновременно являются поварами, принимают заказы у людей перед вами.
При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый
из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ.
Все перед вами ожидают, когда их бургеры будут готовы до того, как они покинут кассу, поскольку каждый из 8 кассиров сразу идет и готовит бургер, прежде чем получить следующий заказ.
Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе.
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
Ни о чём не жалея, расплачиваетесь 💸.
Затем, наконец, наступает ваша очередь, вы заказываете 2 очень вкусных бургера для вашей возлюбленной и вас.
И кассир уходит на кухню 👨‍🍳.
Вы оплачиваете 💸.
Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет.
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь,
у вас не получается уделять должного внимание своей даме сердца 😞.
Кассир идёт на кухню.
Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки,
когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой.
Вы ждёте, стоя перед прилавком 🕙, чтобы никто не забрал ваши бургеры перед вами, так как номеров заказа нет.
Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой.
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик.
Поскольку вы и ваша возлюбленная заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они прибудут, вы не можете уделить внимания вашей возлюбленной. 😞
Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹.
Это "синхронная" работа: вы "синхронизированы" с кассиром/поваром 👨‍🍳. Вам приходится ждать 🕙 и быть там в точный момент, когда кассир/повар 👨‍🍳 завершает приготовление бургеров и отдаёт их вам, иначе кто-то может их взять.
Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞.
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
---
Затем ваш кассир/повар 👨‍🍳 наконец возвращается с вашими бургерами, после долгого ожидания 🕙 перед стойкой.
В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍),
на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе".
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳.
Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳.
Вы берёте ваши бургеры и идёте за столик с вашей возлюбленной.
Несмотря на обилие работников, опыт в итоге получился не из лучших 😞.
Вы их просто кушаете, и всё. ⏹
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
Обменяться словами или пофлиртовать не очень получилось, так как больше времени было потрачено на ожидание 🕙 перед стойкой. 😞
/// info | Информация
Прекрасные иллюстрации от <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Кетрины Томпсон</a>. 🎨
///
---
Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире.
В этом сценарии с параллельными бургерами вы — это компьютер / программа 🤖 с двумя процессорами (вы и ваша возлюбленная), оба долгое время ожидающие 🕙 и посвящающие своё внимание ⏯ быть "ожидающими у кассы" 🕙.
В этом фастфуд-магазине 8 процессоров (кассиров/поваров). Хотя в магазине конкурентных бургеров могло быть только 2 (один кассир и один повар).
Вот более реалистичный пример. Представьте себе банк.
Но всё же, окончательный опыт не самый лучший. 😞
До недавних пор в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙.
---
Каждый кассир обслуживал одного клиента, потом следующего 👨‍💼⏯.
Это была бы параллельная аналогичная история для бургеров. 🍔
Нужно было долгое время 🕙 стоять перед окошком вместе со всеми, иначе пропустишь свою очередь.
Для более "реального" примера этого, представьте банк.
Сомневаюсь, что у вас бы возникло желание прийти с возлюбленной 😍 в банк 🏦 оплачивать налоги.
До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинная очередь 🕙🕙🕙🕙🕙🕙🕙🕙.
### Выводы о бургерах
Все кассиры занимались каждым клиентом один за другим 👨‍💼⏯.
В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙,
поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯.
И вам долгое время приходилось ждать 🕙 в очереди, иначе потеряете свою очередь.
И то же самое с большинством веб-приложений.
Скорее всего, вам бы не захотелось брать вашу возлюбленную 😍 с собой для быстрого похода в банк 🏦.
Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению.
### Заключение о бургерах
Потом снова ждать 🕙, пока вернётся ответ.
В этом сценарии "быстрого питания с бургерами с вашей возлюбленной", так как там много ожидания 🕙, имеет много больше смысла иметь конкурентную систему ⏸🔀⏯.
<!--https://forum.wordreference.com/threads/%D0%9D%D0%BE-%D0%B5%D1%81%D0%BB%D0%B8.3258695/-->
Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени.
И это и есть случай для большинства веб-приложений.
Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API.
Много, много пользователей, но ваш сервер ожидает 🕙, чтобы они отправили свои запросы через своё не очень хорошее соединение.
Большинство популярных фреймворков (включая Flask и Django) создавались
до появления в Python новых возможностей асинхронного программирования. Поэтому
их можно разворачивать с поддержкой параллельного исполнения или асинхронного
программирования старого типа, которое не настолько эффективно.
И потом снова ждёт 🕙, чтобы ответы вернулись.
При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером
(<a href="https://asgi.readthedocs.io" class="external-link" target="_blank">ASGI</a>)
была разработана командой Django для внедрения поддержки веб-сокетов.
Это "ожидание" 🕙 измеряется в микросекундах, но в итоге, если всё сложить, это много времени ожидания.
Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный),
и в этом преимущество Go как языка программирования.
Вот почему имеет смысл использовать асинхронный код ⏸🔀⏯ для веб-API.
И тот же уровень производительности даёт **FastAPI**.
Эта форма асинхронности является тем, что сделало NodeJS популярным (хотя NodeJS не параллелен) и это то, что делает Go мощным языком программирования.
Поскольку можно использовать преимущества параллелизма и асинхронности вместе,
вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков
и на уровне с Go, который является компилируемым языком близким к C <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(всё благодаря Starlette)</a>.
И это тот же уровень производительности, который вы получаете с **FastAPI**.
### Получается, конкурентность лучше параллелизма?
И так как у вас может быть параллелизм и асинхронность одновременно, вы получаете более высокую производительность, чем большинство протестированных NodeJS фреймворков, и сопоставимо с Go, который является компилируемым языком, ближе к C <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(всё это благодаря Starlette)</a>.
Нет! Мораль истории совсем не в этом.
### Конкуренция лучше параллелизма?
Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание.
Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях.
Нет! Это не мораль истории.
Давайте посмотрим с другой стороны, представьте такую картину:
Конкурентность отличается от параллелизма. И она лучше в **конкретных** сценариях, которые включают много ожидания. Из-за этого, обычно она намного лучше, чем параллелизм для разработки веб-приложений. Но не всегда и не для всего.
> Вам нужно убраться в большом грязном доме.
Так что, чтобы уравновесить это, представьте себе следующий короткий рассказ:
> Вам нужно убрать большой, грязный дом.
*Да, это вся история*.
---
Тут не нужно нигде ждать 🕙, просто есть куча работы в разных частях дома.
Тут нет ожидания 🕙 нигде, просто много работы по разным местам дома.
Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня,
но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете.
Вы могли бы иметь очереди как в примере с бургерами, сначала гостиная, затем кухня, но так как вы не ждете 🕙 чего-либо, а просто убираете и убираете, очереди никак не повлияют на это.
И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё,
и работы будет сделано тоже одинаковое количество.
Добавление или отсутствие очередей (конкурентности) не увеличит или уменьшит время завершения работы, и вы выполните то же количество работы.
Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳,
и каждый из них (вместе с вами) взялся бы за свой участок дома,
с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**.
Но в этом случае, если бы вы могли пригласить 8 бывших кассиров/поваров/теперь-уборщиков, и каждый из них (вместе с вами) мог бы взяться за зону дома, чтобы ее убрать, вы могли бы сделать всю работу **параллельно**, с дополнительной помощью, и закончить намного быстрее.
В описанном сценарии каждый уборщик (включая вас) был бы исполнителем, занятым на своём участке работы.
В этой ситуации каждый из уборщиков (включая вас) будет процессором, выполняющим свою часть работы.
И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание),
а работу в компьютере делает <abbr title="Центральный процессор (CPU)">ЦП</abbr>,
такие задачи называют <abbr title="CPU bound">ограниченными производительностью процессора</abbr>.
И поскольку основная часть времени выполнения уходит на реальную работу (вместо ожидания), и работа в компьютере выполняется <abbr title="Центральный процессор">ЦП</abbr>, такие задачи называют "ограниченными производительностью процессора" (<abbr title="CPU bound">CPU bound</abbr>).
---
Ограничение по процессору проявляется в операциях, где требуется выполнять сложные математические вычисления.
Общие примеры операций, связанные с производительностью процессора, — это те, которые требуют сложных математических вычислений.
Например:
* Обработка **звука** или **изображений**.
* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета,
обработка обычно требует проведения расчётов по всем пикселям сразу.
* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов".
Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить.
* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание.
Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется
специальный процессор для создания и / или использования построенных таким образом моделей.
* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения / цвета, обработка этого обычно требует вычисления чего-то на этих пикселях, все одновременно.
* **Машинное обучение**: оно обычно требует множества умножений "матриц" и "векторов". Представьте огромную таблицу с числами в Экселе и умножение всех их вместе одновременно.
* **Глубокое обучение**: это подполе Машинного обучения, так что, то же самое применимо. Просто здесь не одна таблица чисел для умножения, а огромное их множество, и в многих случаях используется специальный процессор для создания и / или использования этих моделей.
### Конкурентность + параллелизм: Веб + машинное обучение
### Конкурентность + параллелизм: Веб + Машинное обучение
**FastAPI** предоставляет возможности конкуретного программирования,
которое очень распространено в веб-разработке (именно этим славится NodeJS).
С **FastAPI** вы можете использовать преимуществ конкурентности, который очень распространён в веб-разработке (та же главная привлекательность NodeJS).
Кроме того вы сможете использовать все преимущества параллелизма и
<abbr title="multiprocessing">многопроцессорности</abbr> (когда несколько процессов работают параллельно),
если рабочая нагрузка предполагает **ограничение по процессору**,
как, например, в системах машинного обучения. <!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_329-->
Но вы также можете использовать преимущества параллелизма и многопроцессорности (имеющих несколько процессов, работающих параллельно) для рабочих нагрузок, зависимых от **производительности процессора**, таких как в системах Машинного обучения.
Необходимо также отметить, что Python является главным языком в области
<abbr title="наука о данных (data science)">**дата-сайенс**</abbr>,
машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI
отличным вариантом (среди многих других) для разработки веб-API и приложений
в области дата-сайенс / машинного обучения.
Это, плюс простой факт, что Python является главным языком для **Дата-сайенс**, Машинного обучения и особенно глубокого обучения, делают FastAPI очень хорошим выбором для Дата-сайенс / Машинного обучения веб-API и приложений (среди многих других).
Как добиться такого параллелизма в эксплуатации описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}.
Чтобы увидеть, как достичь этого параллелизма в эксплуатации, смотрите раздел о [Развёртывании](deployment/index.md){.internal-link target=_blank}.
## `async` и `await`
В современных версиях Python разработка асинхронного кода реализована очень интуитивно.
Он выглядит как обычный "последовательный" код и самостоятельно выполняет "ожидание", когда это необходимо.
Современные версии Python предлагают очень удобный способ создания асинхронного кода. Это делает код похожим на обычный "последовательный" код и автоматически вставляет "ожидание", когда это необходимо.
Если некая операция требует ожидания перед тем, как вернуть результат, и
поддерживает современные возможности Python, код можно написать следующим образом:
Если есть операция, которая требует ожидания перед тем, как результаты будут готовы, и она поддерживает эти новые возможности Python, вы можете написать её как:
```Python
burgers = await get_burgers(2)
```
Главное здесь слово `await`. Оно сообщает интерпретатору, что необходимо дождаться ⏸
пока `get_burgers(2)` закончит свои дела 🕙, и только после этого сохранить результат в `burgers`.
Зная это, Python может пока переключиться на выполнение других задач 🔀 ⏯
(например получение следующего запроса).<!--http://new.gramota.ru/spravka/buro/search-answer?s=296614-->
Ключ здесь — `await`. Он сообщает Python, что нужно дождаться ⏸, пока `get_burgers(2)` завершит своё выполнение 🕙, прежде чем сохранить результаты в `burgers`. Основываясь на этом, Python сможет временно перейти к выполнению других задач 🔀 ⏯ (например, получение нового запроса).
Чтобы ключевое слово `await` сработало, оно должно находиться внутри функции,
которая поддерживает асинхронность. Для этого вам просто нужно объявить её как `async def`:
Чтобы `await` работал, он должен находиться внутри функции, поддерживающей асинхронность. Для этого просто объявите её с помощью `async def`:
```Python hl_lines="1"
async def get_burgers(number: int):
# Готовим бургеры по специальному асинхронному рецепту
# Выполняем некоторые асинхронные действия, чтобы создать бургеры
return burgers
```
@ -355,26 +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`, вам нужно <abbr title="await">"ожидать"</abbr> её.
Поэтому такое не сработает:
Когда вы хотите вызвать функцию `async def`, вы должны "ожидать" её. Поэтому, это не сработает:
```Python
# Это не заработает, поскольку get_burgers объявлена с использованием async def
# Это не сработает, потому что get_burgers была определена с использованием: async def
burgers = get_burgers(2)
```
---
Если сторонняя библиотека требует вызывать её с ключевым словом `await`,
необходимо писать *функции обработки пути* с использованием `async def`, например:
Так, если вы используете библиотеку, которая сообщает вам, что можете вызвать её с помощью `await`, вам нужно создать *функции обработки пути*, которые её используют с `async def`, как в:
```Python hl_lines="2-3"
@app.get('/burgers')
@ -383,129 +349,96 @@ async def read_burgers():
return burgers
```
### Технические подробности
### Более технические подробности
Как вы могли заметить, `await` может применяться только в функциях, объявленных с использованием `async def`.
Как вы могли заметить, `await` можно использовать только внутри функций, определённых с помощью `async def`.
<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_128-->
Но выполнение такой функции необходимо "ожидать" с помощью `await`.
Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`.
Но в то же время функции, определённые с помощью `async def`, должны быть "ожиданы". Поэтому, функции с `async def` могут вызываться только внутри функций, определённых с `async def`.
Но как же тогда появилась первая <abbr title="или яйцо?🤔">курица</abbr>? В смысле... как нам вызвать первую асинхронную функцию?
Так что как же насчёт яйца и курицы, как вызвать первую `async` функцию?
При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*,
и дальше с этим разберётся FastAPI.
Если вы работаете с **FastAPI**, вы можете не заботиться об этом, потому что эта "первая" функция будет вашей *функцией обработки пути*, и FastAPI будет знать, как сделать всё правильно.
Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI.
Но если вы хотите использовать `async` / `await` без FastAPI, вы тоже можете это сделать.
### Пишите свой асинхронный код
Starlette (и **FastAPI**) основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, что делает их совместимыми как со стандартной библиотекой <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> в Python, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.<!--http://new.gramota.ru/spravka/buro/search-answer?s=285295-->
Starlette (и **FastAPI**) базируются на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, что делает их совместимыми как со стандартной библиотекой Python <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a>, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
В частности, вы можете напрямую использовать <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> для ваших продвинутых случаев использования конкурентности, которые требуют более сложных паттернов в вашем собственном коде.
В частности, вы можете напрямую использовать <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> в тех проектах, где требуется более сложная логика работы с конкурентностью.
И даже если вы не использовали FastAPI, вы всё равно могли бы написать свои собственные асинхронные приложения с помощью <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, чтобы они были высоко совместимыми и получали все его преимущества (например, структурированная конкурентность).
Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, чтобы они были максимально совместимыми и получали его преимущества (например *структурную конкурентность*).
Я создал другую библиотеку поверх AnyIO, как тонкий слой поверх него, чтобы немного улучшить аннотации типов и получить лучшую **автодополнения**, **ошибки в строках кода** и т. д. Она также имеет дружный вводный материал и учебник, который поможет вам **понять** и писать **свой собственный асинхронный код**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. Он будет особенно полезен, если вам нужно **сочетать асинхронный код с обычным** (блокирующим/синхронным) кодом.
### Другие виды асинхронного программирования
### Другие формы асинхронного кода
Стиль написания кода с `async` и `await` появился в языке Python относительно недавно.
Этот стиль использования `async` и `await` относительно новый в языке.
Но он сильно облегчает работу с асинхронным кодом.
Но он сильно упрощает работу с асинхронным кодом.
Ровно такой же синтаксис (ну или почти такой же) недавно был включён в современные версии JavaScript (в браузере и NodeJS).
Этот же синтаксис (или почти идентичный) также был недавно включен в современные версии JavaScript (в браузерах и NodeJS).
До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать.
Но раньше обработка асинхронного кода была намного более сложной и трудной.
В предыдущих версиях Python для этого использовались потоки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Но такой код намного сложнее понимать, отлаживать и мысленно представлять.
В предыдущих версиях Python, вы могли использовать потоки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Но код в этом случае был намного сложнее для понимания, отладки и осмысления.
Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели
<abbr title="callback">"обратные вызовы"</abbr>. Что выливалось в
<a href="http://callbackhell.ru/" class="external-link" target="_blank">ад обратных вызовов</a>.
В предыдущих версиях NodeJS / Javascript для браузеров, для этого использовались "обратные вызовы". Что приводило к <a href="http://callbackhell.com/" class="external-link" target="_blank">аду обратных вызовов</a>.
## Сопрограммы
<abbr title="coroutine">**Корути́на**</abbr> (или же сопрограмма) — это крутое словечко для именования той сущности,
которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию,
но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`.
**Сопрограмма** — это просто очень крутое слово для обозначения того, что возвращается функцией `async def`. Python знает, что это что-то вроде функции, которую можно запустить, и которая закончится в какой-то момент, но которая может быть также поставлена на паузу ⏸, когда внутри встречается `await`.
Всю функциональность асинхронного программирования с использованием `async` и `await`
часто обобщают словом "корутины". Они аналогичны <abbr title="Goroutines">"горутинам"</abbr>, ключевой особенности
языка Go.
Но вся эта функциональность использования асинхронного кода с `async` и `await` часто суммируется как использование "сопрограмм". Это сопоставимо с основной ключевой особенностью Go, "Горутинами".
## Заключение
В самом начале была такая фраза:
Давайте увидим ту же фразу сверху:
> Современные версии Python поддерживают разработку так называемого
**"асинхронного кода"** посредством написания **"сопрограмм"** с использованием
синтаксиса **`async` и `await`**.
> Современные версии Python поддерживают **"асинхронный код"** с использованием чего-то, называемого **"сопрограммами"**, с синтаксисом **`async` и `await`**.
Теперь всё должно звучать понятнее. ✨
Теперь это должно звучать более понятно. ✨
На этом основана работа FastAPI (посредством Starlette), и именно это
обеспечивает его высокую производительность.
Всё это то, на чём работает FastAPI (через Starlette) и что делает его настолько невероятно производительным.
## Очень технические подробности
/// warning
/// warning | Предупреждение
Этот раздел читать не обязательно.
Вы, вероятно, можете это пропустить.
Здесь приводятся подробности внутреннего устройства **FastAPI**.
Это очень технические подробности того, как **FastAPI** работает внутри.
Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.)
и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`,
читайте дальше.
Если у вас есть технические знания (сопрограммы, потоки, блокировки и т. д.) и вы интересуетесь тем, как FastAPI обрабатывает `async def` в отличие от обычного `def`, продолжайте.
///
### Функции обработки пути
Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def`
вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем
<abbr title="threadpool">пуле потоков</abbr>, а не напрямую (это бы заблокировало сервер).
Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def` вместо `async def`, она выполняется во внешнем пуле потоков, который затем ожидается, вместо того, чтобы быть вызванной напрямую (так как это заблокировало бы сервер).
Если ранее вы использовали другой асинхронный фреймворк, который работает иначе,
и привыкли объявлять простые вычислительные *функции* через `def` ради
незначительного прироста скорости (порядка 100 наносекунд), обратите внимание,
что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит
`async def`, если только *функция обработки пути* не использует код, приводящий
к блокировке <abbr title="Ввод/вывод: чтение и запись на диск, сетевые соединения.">I/O</abbr>.
<!--Уточнить: Не использовать async def, если код приводит к блокировке IO?-->
Если вы приходите из другого асинхронного фреймворка, который работает не так, как описано выше, и вы привыкли определять тривиальные вычислительные *функции обработки пути* с простым `def` для маленького прироста производительности (около 100 наносекунд), обратите внимание, что в **FastAPI** эффект будет полностью противоположным. В этих случаях лучше использовать `async def`, если только ваши *функции обработки пути* не используют код, который выполняет блокирующий <abbr title="Ввод/вывод: чтение или запись на диск, сетевые коммуникации.">I/O</abbr>.
<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_285-->
Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](index.md#_11){.internal-link target=_blank}
другого фреймворка (или хотя бы на уровне с ним).
Тем не менее, в обеих ситуациях есть вероятность, что **FastAPI** [всё еще будет быстрее](index.md#performance){.internal-link target=_blank}, чем (или, по крайней мере, сравним с) ваш предыдущий фреймворк.
### Зависимости
То же относится к зависимостям. Если это обычная функция `def`, а не `async def`,
она запускается во внешнем пуле потоков.
Тоже самое относится к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость является стандартной функцией `def` вместо `async def`, она запускается во внешнем пуле потоков.
### Подзависимости
Вы можете объявить множество ссылающихся друг на друга зависимостей и подзависимостей
(в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`,
другие обычным образом через `def`, и такая схема вполне работоспособна. Функции,
объявленные с помощью `def` будут запускаться на внешнем потоке (из пула),
а не с помощью `await`.
Вы можете иметь множество зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}, требующих друг друга (как параметры определения функций), некоторые из них могут быть созданы с помощью `async def`, а некоторые с обычным `def`. Это всё равно будет работать, и те, которые созданы с обычным `def`, будут вызываться на внешнем потоке (из пула), а не "ожидаться".
### Другие служебные функции
Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять
с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы
их запускаете.
Любая другая служебная функция, которую вы вызываете напрямую, может быть создана с обычным `def` или `async def`, и FastAPI не будет влиять на то, как вы её вызываете.
Этим они отличаются от функций, которые FastAPI вызывает самостоятельно:
*функции обработки пути* и зависимости.
Это в отличие от функций, которые FastAPI вызывает для вас: *функции обработки пути* и зависимости.
Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую
(как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с
помощью `async def`, её вызов должен осуществляться с ожиданием через `await`.
Если ваша служебная функция — это обычная функция с `def`, она будет вызвана напрямую (как вы пишите это в коде), не в пуле потоков, если функция создана с `async def`, тогда вам нужно `await` для этой функции, когда вы вызываете её в вашем коде.
---
<!--http://new.gramota.ru/spravka/buro/search-answer?s=299749-->
Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали.
Еще раз повторим, что все эти технические подробности вероятно будут полезны, если вы специально искали их.
В противном случае просто ознакомьтесь с основными принципами в разделе выше: <a href="#_1">Нет времени?</a>.
В противном случае вы должны обратиться к руководящим принципам из раздела выше: <a href="#in-a-hurry">В спешке?</a>.

45
docs/ru/docs/benchmarks.md

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

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

@ -1,163 +1,157 @@
# Запуск сервера вручную - Uvicorn
# Запуск сервера вручную
Для запуска приложения **FastAPI** на удалённой серверной машине вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**.
## Использование команды `fastapi run`
Существует три наиболее распространённые альтернативы:
Коротко говоря, используйте `fastapi run`, чтобы запустить ваше приложение FastAPI:
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>: высокопроизводительный ASGI сервер.
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: ASGI сервер, помимо прочего поддерживающий HTTP/2 и Trio.
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: ASGI сервер, созданный для Django Channels.
## Сервер как машина и сервер как программа
В этих терминах есть некоторые различия и вам следует запомнить их. 💡
Слово "**сервер**" чаще всего используется в двух контекстах:
<div class="termy">
- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина).
- программа, запущенная на таком компьютере (например, Uvicorn).
```console
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
Просто запомните, если вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов.
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Запуск серверной программы для продакшена 🚀
Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором вы запускаете программы.
Поиск структуры файлов пакета из директорий
с файлами <font color="#3465A4">__init__.py</font>
Импорт из <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
## Установка программного сервера
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
Вы можете установить сервер, совместимый с протоколом ASGI, так:
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Импорт объект приложения FastAPI из модуля при помощи
следующего кода:
//// tab | Uvicorn
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, очень быстрый ASGI сервер, основанный на библиотеках uvloop и httptools.
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Использование строки импорта: <font color="#3465A4">main:app</font>
<div class="termy">
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Сервер запущен на <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Документация доступна по адресу <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
```console
$ pip install "uvicorn[standard]"
Логи:
---> 100%
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Запущен серверный процесс <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Ожидание запуска приложения.
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Запуск приложения завершён.
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn работает на <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>нажмите CTRL+C
для завершения<b>)</b>
```
</div>
/// tip | Подсказка
С опцией `standard`, Uvicorn будет устанавливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями.
Это подойдёт для большинства случаев. 😎
В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ.
Вы можете использовать эту команду, чтобы например запустить ваше **FastAPI**-приложение в контейнере, на сервере и т.д.
///
////
## ASGI-сервера
//// tab | Hypercorn
Давайте углубимся в детали.
* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, ASGI сервер, поддерживающий протокол HTTP/2.
<div class="termy">
FastAPI использует стандарт для создания Python веб-фреймворков и серверов, называемый <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr>. FastAPI — это ASGI веб-фреймворк.
```console
$ pip install hypercorn
---> 100%
```
Основное, что вам нужно для запуска **FastAPI** приложения (или любого другого ASGI приложения) на удалённой серверной машине — это программа ASGI сервера, такая как **Uvicorn**, именно она используется по умолчанию в команде `fastapi`.
</div>
Среди альтернатив:
...или какой-либо другой ASGI сервер.
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>: высокопроизводительный ASGI сервер.
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: ASGI сервер, поддерживающий HTTP/2 и Trio среди прочего.
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: ASGI сервер, созданный для Django Channels.
* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a>: HTTP сервер на Rust для Python приложений.
* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a>: лёгкая и многофункциональная среда выполнения веб-приложений от NGINX.
////
## Сервер как машина и сервер как программа
## Запуск серверной программы
Есть небольшая деталь о названиях, которую нужно иметь в виду. 💡
Затем запустите ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`:
Слово "**сервер**" обычно используется для обозначения как удалённого/облачного компьютера (физическая или виртуальная машина), так и программы, запущенной на этой машине (например, Uvicorn).
//// tab | Uvicorn
Просто помните, что когда вы видите "сервер" в общем случае, это может обозначать что-то из этих двух вещей.
<div class="termy">
Когда речь идёт о удалённой машине, её часто называют **сервер**, но также **машина**, **ВМ** (виртуальная машина), **нода**. Все они относятся к каким-то удалённым машинам, обычно под управлением Linux, на которых вы запускаете программы.
```console
$ uvicorn main:app --host 0.0.0.0 --port 80
## Установка программы сервера
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
```
Когда вы устанавливаете FastAPI, он поставляется с сервером для продакшена, Uvicorn, и вы можете запустить его с помощью команды `fastapi run`.
</div>
Но вы также можете установить ASGI-сервер вручную.
////
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и тогда можете установить серверное приложение.
//// tab | Hypercorn
Например, чтобы установить Uvicorn:
<div class="termy">
```console
$ hypercorn main:app --bind 0.0.0.0:80
$ pip install "uvicorn[standard]"
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
---> 100%
```
</div>
////
Аналогичный процесс будет применен для любой другой программы ASGI сервера.
/// warning | Предупреждение
/// tip | Подсказка
Не забудьте удалить опцию `--reload`, если ранее пользовались ею.
Добавив `standard`, Uvicorn установит и будет использовать некоторые рекомендованные дополнительные зависимости.
Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности.
Среди них `uvloop`, высокопроизводительная замена для `asyncio`, которая предоставляет значительное увеличение производительности при использовании асинхронности.
Она сильно помогает во время **разработки**, но **не следует** использовать её при **реальной работе** приложения.
Когда вы устанавливаете FastAPI чем-то вроде `pip install "fastapi[standard]"`, вы также получаете `uvicorn[standard]`.
///
## Hypercorn с Trio
Starlette и **FastAPI** основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, которая делает их совместимыми как с <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> - стандартной библиотекой Python, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a>, высокопроизводительной заменой `asyncio`.
## Запуск программы сервера
Но если вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨
### Установка Hypercorn с Trio
Для начала, вам нужно установить Hypercorn с поддержкой Trio:
Если вы установили ASGI-сервер вручную, вам обычно нужно будет передать строку импорта в специальном формате, чтобы он импортировал ваше FastAPI-приложение:
<div class="termy">
```console
$ pip install "hypercorn[trio]"
---> 100%
$ uvicorn main:app --host 0.0.0.0 --port 80
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
```
</div>
### Запуск с Trio
/// note | Примечание
Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`:
Команда `uvicorn main:app` относится к:
<div class="termy">
* `main`: файл `main.py` (Python "модуль").
* `app`: объект, созданный внутри `main.py` строкой `app = FastAPI()`.
```console
$ hypercorn main:app --worker-class trio
Это эквивалентно:
```Python
from main import app
```
</div>
///
Каждая альтернативная программа ASGI сервера будет иметь аналогичную команду, вы можете узнать больше в их соответствующей документации.
/// warning | Предупреждение
Hypercorn, в свою очередь, запустит ваше приложение использующее Trio.
Uvicorn и другие серверы поддерживают опцию `--reload`, которая полезна во время разработки.
Таким образом, вы сможете использовать Trio в своём приложении. Но лучше использовать AnyIO, для сохранения совместимости и с Trio, и с asyncio. 🎉
Опция `--reload` потребляет значительно больше ресурсов, более нестабильна и т.д.
Она очень полезна во время **разработки**, но **не следует** использовать её в **продакшене**.
///
## Концепции развёртывания
В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`).
В этих примерах выполняется запуск серверной программы (например, Uvicorn), создавая **один процесс**, который слушает на всех IP (`0.0.0.0`) на предустановленном порту (например, `80`).
Это основная идея. Но возможно, вы озаботитесь добавлением дополнительных возможностей, таких как:
Это базовая идея. Но, вероятно, вам захочется позаботиться о некоторых дополнительных вещах, таких как:
* Использование более безопасного протокола HTTPS
* Настройки запуска приложения
* Перезагрузка приложения
* Запуск нескольких экземпляров приложения
* Управление памятью
* Использование перечисленных функций перед запуском приложения.
* Безопасность - HTTPS
* Запуск при старте системы
* Перезапуски
* Репликация (число запущенных процессов)
* Память
* Предыдущие шаги перед стартом
Я расскажу вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀
Я расскажу вам больше о каждой из этих концепций, как их рассматривать и приведу конкретные примеры стратегий для их решения в следующих главах. 🚀

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

@ -1,261 +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".
Там вы можете выбрать "Releases only".
С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.
Таким образом, вы будете получать уведомления (на ваш email) каждый раз, когда будет выходить новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми функциями.
## Связаться с автором
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себястьян Рамирез / `tiangolo`)</a>, автором FastAPI.
Вы можете связаться со мной <a href="https://tiangolo.com" class="external-link" target="_blank">(Себастьян Рамирес / `tiangolo`)</a>, автором.
Вы можете:
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Подписаться на меня на **GitHub**</a>.
* Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
* Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
* Ознакомиться с другими проектами с открытым исходным кодом, которые я создал и которые могут быть полезны вам.
* Подписывайтесь на меня, чтобы узнавать о моих новых проектах с открытым исходным кодом.
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Подписаться на меня в **Twitter**</a> или в <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>.
* Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это).
* Получать уведомления, когда я делаю объявления и представляю новые инструменты.
* Вы также можете <a href="https://twitter.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в Twitter</a> (это отдельный аккаунт).
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **Linkedin**</a>.
* Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷‍♂).
* Читать, что я пишу (или подписаться на меня) в <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или в <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
* Читать другие идеи, статьи и читать об инструментах созданных мной.
* Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое.
* Расскажите мне, как вы используете FastAPI (мне нравится об этом слышать).
* Узнавать о моих объявлениях или новых инструментах.
* Вы также можете <a href="https://twitter.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в Twitter</a> (отдельный аккаунт).
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Следите за мной на **LinkedIn**</a>.
* Узнавайте о моих объявлениях или новых инструментах (хотя я чаще использую Twitter 🤷‍♂).
* Читайте, что я пишу (или подписывайтесь на меня) на <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или на <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
* Читайте другие идеи, статьи и узнавайте о созданных мной инструментах.
* Подпишитесь на меня, чтобы знать, когда я публикую что-то новое.
## Оставить сообщение в Twitter о **FastAPI**
## Написать твит о **FastAPI**
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в Twitter о **FastAPI**</a> и позвольте мне и другим узнать - почему он Вам нравится. 🎉
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Напишите твит о **FastAPI**</a>, и позвольте мне и другим узнать, почему он вам нравится. 🎉
Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п.
Мне нравится слышать о том, как используется **FastAPI**, что вам в нём понравилось, в каком проекте/компании вы его используете и т.п.
## Оставить голос за FastAPI
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Голосуйте за **FastAPI** в Slant</a>.
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>.
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, как Вы используете **FastAPI** на StackShare</a>.
* <a href="https://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>.
## Помочь другим с их проблемами на GitHub
## Помогите другим с вопросами на GitHub
Вы можете посмотреть, какие <a href="https://github.com/fastapi/fastapi/issues" class="external-link" target="_blank">проблемы</a> испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓
Вы можете попытаться помочь другим с их вопросами в:
Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. 🎉
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">Обсуждения GitHub</a>
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">Проблемы GitHub</a>
Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗
Во многих случаях вы уже можете знать ответы на эти вопросы. 🤓
Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
Если вы будете помогать многим людям с их вопросами, вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉
Просто помните, самое важное: старайтесь быть добрыми. Люди приходят со своими разочарованиями и часто не задают вопросы так, как следовало бы, но старайтесь быть как можно добрее. 🤗
Идея сообщества **FastAPI** заключается в том, чтобы быть добрыми и гостеприимными. В то же время, не терпите издевательства или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге.
---
Как помочь другим с их проблемами:
Вот как помочь другим с вопросами (в обсуждениях или проблемах):
### Понять вопрос
* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего.
* Убедитесь, что вы поняли, какова **цель** и заслуга человека, задающего вопрос.
* Затем убедитесь, что вопрос (в большинстве случаев это вопрос) **ясен**.
* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
* Во многих случаях вопрос касается выдуманного решения пользователя, но существует **лучшее** решение. Если вы сможете понять основную проблему и контекст лучше, вы сможете предложить альтернативное **решение**.
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
* Если вопрос вам не ясен, попросите больше **деталей**.
* Ежели вопрос Вам непонятен, запросите больше **деталей**.
### Воспроизведите проблему
### Воспроизвести проблему
В большинстве случаев и вопросов что-то связано с **исходным кодом** пользователя.
В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего.
Во многих случаях они скопируют только фрагмент кода, но этого недостаточно для того, чтобы **воспроизвести проблему**.
И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**.
* Вы можете попросить их предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный, воспроизводимый пример</a>, который вы можете **копировать и вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, которое они наблюдают, или чтобы лучше понять их контекст.
* Попросите предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая.
* Если вы чувствуете щедрость, вы можете попробовать **создать пример** самостоятельно, только на основе описания проблемы. Просто помните, что это может занять много времени и, возможно, лучше сначала попросить их прояснить проблему.
* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
### Предложите решения
### Предложить решение
* После того, как вы смогли понять вопрос, вы можете предложить возможный **ответ**.
* После того как Вы поняли вопрос, Вы можете дать **ответ**.
* Во многих случаях лучше понять их **основную проблему или контекст**, так как может быть лучшее решение, чем то, которое они пытаются использовать.
* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать.
### Попросить закрыть
### Попросить закрыть проблему
Если они ответят, с большой вероятностью вы решили их проблему, поздравляю, **вы герой**! 🦸
Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
* Теперь, если это решило их проблему, вы можете попросить их:
* В таком случае, если вопрос решён, попросите **закрыть проблему**.
* В обсуждениях на GitHub: отметить комментарий как **ответ**.
* В проблемах на 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>. 👀
Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы.
Если вы выберете "Watching" вместо "Releases only", вы получите уведомления, когда кто-то создаёт новую проблему или задаёт вопрос. Вы также можете уточнить, что хотите получать уведомления только о новых проблемах, обсуждениях или PR и т.д.
Тогда Вы можете попробовать решить эту проблему.
Затем вы можете попытаться помочь решить эти вопросы.
## Запросить помощь с решением проблемы
## Задавать вопросы
Вы можете <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">создать новый запрос с просьбой о помощи</a> в репозитории на GitHub, например:
Вы можете <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">создать новый вопрос</a> в репозитории GitHub, чтобы:
* Задать **вопрос** или попросить помощи в решении **проблемы**.
* Предложить новое **улучшение**.
* Задать **вопрос** или попросить о **проблеме**.
* Предложить новую **функцию**.
**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉
**Примечание**: если вы это сделаете, я попрошу вас также помочь другим. 😉
## Проверять пул-реквесты
## Проверка пул-реквестов
Вы можете помочь мне проверять пул-реквесты других участников.
Вы можете помочь мне с проверкой пул-реквестов от других участников.
И повторюсь, постарайтесь быть доброжелательным. 🤗
Снова повторяю, пожалуйста, старайтесь быть добрыми. 🤗
---
О том, что нужно иметь в виду при проверке пул-реквестов:
Вот что нужно иметь в виду и как проверять пул-реквесты:
### Понять проблему
* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение.
* Во-первых, убедитесь, что вы **поняли проблему**, которую пытается решить пул-реквест. Возможно, это обсуждается в обсуждениях GitHub или проблеме.
* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт.
* Также существует вероятность, что пул-реквест не требуется, поскольку проблему можно решить **по-другому**. Затем вы можете предложить или спросить об этом.
### Не переживайте о стиле
### Не беспокойтесь о стиле
* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную.
* Не слишком беспокойтесь о таких вещах, как стиль сообщений о коммитах, я буду принимать и сливать с учетом мануальной настройки.
* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты.
* Также не беспокойтесь о правилах стиля, уже есть автоматизированные инструменты, которые это проверяют.
И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями.
И если всё же потребуются другие правила стиля или согласованность, я попрошу об этом непосредственно, или добавлю нужные изменения сам.
### Проверить код
### Проверка кода
* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу.
* Проверьте и прочтите код, посмотрев, имеет ли он смысл, **запустите его локально** и посмотрите, действительно ли он решает задачу.
* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код.
* Затем **комментируйте**, что вы это сделали, так я узнаю, что вы действительно проверили код.
/// info | Информация
К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений.
К сожалению, я не могу просто доверять PR, у которых имеется несколько положительных отзывов.
Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅
Бывали случаи, когда PR имели 3, 5 или больше положительных отзывов, вероятно из-за привлекательного описания, но когда я проверял такие PR, они оказывались некорректными, имели ошибку или не решали заявленную проблему. 😅
Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓
Поэтому действительно важно, чтобы вы прочли и исполнили код, и сообщили мне в комментариях, что вы это сделали. 🤓
///
* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах.
* Если PR можно упростить каким-то образом, вы можете попросить об этом, но не стоит быть слишком придирчивыми, может быть множество субъективных точек зрения (и у меня также будет своя 🙈), поэтому лучше сосредоточиться на фундаментальных вещах.
### Тестировать
### Тестирование
* Помогите мне проверить, что у пул-реквеста есть **тесты**.
* Помогите мне проверить, что у PR есть **тесты**.
* Проверьте, что тесты **падали** до пул-реквеста. 🚨
* Проверьте, что тесты **падали** до PR. 🚨
* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅
* Затем проверьте, что тесты **не валятся** после PR. ✅
* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим.
* Многие PR не имеют тестов, вы можете **напомнить** им об их добавлении или даже **предложить** свои тесты. Это одна из тех вещей, которые отнимают больше всего времени, и вы можете существенно помочь с ними.
* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓
* Затем также укажите в комментариях, что вы проверили, так я узнаю, что вы это сделали. 🤓
## Создать пул-реквест
## Создайте пул-реквест
Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например:
Вы можете [внести вклад](contributing.md){.internal-link target=_blank} в исходный код с помощью Pull Requests, например:
* Исправить опечатку, которую Вы нашли в документации.
* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>.
* Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела.
* Помочь с [переводом документации](contributing.md#_8){.internal-link target=_blank} на Ваш язык.
* Вы также можете проверять переводы сделанные другими.
* Предложить новые разделы документации.
* Исправить существующуе проблемы/баги.
* Чтобы исправить ошибку в документации.
* Чтобы поделиться статьей, видео или подкастом, который вы создали или нашли, о FastAPI, <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">редактируя этот файл</a>.
* Убедитесь, что добавили ссылку в начало соответствующего раздела.
* Чтобы помочь [перевести документацию](contributing.md#translations){.internal-link target=_blank} на ваш язык.
* Вы также можете помочь рецензировать переводы, созданные другими.
* Чтобы предложить новые разделы документации.
* Чтобы исправить существующую проблему или баг.
* Убедитесь, что добавили тесты.
* Добавить новую возможность.
* Чтобы добавить новую возможность.
* Убедитесь, что добавили тесты.
* Убедитесь, что добавили документацию, если она необходима.
* Убедитесь, что добавили документацию, если это актуально.
## Помочь поддерживать FastAPI
## Помогите поддерживать FastAPI
Помогите мне поддерживать **FastAPI**! 🤓
Помогите мне поддержать **FastAPI**! 🤓
Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать.
Есть много работы, и большую часть из неё **ВЫ** можете сделать.
Основные задачи, которые Вы можете выполнить прямо сейчас:
Основные задачи, которые вы можете сделать прямо сейчас:
* [Помочь другим с их проблемами на GitHub](#github_1){.internal-link target=_blank} (смотрите вышестоящую секцию).
* [Проверить пул-реквесты](#-){.internal-link target=_blank} (смотрите вышестоящую секцию).
* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (см. раздел выше).
* [Проверка пул-реквестов](#review-pull-requests){.internal-link target=_blank} (см. раздел выше).
Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI.
Эти две задачи **занимают больше всего времени**. Это основная работа по поддержке FastAPI.
Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
Если вы можете помочь мне с этим, **вы помогаете поддерживать FastAPI**, обеспечивая его дальнейшее **развитие быстрее и лучше**. 🚀
## Подключиться к чату
## Присоединяйтесь к чату
Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank"> чату в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI.
Присоединяйтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">чат-серверу Discord</a> 👥 и общайтесь с другими в сообществе FastAPI.
/// tip | Подсказка
Вопросы по проблемам с фреймворком лучше задавать в <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#_3){.internal-link target=_blank}.
Задавайте вопросы в <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">Обсуждениях GitHub</a>, так у вас будет намного больше шансов получить помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}.
Используйте этот чат только для бесед на отвлечённые темы.
Используйте чат только для других общих разговоров.
///
### Не использовать чаты для вопросов
### Не используйте чат для вопросов
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
Помните, что в чатах легче задаются вопросы, которые носят слишком общий характер и на них труднее найти ответы, поэтому вы можете не получить ответы.
В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅
На GitHub шаблон поможет вам задать правильный вопрос, чтобы вы могли легче получить хороший ответ, или даже решить проблему самостоятельно до того, как вы зададите его. На GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это занимает некоторое время. Я лично не могу сделать то же самое с системами чатов. 😅
Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#_3){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
Разговоры в чатах также не так легко доступны для поиска, как в GitHub, поэтому вопросы и ответы могут затеряться. И только те, что на GitHub, учитываются в получении статуса [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что вы, скорее всего, получите больше внимания на GitHub.
С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄
С другой стороны, в чаты подключены тысячи пользователей, поэтому есть большая вероятность, что вы найдёте там кого-то, с кем могли бы поговорить почти в любое время. 😄
## Спонсировать автора
Вы также можете оказать мне финансовую поддержку посредством <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">спонсорства через GitHub</a>.
Там можно просто купить мне кофе ☕️ в знак благодарности. 😄
А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉
## Спонсировать инструменты, на которых зиждется мощь FastAPI
Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic.
Им тоже можно оказать спонсорскую поддержку:
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
Если ваш **продукт/компания** зависит от **FastAPI** или связана с ним и вы хотите достичь его пользователей, вы можете спонсировать автора (меня) через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">спонсоров GitHub</a>. В зависимости от уровня, вы можете получить некоторые дополнительные преимущества, такие как награда в документации. 🎁
---
Благодарствую! 🚀
Спасибо! 🚀

266
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>Готовый к внедрению высокопроизводительный фреймворк, простой в изучении и разработке.</em>
<em>Фреймворк FastAPI: высокая производительность, простота освоения, быстрая разработка, готов к использованию в производстве</em>
</p>
<p align="center">
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
@ -33,20 +33,20 @@
---
FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API используя Python, в основе которого лежит стандартная аннотация типов Python.
FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API, использующий Python и стандартные аннотации типов Python.
Ключевые особенности:
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков Python](#_10).
* **Быстрота разработки**: Увеличьте скорость разработки примерно на 200–300%. *
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
* **Интуитивно понятный**: Отличная поддержка редактора. <abbr title="также известное как автозаполнение, автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
* **Лёгкость**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
* **Краткость**: Сведите к минимуму дублирование кода. Каждый объявленный параметр - определяет несколько функций. Меньше ошибок.
* **Надежность**: Получите готовый к работе код. С автоматической интерактивной документацией.
* **На основе стандартов**: Основан на открытых стандартах 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>.
* **Быстрый**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков на Python](#performance).
* **Быстрая разработка**: Повышает скорость разработки примерно на 200–300%. *
* **Меньше ошибок**: Уменьшает количество ошибок, вносимых разработчиком, на 40%. *
* **Интуитивно понятный**: Отличная поддержка редактора. <abbr title="также известны как автодополнение, IntelliSense">Автозаполнение</abbr> везде. Меньше времени на отладку.
* **Простой**: Разработан для простоты использования и изучения. Меньше времени на чтение документации.
* **Краткий**: Сведите к минимуму дублирование кода. Множество функций из каждого объявления параметра. Меньше ошибок.
* **Надежный**: Получите готовый к производству код. С автоматической интерактивной документацией.
* **На основе стандартов**: Основан на (и полностью совместим с) открытых стандартах 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,88 +67,86 @@ 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> podcast host</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> ведущий подкаста</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> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> создатель</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания 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>
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> основатели - <a href="https://spacy.io" target="_blank">spaCy</a> создатели</strong> <a href="https://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>
---
## **Typer**, интерфейс командной строки для FastAPI
"_Если кто-то хочет создать производственный Python API, я бы очень рекомендовал **FastAPI**. Он **замечательно спроектирован**, **прост в использовании** и **очень масштабируем**, он стал **ключевым компонентом** в нашей стратегии разработки API. Благодаря нему автоматизация и сервисы, такие как наш Виртуальный Инженер TAC, стали возможными._"
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
Если вы создаете приложение <abbr title="Интерфейс командной строки">CLI</abbr> для использования в терминале вместо веб-API, ознакомьтесь с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
**Typer** — младший брат FastAPI. И он предназначен для использования в качестве **интерфейса командной строки для FastAPI**. ⌨️ 🚀
---
## Зависимости
## **Typer**, FastAPI для CLI
FastAPI стоит на плечах гигантов:
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> для части связанной с вебом.
* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> для части связанной с данными.
Если вы создаете приложение для <abbr title="Command Line Interface">CLI</abbr>, используемое в терминале вместо веб API, ознакомьтесь с <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
## Установка
**Typer** — младший брат FastAPI. Он предназначен быть **FastAPI для CLI**. ⌨️ 🚀
<div class="termy">
## Требования
```console
$ pip install fastapi
FastAPI опирается на гигантов:
---> 100%
```
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> для веб-компонентов.
* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> для работы с данными.
</div>
## Установка
Вам также понадобится сервер ASGI для производства, такой как <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> или <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
Создайте и активируйте <a href="https://fastapi.tiangolo.com/virtual-environments/" class="external-link" target="_blank">виртуальное окружение</a>, а затем установите FastAPI:
<div class="termy">
```console
$ pip install "uvicorn[standard]"
$ pip install "fastapi[standard]"
---> 100%
```
</div>
**Примечание**: Убедитесь, что вы обернули `"fastapi[standard]"` в кавычки, чтобы это работало во всех терминалах.
## Пример
### Создание
* Создайте файл `main.py` со следующим содержимым:
Создайте файл `main.py` с:
```Python
from typing import Union
@ -193,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>
@ -204,31 +202,45 @@ async def read_item(item_id: int, q: Union[str, None] = None):
<div class="termy">
```console
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
$ fastapi dev main.py
╭────────── FastAPI CLI - Режим разработки ───────────╮
│ │
│ Сервер работает на: http://127.0.0.1:8000 │
│ │
│ Документация API: http://127.0.0.1:8000/docs │
│ │
│ Запущено в режиме разработки, для использования в │
│ продакшн используйте: │
│ │
│ fastapi run │
│ │
╰─────────────────────────────────────────────────────╯
INFO: Будет следить за изменениями в этих директориях: ['/home/user/code/awesomeapp']
INFO: Uvicorn работает на http://127.0.0.1:8000 (Нажмите CTRL+C чтобы остановить)
INFO: Запущен процесс перезагрузки [2248755] с использованием WatchFiles
INFO: Запущен серверный процесс [2248757]
INFO: Ожидание запуска приложения.
INFO: Запуск приложения завершён.
```
</div>
<details markdown="1">
<summary>О команде <code>uvicorn main:app --reload</code>...</summary>
<summary>О команде <code>fastapi dev main.py</code>...</summary>
Команда `uvicorn main:app` относится к:
Команда `fastapi dev` читает ваш файл `main.py`, определяет **FastAPI** приложение в нем и запускает сервер, используя <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>.
* `main`: файл `main.py` (модуль Python).
* `app`: объект, созданный внутри `main.py` с помощью строки `app = FastAPI()`.
* `--reload`: перезапуск сервера после изменения кода. Делайте это только во время разработки.
По умолчанию, `fastapi dev` запускается с активированной функцией автообновления для локальной разработки.
Вы можете узнать больше об этом в <a href="https://fastapi.tiangolo.com/fastapi-cli/" target="_blank">документации FastAPI CLI</a>.
</details>
### Проверка
Откройте браузер на <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 ответ:
@ -238,10 +250,10 @@ INFO: Application startup complete.
Вы уже создали API, который:
* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.
* И первый и второй _путь_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
* _путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
* _путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
* Получает HTTP-запросы в _пути_ `/` и `/items/{item_id}`.
* Оба _пути_ принимают операции `GET` <em>(также известные как HTTP методы)</em>.
* _Путь_ `/items/{item_id}` принимает _параметр пути_ `item_id`, который должен быть `int`.
* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
### Интерактивная документация по API
@ -259,11 +271,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
@ -295,41 +307,41 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
Сервер должен перезагрузиться автоматически (потому что вы добавили `--reload` к команде `uvicorn` выше).
Сервер `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`:
@ -343,15 +355,15 @@ item_id: int
item: Item
```
... и с этим единственным объявлением вы получаете:
...и с этим единственным объявлением вы получаете:
* Поддержка редактора, в том числе:
* Поддержку редактора, включая:
* Автозавершение.
* Проверка типов.
* Валидация данных:
* Автоматические и четкие ошибки, когда данные недействительны.
* Проверка даже для глубоко вложенных объектов JSON.
* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> входных данных: поступающие из сети в объекты Python с соблюдением типов. Чтение из:
* Проверку типов.
* Валидацию данных:
* Автоматические и чёткие ошибки, когда данные недействительны.
* Валидацию даже для глубоко вложенных объектов JSON.
* <abbr title="также известна как: сериализация, синтаксический анализ, маршаллинг">Преобразование</abbr> входных данных: поступающих из сети в данные и типы Python. Чтение из:
* JSON.
* Параметров пути.
* Параметров запроса.
@ -359,8 +371,8 @@ item: Item
* Заголовков.
* Форм.
* Файлов.
* <abbr title="также известный как: сериализация, синтаксический анализ, маршалинг">Преобразование</abbr> выходных данных: преобразование объектов Python в данные передаваемые по сети интернет (такие как JSON):
* Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т.д.).
* <abbr title="также известна как: сериализация, синтаксический анализ, маршаллинг">Преобразование</abbr> выходных данных: преобразование данных и типов Python в данные сети (например JSON):
* Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т. д.).
* Объекты `datetime`.
* Объекты `UUID`.
* Модели баз данных.
@ -373,28 +385,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}
@ -412,34 +424,40 @@ 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), таких как:
* **Веб-сокеты**
* очень простые тесты на основе HTTPX и `pytest`
* Много дополнительных функций (благодаря Starlette), как например:
* **WebSockets**
* невероятно простые тесты, основанные на HTTPX и `pytest`
* **CORS**
* **Cookie сеансы(сессии)**
* **Сеансы Cookies**
* ...и многое другое.
## Производительность
Независимые тесты 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>.
Чтобы узнать больше об этом, см. раздел <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Бенчмарки</a>.
## Необязательные зависимости
## Зависимости
FastAPI зависит от Pydantic и Starlette.
### Зависимости `standard`
Когда вы устанавливаете FastAPI с использованием `pip install "fastapi[standard]"`, он поставляется с `standard` группой необязательных зависимостей:
Используется Pydantic:
@ -447,20 +465,38 @@ item: Item
Используется Starlette:
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - Обязательно, если вы хотите использовать `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Обязательно, если вы хотите использовать `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Обязательно, если вы хотите использовать конфигурацию шаблона по умолчанию.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Обязательно, если вы хотите поддерживать форму <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">"парсинга"</abbr> с помощью `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Обязательно, для поддержки `SessionMiddleware`.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Обязательно, для поддержки `SchemaGenerator` Starlette (возможно, вам это не нужно с FastAPI).
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Обязательно, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">"парсинг"</abbr> форм, с `request.form()`.
Используется FastAPI:
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - сервер, который загружает и обслуживает ваше приложение. Это включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), нужные для высокопроизводительного сервиса.
* `fastapi-cli[standard]` - для предоставления команды `fastapi`.
* Это включает `fastapi-cloud-cli`, который позволяет развернуть ваше FastAPI приложение на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
### Без `standard` зависимостей
Если вы не хотите включать `standard` необязательные зависимости, вы можете установить FastAPI с `pip install fastapi` вместо `pip install "fastapi[standard]"`.
Используется FastAPI / Starlette:
### Без `fastapi-cloud-cli`
Если вы хотите установить FastAPI с стандартными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
### Дополнительные необязательные зависимости
Существуют некоторые дополнительные зависимости, которые вы можете добавить.
Дополнительные необязательные зависимости Pydantic:
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - для управления настройками.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - для добавления типов, которые могут быть использованы с Pydantic.
Дополнительные необязательные зависимости FastAPI:
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - сервер, который загружает и обслуживает ваше приложение.
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Обязательно, если вы хотите использовать `ORJSONResponse`.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Обязательно, если вы хотите использовать `UJSONResponse`.
Вы можете установить все это с помощью `pip install "fastapi[all]"`.
## Лицензия
Этот проект распространяется на условиях лицензии MIT.

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

@ -1,84 +1,28 @@
# Генераторы проектов - Шаблоны
Чтобы начать работу быстрее, Вы можете использовать "генераторы проектов", в которые включены множество начальных настроек для функций безопасности, баз данных и некоторые <dfn title="также известные как маршруты, URLы, ручки, ">эндпоинты</dfn> API.
В генераторе проектов всегда будут предустановлены какие-то настройки, которые Вам следует обновить и подогнать под свои нужды, но это может быть хорошей отправной точкой для Вашего проекта.
## Full Stack FastAPI PostgreSQL
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
### Full Stack FastAPI PostgreSQL - Особенности
* Полностью интегрирован с **Docker** (основан на Docker).
* Развёртывается в режиме Docker Swarm.
* Интегрирован с **Docker Compose** и оптимизирован для локальной разработки.
* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
* Бэкенд построен на фреймворке <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a>:
* **Быстрый**: Высокопроизводительный, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic).
* **Интуитивно понятный**: Отличная поддержка редактора. <dfn title="также известное как автозаполнение, интеллектуальность, автозавершение">Автодополнение кода</dfn> везде. Меньше времени на отладку.
* **Простой**: Разработан так, чтоб быть простым в использовании и изучении. Меньше времени на чтение документации.
* **Лаконичный**: Минимизировано повторение кода. Каждый объявленный параметр определяет несколько функций.
* **Надёжный**: Получите готовый к работе код. С автоматической интерактивной документацией.
* **Стандартизированный**: Основан на открытых стандартах API (<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> и <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>) и полностью совместим с ними.
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Множество других возможностей**</a> включая автоматическую проверку и сериализацию данных, интерактивную документацию, аутентификацию с помощью OAuth2 JWT-токенов и т.д.
* **Безопасное хранение паролей**, которые хэшируются по умолчанию.
* Аутентификация посредством **JWT-токенов**.
* <dfn title="Python-объекты связанные с базами данных">Модели</dfn> **SQLAlchemy** (независящие от расширений Flask, а значит могут быть непосредственно использованы процессами Celery).
* Базовая модель пользователя (измените или удалите её по необходимости).
* **Alembic** для организации миграций.
* **CORS** (Совместное использование ресурсов из разных источников).
* **Celery**, процессы которого могут выборочно импортировать и использовать модели и код из остальной части бэкенда.
* Тесты, на основе **Pytest**, интегрированные в Docker, чтобы Вы могли полностью проверить Ваше API, независимо от базы данных. Так как тесты запускаются в Docker, для них может создаваться новое хранилище данных каждый раз (Вы можете, по своему желанию, использовать ElasticSearch, MongoDB, CouchDB или другую СУБД, только лишь для проверки - будет ли Ваше API работать с этим хранилищем).
* Простая интеграция Python с **Jupyter Kernels** для разработки удалённо или в Docker с расширениями похожими на Atom Hydrogen или Visual Studio Code Jupyter.
* Фронтенд построен на фреймворке **Vue**:
* Сгенерирован с помощью Vue CLI.
* Поддерживает **аутентификацию с помощью JWT-токенов**.
* Страница логина.
* Перенаправление на страницу главной панели мониторинга после логина.
* Главная страница мониторинга с возможностью создания и изменения пользователей.
* Пользователь может изменять свои данные.
* **Vuex**.
* **Vue-router**.
* **Vuetify** для конструирования красивых компонентов страниц.
* **TypeScript**.
* Сервер Docker основан на **Nginx** (настроен для удобной работы с Vue-router).
* Многоступенчатая сборка Docker, то есть Вам не нужно сохранять или коммитить скомпилированный код.
* Тесты фронтенда запускаются во время сборки (можно отключить).
* Сделан настолько модульно, насколько возможно, поэтому работает "из коробки", но Вы можете повторно сгенерировать фронтенд с помощью Vue CLI или создать то, что Вам нужно и повторно использовать то, что захотите.
* **PGAdmin** для СУБД PostgreSQL, которые легко можно заменить на PHPMyAdmin и MySQL.
* **Flower** для отслеживания работы Celery.
* Балансировка нагрузки между фронтендом и бэкендом с помощью **Traefik**, а значит, Вы можете расположить их на одном домене, разделив url-пути, так как они обслуживаются разными контейнерами.
* Интеграция с Traefik включает автоматическую генерацию сертификатов Let's Encrypt для поддержки протокола **HTTPS**.
* GitLab **CI** (непрерывная интеграция), которая включает тестирование фронтенда и бэкенда.
## Full Stack FastAPI Couchbase
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
⚠️ **ПРЕДУПРЕЖДЕНИЕ** ⚠️
Если Вы начинаете новый проект, ознакомьтесь с представленными здесь альтернативами.
Например, генератор проектов <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> может быть более подходящей альтернативой, так как он активно поддерживается и используется. И он включает в себя все новые возможности и улучшения.
Но никто не запрещает Вам использовать генератор с СУБД Couchbase, возможно, он всё ещё работает нормально. Или у Вас уже есть проект, созданный с помощью этого генератора ранее, и Вы, вероятно, уже обновили его в соответствии со своими потребностями.
Вы можете прочитать о нём больше в документации соответствующего репозитория.
## Full Stack FastAPI MongoDB
...может быть когда-нибудь появится, в зависимости от наличия у меня свободного времени и прочих факторов. 😅 🎉
## Модели машинного обучения на основе spaCy и FastAPI
GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
### Модели машинного обучения на основе spaCy и FastAPI - Особенности
* Интеграция с моделями **spaCy** NER.
* Встроенный формат запросов к **когнитивному поиску Azure**.
* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
* Встроенное развёртывание на основе **Azure DevOps** Kubernetes (AKS) CI/CD.
* **Многоязычность**. Лёгкий выбор одного из встроенных в spaCy языков во время настройки проекта.
* **Легко подключить** модели из других фреймворков (Pytorch, Tensorflow) не ограничиваясь spaCy.
# Full Stack FastAPI Шаблон
Шаблоны, хотя обычно они поставляются с определенной конфигурацией, разработаны для гибкости и настройки. Это позволяет вам изменять и адаптировать их в соответствии с требованиями вашего проекта, что делает их отличной отправной точкой. 🏁
Вы можете использовать этот шаблон, чтобы начать работу, так как он включает множество начальных настроек, безопасности, базы данных и некоторые API-эндпоинты, которые уже выполнены за вас.
Репозиторий GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
## Full Stack FastAPI Шаблон - Технологический стек и функции
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python бэкенд API.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия с SQL базой данных Python (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), используемый FastAPI, для валидации данных и управления настройками.
- 💾 [PostgreSQL](https://www.postgresql.org) в качестве SQL базы данных.
- 🚀 [React](https://react.dev) для фронтенда.
- 💃 Используются TypeScript, хуки, [Vite](https://vitejs.dev), и другие элементы современного фронтенд стека.
- 🎨 [Chakra UI](https://chakra-ui.com) для фронтенд-компонентов.
- 🤖 Автоматически сгенерированный фронтенд-клиент.
- 🧪 [Playwright](https://playwright.dev) для End-to-End тестирования.
- 🦇 Поддержка темного режима.
- 🐋 [Docker Compose](https://www.docker.com) для разработки и производства.
- 🔒 Безопасное хеширование паролей по умолчанию.
- 🔑 JWT токены аутентификации.
- 📫 Восстановление пароля по электронной почте.
- ✅ Тесты с [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) в качестве обратного прокси / балансировщика нагрузки.
- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд-прокси Traefik для автоматической обработки HTTPS-сертификатов.
- 🏭 CI (непрерывная интеграция) и CD (непрерывное развертывание), основанные на GitHub Actions.

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

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

67
docs/ru/docs/tutorial/cors.md

@ -1,85 +1,88 @@
# CORS (Cross-Origin Resource Sharing)
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Понятие CORS или "Cross-Origin Resource Sharing"</a> относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом "источнике" ("origin").
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS или "Cross-Origin Resource Sharing"</a> относится к ситуациям, когда фронтенд, работающий в браузере, использует JavaScript-код для взаимодействия с бэкендом, который находится в другом "источнике" по сравнению с фронтендом.
## Источник
Источник - это совокупность протокола (`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`, и если бэкенд вернёт соответствующие заголовки для авторизации взаимодействия с другим источником (`http://localhost:8080`), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд.
Затем браузер отправит HTTP-запрос `OPTIONS` на бэкенд на порту `80`, и если бэкенд отправит соответствующие заголовки, разрешающие взаимодействие с этого отличающегося источника (`http://localhost:8080`), тогда браузер на порту `8080` позволит JavaScript на фронтенде отправить свой запрос на бэкенд на порту `80`.
Чтобы это работало, у бэкенда должен быть список "разрешённых источников" ("allowed origins").
Чтобы это воплотилось, бэкенд на порту `80` должен иметь список "разрешённых источников".
В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд работал корректно.
В данном случае список должен содержать `http://localhost:8080`, чтобы фронтенд на порту `8080` работал корректно.
## Подстановочный символ `"*"`
## Подстановочные символы
В качестве списка источников можно указать подстановочный символ `"*"` ("wildcard"), чтобы разрешить любые источники.
Можно также задать список как `"*"` (подстановочный символ), чтобы разрешить все источники.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п.
Но тогда разрешатся только определённые виды взаимодействия, исключая всё, что связано с учётными данными: куки, заголовки Authorization такие, как те, что используются с токенами Bearer и т.д.
Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.
Поэтому, чтобы всё функционировало правильно, лучше явно указывать разрешённые источники.
## Использование `CORSMiddleware`
Вы можете настроить этот механизм в вашем **FastAPI** приложении, используя `CORSMiddleware`.
Вы можете настроить это в вашем приложении **FastAPI** с помощью `CORSMiddleware`.
* Импортируйте `CORSMiddleware`.
* Создайте список разрешённых источников (в виде строк).
* Добавьте его как "middleware" к вашему **FastAPI** приложению.
* Создайте список разрешённых источников (как строки).
* Добавьте его как "middleware" к вашему приложению **FastAPI**.
Вы также можете указать, разрешает ли ваш бэкенд использование:
Вы также можете указать, позволяет ли ваш бэкенд использовать:
* Учётных данных (включая заголовки Authorization, куки и т.п.).
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
* Учётные данные (заголовки Authorization, куки и т.п.).
* Специфические HTTP-методы (`POST`, `PUT`) или все из них с помощью подстановочного символа `"*"`.
* Специфические HTTP-заголовки или все из них с помощью подстановочного символа `"*"`.
{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
`CORSMiddleware` использует для параметров "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
По умолчанию параметры, используемые реализацией `CORSMiddleware`, являются ограничительными, поэтому вам потребуется явно разрешить конкретные источники, методы или заголовки, чтобы браузеры могли использовать их в междоменном контексте.
Поддерживаются следующие аргументы:
* `allow_origins` - Список источников, на которые разрешено выполнять кросс-доменные запросы. Например, `['https://example.org', 'https://www.example.org']`. Можно использовать `['*']`, чтобы разрешить любые источники.
* `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\.example\.org'`.
* `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию равно `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы.
* `allow_headers` - Список HTTP-заголовков, которые должны поддерживаться при кросс-доменных запросах. По умолчанию равно `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">простых CORS-запросов</a>.
* `allow_credentials` - указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. Также, `allow_origins` нельзя присвоить `['*']`, если разрешено использование учётных данных. В таком случае должен быть указан список источников.
* `allow_origins` - Список источников, которым разрешено выполнять междоменные запросы. Например, `['https://example.org', 'https://www.example.org']`. Вы можете использовать `['*']`, чтобы разрешить любой источник.
* `allow_origin_regex` - Строка регулярного выражения для соответствия источникам, которым разрешено выполнять междоменные запросы, например, `'https://.*\.example\.org'`.
* `allow_methods` - Список HTTP-методов, которые должны быть разрешены для междоменных запросов. По умолчанию равно `['GET']`. Вы можете использовать `['*']`, чтобы разрешить все стандартные методы.
* `allow_headers` - Список HTTP-заголовков запросов, которые должны поддерживаться при междоменных запросах. По умолчанию равно `[]`. Вы можете использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">простых CORS-запросов</a>.
* `allow_credentials` - Указывает, что куки должны поддерживаться для междоменных запросов. По умолчанию равно `False`.
Нельзя установить значения `allow_origins`, `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`.
`CORSMiddleware` отвечает на два типа HTTP-запросов...
Middleware отвечает на два определённых типа HTTP-запросов...
### CORS-запросы с предварительной проверкой
Это любые `OPTIONS` запросы с заголовками `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.
///

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

@ -1,48 +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 версии 1 метод назывался `.dict()`, он был устаревшим (но все еще поддерживается) в Pydantic версии 2 и переименован в `.model_dump()`.
Примеры здесь используют `.dict()` для совместимости с Pydantic версии 1, но вы должны использовать `.model_dump()`, если можете применять Pydantic версии 2.
///
### Про `**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- модели).
И если мы вызовем:
@ -50,7 +58,7 @@ user_dict = user_in.dict()
print(user_dict)
```
мы можем получить `dict` с такими данными:
мы получим Python `dict` с:
```Python
{
@ -63,15 +71,15 @@ print(user_dict)
#### Распаковка `dict`
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
Если мы возьмём `dict` вроде `user_dict` и передадим его в функцию (или класс) с помощью `**user_dict`, Python "распакует" его. Он передаст ключи и значения `user_dict` напрямую как аргументы ключ-значение.
Поэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:
Поэтому, продолжая с `user_dict`, написание:
```Python
UserInDB(**user_dict)
```
Будет работать так же, как примерно такой код:
будет эквивалентно:
```Python
UserInDB(
@ -82,7 +90,7 @@ UserInDB(
)
```
Или, если для большей точности мы напрямую используем `user_dict` с любым потенциальным содержимым, то этот пример будет выглядеть так:
Или, более точно, используя напрямую `user_dict`, с любым будущим содержимым:
```Python
UserInDB(
@ -102,25 +110,25 @@ user_dict = user_in.dict()
UserInDB(**user_dict)
```
будет равнозначен такому:
будет эквивалентен:
```Python
UserInDB(**user_in.dict())
```
...потому что `user_in.dict()` - это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` и ставим перед ним `**`.
...потому что `user_in.dict()` — это `dict`, и затем мы указываем Python "распаковать" его, передавая его в `UserInDB`, добавив перед ним `**`.
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
Таким образом, мы получаем Pydantic-модель из данных другой Pydantic-модели.
#### Распаковка `dict` и дополнительные именованные аргументы
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
И затем, добавляя дополнительный именованный аргумент `hashed_password=hashed_password`, как в:
```Python
UserInDB(**user_in.dict(), hashed_password=hashed_password)
```
... то мы получим что-то подобное:
...это будет равно:
```Python
UserInDB(
@ -134,39 +142,39 @@ UserInDB(
/// warning | Предупреждение
Цель использованных в примере вспомогательных функций - не более чем демонстрация возможных операций с данными, но, конечно, они не обеспечивают настоящую безопасность.
Поддерживающие дополнительные функции `fake_password_hasher` и `fake_save_user` существуют исключительно для демонстрации возможного потока данных, но, конечно, не обеспечивают реальной безопасности.
///
## Сократите дублирование
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
Сокращение дублирования кода — одна из основных идей **FastAPI**.
Поскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.
Поскольку дублирование кода увеличивает вероятность появления ошибок, проблем с безопасностью, проблем с десинхронизацией кода (когда вы обновляете что-то в одном месте, но не в других), и т.д.
А все описанные выше модели используют много общих данных и дублируют названия атрибутов и типов.
И все эти модели разделяют много данных и дублируют названия и типы атрибутов.
Мы можем это улучшить.
Мы могли бы сделать лучше.
Мы можем определить модель `UserBase`, которая будет базовой для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию, и т.п.).
Мы можем определить модель `UserBase`, которая будет базовой для наших других моделей. А затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию и т.д.).
Все операции конвертации, валидации, документации, и т.п. будут по-прежнему работать нормально.
Все преобразования данных, валидация, документация и т.д. будут работать как обычно.
В этом случае мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля):
Таким образом, мы можем определить только отличия между моделями (с открытым `password`, с `hashed_password` и без пароля):
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
## `Union` или `anyOf`
Вы можете определить ответ как `Union` из двух типов. Это означает, что ответ должен соответствовать одному из них.
Вы можете объявить ответ как `Union` из двух или более типов, что значит, что ответ может быть любым из них.
Он будет определён в OpenAPI как `anyOf`.
Для этого используйте стандартные аннотации типов в 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]`.
///
@ -174,31 +182,31 @@ UserInDB(
### `Union` в Python 3.10
В этом примере мы передаём `Union[PlaneItem, CarItem]` в качестве значения аргумента `response_model`.
В этом примере мы передаём `Union[PlaneItem, CarItem]` как значение аргумента `response_model`.
Поскольку мы передаём его как **значение аргумента** вместо того, чтобы поместить его в **аннотацию типа**, нам придётся использовать `Union` даже в Python 3.10.
Поскольку мы передаём его как **значение для аргумента**, а не помещаем его в **аннотацию типа**, нам необходимо использовать `Union` даже в Python 3.10.
Если оно было бы указано в аннотации типа, то мы могли бы использовать вертикальную черту как в примере:
Если бы это было в аннотации типа, мы могли бы использовать вертикальную черту, как в примере:
```Python
some_variable: PlaneItem | CarItem
```
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
Но если мы поместим это в присвоение `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается выполнить **недопустимую операцию** между `PlaneItem` и `CarItem` вместо интерпретации это как аннотацию типа.
## Список моделей
Таким же образом вы можете определять ответы как списки объектов.
Аналогичным образом вы можете объявить ответы как списки объектов.
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
Для этого используйте стандартный Python `typing.List` (или просто `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 и выше):
@ -206,6 +214,6 @@ some_variable: PlaneItem | CarItem
## Резюме
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
Используйте несколько Pydantic-моделей и свободно наследуйте для каждого случая.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность существовать в разных "состояниях". Как в случае с "сущностью" пользователя с состояниями, включающими `password`, `password_hash` и без пароля.

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

@ -1,50 +1,66 @@
# Первые шаги
Самый простой FastAPI файл может выглядеть так:
Самый простой файл FastAPI может выглядеть следующим образом:
{* ../../docs_src/first_steps/tutorial001.py *}
Скопируйте в файл `main.py`.
Скопируйте этот код в файл `main.py`.
Запустите сервер в режиме реального времени:
Запустите live сервер:
<div class="termy">
```console
$ uvicorn main:app --reload
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
```
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Запуск сервера для разработки 🚀
</div>
Ищем структуру файлов пакета в директориях
с файлами <font color="#3465A4">__init__.py</font>
Импортирование из <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
/// note | Технические детали
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
Команда `uvicorn main:app` обращается к:
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Импортируем объект приложения FastAPI из модуля с
помощью следующего кода:
* `main`: файл `main.py` (модуль Python).
* `app`: объект, созданный внутри файла `main.py` в строке `app = FastAPI()`.
* `--reload`: перезапускает сервер после изменения кода. Используйте только для разработки.
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
///
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Используем строку импорта: <font color="#3465A4">main:app</font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Сервер запущен по адресу <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Документация по адресу <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Запуск в режиме разработки, для использования в продакшене:
<b>fastapi run</b>
Логи:
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Будем отслеживать изменения в этих директориях:
<b>[</b><font color="#4E9A06">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn запущен по адресу <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>нажмите CTRL+C
для завершения<b>)</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Процесс перезагрузки запущен <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> с использованием WatchFiles
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Серверный процесс запущен <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Ожидание запуска приложения.
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Запуск приложения завершен.
```
</div>
В окне вывода появится следующая строка:
В выводе будет строка, похожая на:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Uvicorn запущен по адресу http://127.0.0.1:8000 (нажмите CTRL+C для завершения)
```
Эта строка показывает 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"}
@ -52,55 +68,55 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
### Интерактивная документация 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**.
**FastAPI** генерирует "схему" всего вашего API, используя стандарт **OpenAPI** для определения API.
#### "Схема"
"Схема" - это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание.
"Схема" это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание.
#### 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.
Определение схемы содержит пути (paths) API, их параметры и т.п.
Это определение схемы включает в себя пути вашего API, возможные параметры, которые они принимают, и т.д.
#### "Схема" данных
Термин "схема" также может относиться к формату или структуре некоторых данных, например, JSON.
Термин "схема" также может относиться к формату данных, например, к содержимому JSON.
Тогда, подразумеваются атрибуты JSON, их типы данных и т.п.
В этом случае это будет означать атрибуты JSON и типы данных, которые они имеют, и т.д.
#### OpenAPI и JSON Schema
OpenAPI описывает схему API. Эта схема содержит определения (или "схемы") данных, отправляемых и получаемых API. Для описания структуры данных в JSON используется стандарт **JSON Schema**.
OpenAPI определяет схему API для вашего API. А эта схема включает в себя определения (или "схемы") данных, отправляемых и получаемых вашим API, используя **JSON Schema**, стандарт для схем данных JSON.
#### Рассмотрим `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
{
"openapi": "3.0.2",
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
@ -121,11 +137,11 @@ OpenAPI описывает схему API. Эта схема содержит о
#### Для чего нужен OpenAPI
Схема OpenAPI является основой для обеих систем интерактивной документации.
Схема OpenAPI обеспечивает работу двух включенных систем интерактивной документации.
Существуют десятки альтернативных инструментов, основанных на OpenAPI. Вы можете легко добавить любой из них к **FastAPI** приложению.
Существуют десятки альтернатив, все они основываются на OpenAPI. Вы можете легко добавить любую из этих альтернатив к своему приложению на **FastAPI**.
Вы также можете использовать OpenAPI для автоматической генерации кода для клиентов, которые взаимодействуют с API. Например, для фронтенд-, мобильных или IoT-приложений.
Вы также можете использовать её для автоматической генерации кода для клиентов, которые взаимодействуют с вашим API. Например, для фронтенд-, мобильных или IoT-приложений.
## Рассмотрим поэтапно
@ -133,137 +149,109 @@ OpenAPI описывает схему 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`.
Это единая точка входа для создания и взаимодействия с API.
Именно к этой переменной `app` обращается `uvicorn` в команде:
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Если создать такое приложение:
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
И поместить его в `main.py`, тогда вызов `uvicorn` будет таким:
Здесь переменная `app` будет "экземпляром" класса `FastAPI`.
<div class="termy">
```console
$ uvicorn main:my_awesome_api --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Это будет главная точка взаимодействия для создания и работы с вашим API.
### Шаг 3: определите *операцию пути (path operation)*
### Шаг 3: создайте *операцию пути*
#### Путь (path)
#### Путь
"Путь" это часть URL, после первого символа `/`, следующего за именем домена.
Здесь "путь" относится к последней части URL, начиная с первого `/`.
Для URL:
Таким образом, в URL типа:
```
https://example.com/items/foo
```
...путь выглядит так:
...путь будет:
```
/items/foo
```
/// info | Дополнительная иформация
/// info
Термин "path" также часто называется "endpoint" или "route".
"Путь" также часто называют "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` Информация
Синтаксис `@something` в Python называется "декоратор".
Вы помещаете его над функцией. Как красивую декоративную шляпу (думаю, что оттуда и происходит этот термин).
Вы располагаете его над функцией. Подобно декоративной шляпе (вероятно, отсюда и происходит этот термин).
"Декоратор" принимает функцию ниже и выполняет с ней какое-то действие.
В нашем случае, этот декоратор сообщает **FastAPI**, что функция ниже соответствует **пути** `/` и **операции** `get`.
В нашем случае, этот декоратор сообщает **FastAPI**, что функция ниже соответствует **пути** `/` и **операции** `get`.
Это и есть "**декоратор операции пути**".
///
Можно также использовать операции:
Вы также можете использовать другие операции:
* `@app.post()`
* `@app.put()`
@ -278,58 +266,58 @@ 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** будет вызывать её каждый раз при получении `GET` запроса к URL "`/`".
Она будет вызываться **FastAPI** каждый раз, когда будет получен запрос к URL "`/`" с использованием операции `GET`.
В данном случае это асинхронная функция.
В данном случае она является асинхронной функцией.
---
Вы также можете определить ее как обычную функцию вместо `async def`:
Вы также можете определить её как обычную функцию вместо `async def`:
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | Технические детали
/// note
Если не знаете в чём разница, посмотрите [Конкурентность: *"Нет времени?"*](../async.md#_1){.internal-link target=_blank}.
Если вы не знаете разницы, посмотрите [Асинхронность: *"В торопях?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
///
### Шаг 5: верните результат
### Шаг 5: верните содержимое
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.
Также можно вернуть модели Pydantic (рассмотрим это позже).
Также вы можете вернуть модели Pydantic (вы узнаете об этом позже).
Многие объекты и модели будут автоматически преобразованы в JSON (включая ORM). Пробуйте использовать другие объекты, которые предпочтительней для Вас, вероятно, они уже поддерживаются.
Множество других объектов и моделей будут автоматически преобразованы в JSON (включая ORM и т.п.). Попробуйте использовать ваши любимые — они с большой вероятностью уже поддерживаются.
## Резюме
* Импортируем `FastAPI`.
* Создаём экземпляр `app`.
* Пишем **декоратор операции пути** (такой как `@app.get("/")`).
* Пишем **функцию операции пути** (`def root(): ...`).
* Запускаем сервер в режиме разработки (`uvicorn main:app --reload`).
* Импортируйте `FastAPI`.
* Создайте экземпляр `app`.
* Напишите **декоратор операции пути** с помощью декораторов вроде `@app.get("/")`.
* Определите **функцию операции пути**; например, `def root(): ...`.
* Запустите сервер разработки с помощью команды `fastapi dev`.

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

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

88
docs/ru/docs/tutorial/index.md

@ -1,36 +1,60 @@
# Учебник - Руководство пользователя
В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций.
Этот учебник показывает, как использовать **FastAPI** со многими его функциями, шаг за шагом.
Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API.
Каждый раздел постепенно опирается на предыдущие, но структура разбита на отдельные темы, чтобы вы могли перейти прямо к любой конкретной теме для решения своих специфичных нужд API.
Он также создан для использования в качестве будущего справочника.
Он также создан для использования в качестве справочной информации в будущем, чтобы вы могли возвращаться и находить именно то, что вам нужно.
Так что вы можете вернуться и посмотреть именно то, что вам нужно.
## Запуск кода
## Запустите код
Все блоки кода можно копировать и использовать напрямую (это действительно проверенные файлы Python).
Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python).
Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `uvicorn` с параметрами:
Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с помощью:
<div class="termy">
```console
$ uvicorn main:app --reload
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Начало работы сервера разработки 🚀
Поиск структуры файлов пакета в каталогах
с файлами <font color="#3465A4">__init__.py</font>
Импорт из <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Импорт объекта приложения FastAPI из модуля со
следующим кодом:
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Использование строки импорта: <font color="#3465A4">main:app</font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Сервер запущен на <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Документация доступна по адресу <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Запущен в режиме разработки, для продакшена используйте:
<b>fastapi run</b>
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
Логи:
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Будет отслеживать изменения в этих каталогах:
<b>[</b><font color="#4E9A06">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn запущен на <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>нажмите CTRL+C
для выхода<b>)</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Запущен процесс автоперезагрузки <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> с использованием WatchFiles
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Запущен процесс сервера <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Ожидание запуска приложения.
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Запуск приложения завершен.
```
</div>
**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально.
**Настоятельно рекомендуется** написать или скопировать код, отредактировать его и запустить локально.
Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д.
Использование кода в вашем редакторе действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д.
---
@ -38,46 +62,34 @@ $ uvicorn main:app --reload
Первый шаг — установить FastAPI.
Для руководства вы, возможно, захотите установить его со всеми дополнительными зависимостями и функциями:
Убедитесь, что вы создали [виртуальную среду](../virtual-environments.md){.internal-link target=_blank}, активировали ее, а затем **установили FastAPI**:
<div class="termy">
```console
$ pip install "fastapi[all]"
$ pip install "fastapi[standard]"
---> 100%
```
</div>
...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код.
/// note | Технические детали
Вы также можете установить его по частям.
/// note | Примечание
Это то, что вы, вероятно, сделаете, когда захотите развернуть свое приложение в рабочей среде:
При установке с помощью `pip install "fastapi[standard]"` поставляются некоторые стандартные дополнительные зависимости, включая `fastapi-cloud-cli`, который позволяет развертывать приложения на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
```
pip install fastapi
```
Также установите `uvicorn` для работы в качестве сервера:
```
pip install "uvicorn[standard]"
```
Если вы не хотите иметь эти необязательные зависимости, вы можете установить `pip install fastapi`.
И то же самое для каждой из необязательных зависимостей, которые вы хотите использовать.
Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, вы можете установить с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
///
## Продвинутое руководство пользователя
Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**.
Существует также **Продвинутое руководство пользователя**, которое вы можете прочитать после **Учебника - Руководства пользователя**.
**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям.
**Продвинутое руководство пользователя** основывается на этом, использует те же концепции и обучает вас некоторым дополнительным функциям.
Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
Но сначала вам следует прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**.
Он разработан так, чтобы вы могли создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших нужд, с использованием некоторых дополнительных идей из **Продвинутого руководства пользователя**.

87
docs/ru/docs/tutorial/middleware.md

@ -1,45 +1,43 @@
# Middleware (Промежуточный слой)
# Middleware (Промежуточное ПО)
Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
Вы можете добавить промежуточное ПО (middleware) в приложения на **FastAPI**.
"Middleware" это функция, которая выполняется с каждым запросом до его обработки какой-либо конкретной *операцией пути*.
А также с каждым ответом перед его возвращением.
"Промежуточное ПО" - это функция, которая работает с каждым **запросом** до того, как он обработается какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвратом.
* Она принимает каждый поступающий **запрос**.
* Может что-то сделать с этим **запросом** или выполнить любой нужный код.
* Затем передает **запрос** для последующей обработки (какой-либо *операцией пути*).
* Получает **ответ** (от *операции пути*).
* Может что-то сделать с этим **ответом** или выполнить любой нужный код.
* И возвращает **ответ**.
* Оно обрабатывает каждый **запрос**, поступающий в ваше приложение.
* Может что-то сделать с этим **запросом** или выполнить любой необходимый код.
* Затем передает **запрос** для дальнейшей обработки остальным приложением (какой-либо *операцией пути*).
* Затем оно обрабатывает **ответ**, сгенерированный приложением (какой-либо *операцией пути*).
* Может что-то сделать с этим **ответом** или выполнить любой необходимый код.
* Затем возвращает **ответ**.
/// note | Технические детали
Если у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware.
Если у вас есть зависимости с `yield`, код выхода выполнится *после* промежуточного ПО.
Если у вас имеются некие фоновые задачи (см. документацию), то они будут запущены после middleware.
Если есть какие-либо фоновые задачи (рассматриваемые в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}, вы увидите это позже), они будут выполнены *после* всего промежуточного ПО.
///
## Создание middleware
## Создание промежуточного ПО
Для создания middleware используйте декоратор `@app.middleware("http")`.
Чтобы создать промежуточное ПО, используйте декоратор `@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">Starlette's CORS docs</a>.
Но если у вас есть собственные заголовки, которые вы хотите показать клиенту в браузере, вам необходимо добавить их в конфигурации CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) с использованием параметра `expose_headers`, документированного в <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">документации по CORS Starlette</a>.
///
@ -47,28 +45,51 @@
Вы также можете использовать `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 | Примечание
/// 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
## Порядок выполнения нескольких промежуточных ПО
Когда вы добавляете несколько промежуточных ПО с использованием либо декоратора `@app.middleware()`, либо метода `app.add_middleware()`, каждое новое промежуточное ПО оборачивает приложение, формируя стек. Последнее добавленное промежуточное ПО является *самым внешним*, а первое - *самым внутренним*.
На пути запроса сначала выполняется *самое внешнее* промежуточное ПО.
На пути ответа оно выполняется последним.
Например:
```Python
app.add_middleware(MiddlewareA)
app.add_middleware(MiddlewareB)
```
Это приводит к следующему порядку выполнения:
* **Запрос**: MiddlewareB → MiddlewareA → маршрут
* **Ответ**: маршрут → MiddlewareA → MiddlewareB
Это поведение стека гарантирует, что промежуточные ПО выполняются в предсказуемом и контролируемом порядке.
## Другие промежуточные ПО
О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
Вы можете позже прочитать больше о других промежуточных ПО в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
В следующем разделе вы можете прочитать, как настроить <abbr title="Cross-Origin Resource Sharing">CORS</abbr> с помощью middleware.
В следующем разделе вы узнаете, как настроить <abbr title="Cross-Origin Resource Sharing">CORS</abbr> с помощью промежуточного ПО.

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

@ -1,61 +1,51 @@
# Query-параметры и валидация строк
**FastAPI** позволяет определять дополнительную информацию и валидацию для ваших параметров.
**FastAPI** позволяет объявлять дополнительную информацию и валидацию для ваших параметров.
Давайте рассмотрим следующий пример:
Рассмотрим этот пример приложения:
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
Query-параметр `q` имеет тип `Union[str, None]` (или `str | None` в Python 3.10). Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный.
Query-параметр `q` имеет тип `str | None`, это значит, что он имеет тип `str`, но также может быть `None`. Более того, значение по умолчанию равно `None`, поэтому FastAPI определит, что он не является обязательным.
/// note | Технические детали
FastAPI определит параметр `q` как необязательный, потому что его значение по умолчанию `= None`.
FastAPI определит, что значение `q` не является обязательным благодаря значению по умолчанию `= None`.
`Union` в `Union[str, None]` позволит редактору кода оказать вам лучшую поддержку и найти ошибки.
Использование `str | None` позволит вашему редактору кода обеспечить лучшую поддержку и обнаружение ошибок.
///
## Расширенная валидация
## Дополнительная валидация
Добавим дополнительное условие валидации параметра `q` - **длина строки не более 50 символов** (условие проверяется всякий раз, когда параметр `q` не является `None`).
Мы хотим убедиться, что даже если `q` является опциональным, когда он предоставлен, **его длина не превышает 50 символов**.
### Импорт `Query` и `Annotated`
Чтобы достичь этого, первым делом нам нужно импортировать:
Для этого сначала импортируйте:
* `Query` из пакета `fastapi`:
* `Annotated` из пакета `typing` (или из `typing_extensions` для Python ниже 3.9)
* `Query` из `fastapi`
* `Annotated` из `typing`
//// tab | Python 3.10+
В Python 3.9 или выше, `Annotated` является частью стандартной библиотеки, таким образом вы можете импортировать его из `typing`.
```Python hl_lines="1 3"
{!> ../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
////
//// tab | Python 3.8+
/// info | Дополнительная информация
В версиях Python ниже Python 3.9 `Annotation` импортируется из `typing_extensions`.
FastAPI добавил поддержку `Annotated` (и стал рекомендовать его) в версии 0.95.0.
Эта библиотека будет установлена вместе с FastAPI.
Если у вас более старая версия, вы получите ошибки при попытке использовать `Annotated`.
```Python hl_lines="3-4"
{!> ../../docs_src/query_params_str_validations/tutorial002_an.py!}
```
Убедитесь, что вы [обновите версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`.
////
///
## `Annotated` как тип для query-параметра `q`
## Использование `Annotated` в типе для параметра `q`
Помните, как ранее я говорил об Annotated? Он может быть использован для добавления метаданных для ваших параметров в разделе [Введение в аннотации типов Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
Помните, я говорил вам ранее, что `Annotated` может использоваться для добавления метаданных к вашим параметрам в [Введение в аннотации типов Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
Пришло время использовать их в FastAPI. 🚀
Теперь пришло время использовать его с FastAPI. 🚀
У нас была аннотация следующего типа:
У нас была следующая аннотация типа:
//// tab | Python 3.10+
@ -73,7 +63,7 @@ q: Union[str, None] = None
////
Вот что мы получим, если обернём это в `Annotated`:
Теперь мы обернем это в `Annotated`, чтобы получить:
//// tab | Python 3.10+
@ -91,117 +81,92 @@ q: Annotated[Union[str, None]] = None
////
Обе эти версии означают одно и тоже. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`.
Обе версии означают одно и то же: `q` - это параметр, который может быть `str` или `None`, и по умолчанию он равен `None`.
Давайте повеселимся. 🎉
Теперь перейдем к самому интересному. 🎉
## Добавим `Query` в `Annotated` для query-параметра `q`
## Добавим `Query` в `Annotated` для параметра `q`
Теперь, когда у нас есть `Annotated`, где мы можем добавить больше метаданных, добавим `Query` со значением параметра `max_length` равным 50:
Теперь, когда у нас есть `Annotated`, где мы можем поместить больше информации (в данном случае дополнительную валидацию), добавим `Query` внутрь `Annotated` и установим параметр `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, что мы хотим извлечь это значение из параметров query-запроса (что произойдёт в любом случае 🤷), и что мы хотим иметь **дополнительные условия валидации** для этого значения (для чего мы и делаем это - чтобы получить дополнительную валидацию). 😎
/// tip | Подсказка
Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают те же аргументы, что и `Query()`.
///
Теперь FastAPI:
* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов
* Показывает **исчерпывающую ошибку** (будет описание местонахождения ошибки и её причины) для клиента в случаях, когда данные не валидны
* **Задокументирует** параметр в схему OpenAPI *операции пути* (что будет отображено в **UI автоматической документации**)
* **Проверит** данные, убедившись, что максимальная длина составляет 50 символов
* Покажет **четкую ошибку** клиента, когда данные невалидны
* **Документирует** параметр в схеме OpenAPI *операции пути* (что будет отображаться в **автоматической документации**)
## Альтернативный (устаревший) способ задать `Query` как значение по умолчанию
## Альтернативный (старый): `Query` как значение по умолчанию
В предыдущих версиях FastAPI (ниже <abbr title="ранее 2023-03">0.95.0</abbr>) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню.
В предыдущих версиях FastAPI (до <abbr title="раньше 2023-03">0.95.0</abbr>) требовалось использовать `Query` как значение по умолчанию для вашего параметра, вместо размещения его в `Annotated`. Есть высокая вероятность, что вы увидите код, использующий его, поэтому я объясню его вам.
/// tip | Подсказка
При написании нового кода и везде где это возможно, используйте `Annotated`, как было описано ранее. У этого способа есть несколько преимуществ (о них дальше) и никаких недостатков. 🍰
Для нового кода и когда это возможно, используйте `Annotated`, как описано выше. Есть множество преимуществ (объяснены ниже) и никаких недостатков. 🍰
///
Вот как вы могли бы использовать `Query()` в качестве значения по умолчанию параметра вашей функции, установив для параметра `max_length` значение 50:
Вот как вы бы использовали `Query()` в качестве значения по умолчанию параметра вашей функции, устанавливая параметр `max_length` равным 50:
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
В таком случае (без использования `Annotated`), мы заменили значение по умолчанию с `None` на `Query()` в функции. Теперь нам нужно установить значение по умолчанию для query-параметра `Query(default=None)`, что необходимо для тех же целей, как когда ранее просто указывалось значение по умолчанию (по крайней мере, для FastAPI).
Таким образом:
```Python
q: Union[str, None] = Query(default=None)
```
...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
```Python
q: Union[str, None] = None
```
В этом случае (без использования `Annotated`) мы заменяем значение по умолчанию `None` функции на `Query()`, теперь нам необходимо установить значение по умолчанию с параметром `Query(default=None)`, это служит той же цели определения значения по умолчанию (по крайней мере для FastAPI).
И для Python 3.10 и выше:
Так:
```Python
q: str | None = Query(default=None)
```
...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
...делает параметр необязательным, со значением по умолчанию `None`, то же самое, что и:
```Python
q: str | None = None
```
Но он явно объявляет его как query-параметр.
/// info | Дополнительная информация
Но версия с `Query` определяет его явно как query-параметр.
Запомните, важной частью объявления параметра как необязательного является:
Затем мы можем передать больше параметров в `Query`. В данном случае, параметр `max_length`, который применяется к строкам:
```Python
= None
q: str | None = Query(default=None, max_length=50)
```
или:
Это проверит данные, покажет четкую ошибку, когда данные невалидны, и задокументирует параметр в OpenAPI схеме *операции пути*.
```Python
= Query(default=None)
```
так как `None` указан в качестве значения по умолчанию, параметр будет **необязательным**.
### `Query` как значение по умолчанию или в `Annotated`
`Union[str, None]` позволит редактору кода оказать вам лучшую поддержку. Но это не то, на что обращает внимание FastAPI для определения необязательности параметра.
Имейте в виду, что при использовании `Query` внутри `Annotated` вы не можете использовать параметр `default` у `Query`.
///
Вместо этого используйте фактическое значение по умолчанию параметра функции. В противном случае это будет не совместимо.
Теперь, мы можем указать больше параметров для `Query`. В данном случае, параметр `max_length` применяется к строкам:
```Python
q: Union[str, None] = Query(default=None, max_length=50)
```
Входные данные будут проверены. Если данные недействительны, тогда будет указано на ошибку в запросе (будет описание местонахождения ошибки и её причины). Кроме того, параметр задокументируется в схеме OpenAPI данной *операции пути*.
### Использовать `Query` как значение по умолчанию или добавить в `Annotated`
Когда `Query` используется внутри `Annotated`, вы не можете использовать параметр `default` у `Query`.
Вместо этого, используйте обычное указание значения по умолчанию для параметра функции. Иначе, это будет несовместимо.
Следующий пример не рабочий:
Например, это не разрешено:
```Python
q: Annotated[str, Query(default="rick")] = "morty"
```
...потому что нельзя однозначно определить, что именно должно быть значением по умолчанию: `"rick"` или `"morty"`.
...потому что не ясно, какое именно значение должно быть по умолчанию: `"rick"` или `"morty"`.
Вам следует использовать (предпочтительно):
Так что вы бы использовали (предпочтительно):
```Python
q: Annotated[str, Query()] = "rick"
```
...или как в старом коде, который вам может попасться:
...или в старых кодовых базах вы найдете:
```Python
q: str = Query(default="rick")
@ -209,55 +174,69 @@ q: str = Query(default="rick")
### Преимущества `Annotated`
**Рекомендуется использовать `Annotated`** вместо значения по умолчанию в параметрах функции, потому что так **лучше** по нескольким причинам. 🤓
**Использование `Annotated` рекомендуется** вместо значения по умолчанию в параметрах функции, это **лучше** по нескольким причинам. 🤓
Значение **по умолчанию** у **параметров функции** - это **действительно значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌
**Значение по умолчанию** **параметра функции** - это **фактически значение по умолчанию**, что более интуитивно для общего использования Python. 😌
Вы можете **вызвать** ту же функцию в **иных местах** без FastAPI, и она **сработает как ожидается**. Если это **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке. **Python** также укажет на ошибку, если вы вызовете функцию без передачи ей обязательного параметра.
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она **будет работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит вам об этом ошибкой, **Python** также укажет на нее, если вы запустите его без передачи обязательного параметра.
Если вы вместо `Annotated` используете **(устаревший) стиль значений по умолчанию**, тогда при вызове этой функции без FastAPI в **другом месте** вам необходимо **помнить** о передаче аргументов функции, чтобы она работала корректно. В противном случае, значения будут отличаться от тех, что вы ожидаете (например, `QueryInfo` или что-то подобное вместо `str`). И ни ваш редактор кода, ни Python не будут жаловаться на работу этой функции, только когда вычисления внутри дадут сбой.
Когда вы не используете `Annotated` и вместо этого пользуетесь **(старым) стилем значений по умолчанию**, если вы вызовете эту функцию без FastAPI в **других местах**, вам нужно **помнить** передавать аргументы функции, чтобы она работала правильно, в противном случае значения будут отличаться от тех, которые вы ожидаете (например, `QueryInfo` или что-то подобное вместо `str`). И ваш редактор не будет жаловаться, и Python не будет жаловаться, выполняя эту функцию, только операции внутри этой функции будут давать сбой.
Так как `Annotated` может принимать более одной аннотации метаданных, то теперь вы можете использовать ту же функцию с другими инструментами, например <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
Так как `Annotated` может иметь более одной аннотации метаданных, вы теперь даже можете использовать одну и ту же функцию с другими инструментами, такими как <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
## Больше валидации
## Дополнительная валидация
Вы также можете добавить параметр `min_length`:
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
## Регулярные выражения
## Добавление регулярных выражений
Вы можете определить <abbr title="Регулярное выражение, regex или regexp - это последовательность символов, определяющая шаблон для строк.">регулярное выражение</abbr>, которому должен соответствовать параметр:
Вы можете определить <abbr title="Регулярное выражение, regex или regexp - это последовательность символов, определяющая шаблон для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
Данное регулярное выражение проверяет, что полученное значение параметра:
Это регулярное выражение проверяет, что полученное значение параметра:
* `^`: начинается с следующих символов, перед которыми ничего нет.
* `fixedquery`: имеет точное значение `fixedquery`.
* `$`: заканчивается здесь, после `fixedquery` нет символов.
Если вам сложно дается концепция **"регулярные выражения"**, не беспокойтесь. Для многих людей это трудная тема. Вы можете делать множество вещей, не прибегая к регулярным выражениям.
Теперь вы знаете, что когда они вам понадобятся, вы сможете использовать их в **FastAPI**.
### Pydantic v1 `regex` вместо `pattern`
* `^`: начало строки.
* `fixedquery`: в точности содержит строку `fixedquery`.
* `$`: конец строки, не имеет символов после `fixedquery`.
До версии Pydantic 2 и до FastAPI 0.100.0 параметр назывался `regex` вместо `pattern`, но теперь он устарел.
Не переживайте, если **"регулярное выражение"** вызывает у вас трудности. Это достаточно сложная тема для многих людей. Вы можете сделать множество вещей без использования регулярных выражений.
Вы все еще можете увидеть код, использующий его:
Но когда они вам понадобятся, и вы закончите их освоение, то не будет проблемой использовать их в **FastAPI**.
//// tab | Pydantic v1
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
////
Но знайте, что это устаревшая версия и ее следует обновить для использования нового параметра `pattern`. 🤓
## Значения по умолчанию
Вы точно также можете указать любое значение `по умолчанию`, как ранее указывали `None`.
Разумеется, вы можете использовать значения по умолчанию, отличные от `None`.
Например, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`:
Предположим, вы хотите объявить query-параметр `q` с `min_length` равным `3` и со значением по умолчанию `"fixedquery"`:
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
/// note | Технические детали
Наличие значения по умолчанию делает параметр необязательным.
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным (не требуется).
///
## Обязательный параметр
Когда вам не требуется дополнительная валидация или дополнительные метаданные для параметра запроса, вы можете сделать параметр `q` обязательным просто не указывая значения по умолчанию. Например:
Когда нам не нужно объявлять больше валидации или метаданных, мы можем сделать query-параметр `q` обязательным, просто не объявляя значение по умолчанию, например:
```Python
q: str
@ -266,62 +245,48 @@ q: str
вместо:
```Python
q: Union[str, None] = None
q: str | None = None
```
Но у нас query-параметр определён как `Query`. Например:
Но мы теперь определяем его с `Query`, например так:
//// tab | Annotated
```Python
q: Annotated[Union[str, None], Query(min_length=3)] = None
q: Annotated[str | None, Query(min_length=3)] = None
```
////
//// tab | без Annotated
```Python
q: Union[str, None] = Query(default=None, min_length=3)
```
////
В таком случае, чтобы сделать query-параметр `Query` обязательным, вы можете просто не указывать значение по умолчанию:
Так что, когда вам нужно объявить значение обязательным при использовании `Query`, вы можете просто не указывать значение по умолчанию:
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
### Обязательный параметр с `None`
### Обязательно, может быть `None`
Вы можете определить, что параметр может принимать `None`, но всё ещё является обязательным. Это может потребоваться для того, чтобы пользователи явно указали параметр, даже если его значение будет `None`.
Вы можете объявить, что параметр может принимать значение `None`, но при этом является обязательным. Это заставит клиентов отправлять значение, даже если оно равно `None`.
Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но также указать `default=...`:
Для этого вы можете объявить, что `None` допустимый тип, но просто не указывать значение по умолчанию:
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
/// tip | Подсказка
## Список значений для query-параметра / несколько значений
Pydantic, мощь которого используется в FastAPI для валидации и сериализации, имеет специальное поведение для `Optional` или `Union[Something, None]` без значения по умолчанию. Вы можете узнать об этом больше в документации Pydantic, раздел <a href="https://docs.pydantic.dev/latest/concepts/models/#required-optional-fields" class="external-link" target="_blank">Обязательные Опциональные поля</a>.
Когда вы явно определяете query-параметр с помощью `Query`, вы также можете указать его как принимающий список значений или, иначе говоря, принимающий несколько значений.
///
## Множество значений для query-параметра
Для query-параметра `Query` можно указать, что он принимает список значений (множество значений).
Например, query-параметр `q` может быть указан в URL несколько раз. И если вы ожидаете такой формат запроса, то можете указать это следующим образом:
Например, чтобы объявить query-параметр `q`, который может появляться несколько раз в URL, вы можете написать:
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
Затем, получив такой URL:
Затем, с таким URL:
```
http://localhost:8000/items/?q=foo&q=bar
```
вы бы получили несколько значений (`foo` и `bar`), которые относятся к параметру `q`, в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
вы получите несколько значений *query-параметра* `q` (`foo` и `bar`) в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
Таким образом, ответ на этот URL будет:
Так что ответ на этот URL будет:
```JSON
{
@ -334,27 +299,27 @@ http://localhost:8000/items/?q=foo&q=bar
/// tip | Подсказка
Чтобы объявить query-параметр типом `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
Чтобы объявить query-параметр типа `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
///
Интерактивная документация API будет обновлена соответствующим образом, где будет разрешено множество значений:
Интерактивная документация API обновится соответственно, чтобы разрешить множество значений:
<img src="/img/tutorial/query-params-str-validations/image02.png">
### Query-параметр со множеством значений по умолчанию
### Список значений для query-параметра / несколько значений по умолчанию
Вы также можете указать тип `list` со списком значений по умолчанию на случай, если вам их не предоставят:
Вы также можете определить значение по умолчанию `list` для случаев, когда никакие значения не предоставлены:
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
Если вы перейдёте по ссылке:
Если вы перейдете по:
```
http://localhost:8000/items/
```
значение по умолчанию для `q` будет: `["foo", "bar"]` и ответом для вас будет:
значением по умолчанию для `q` будет: `["foo", "bar"]` и ваш ответ будет:
```JSON
{
@ -365,100 +330,163 @@ http://localhost:8000/items/
}
```
#### Использование `list`
#### Использование только `list`
Вы также можете использовать `list` напрямую вместо `List[str]` (или `list[str]` в Python 3.9+):
Вы также можете использовать `list` напрямую вместо `list[str]`:
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note | Технические детали
Запомните, что в таком случае, FastAPI не будет проверять содержимое списка.
Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.
Например, для List[int] список будет провалидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
Например, `list[int]` бы проверяла (и документировала), что содержимое списка является целыми числами. Но простой `list` не будет этого делать.
///
## Больше метаданных
## Объявление дополнительных метаданных
Вы можете добавить больше информации об query-параметре.
Вы можете добавить больше информации о параметре.
Указанная информация будет включена в генерируемую OpenAPI документацию и использована в пользовательском интерфейсе и внешних инструментах.
Эта информация будет включена в генерируемую OpenAPI и использована интерфейсами документации и внешними инструментами.
/// note | Технические детали
Имейте в виду, что разные инструменты могут иметь разные уровни поддержки OpenAPI.
Имейте в виду, что разные инструменты могут иметь разный уровень поддержки OpenAPI.
Некоторые из них могут не отображать (на данный момент) всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
Некоторые из них могут не показывать всю дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
///
Вы можете указать название query-параметра, используя параметр `title`:
Вы можете добавить `title`:
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
Добавить описание, используя параметр `description`:
И `description`:
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
## Псевдонимы параметров
Представьте, что вы хотите использовать query-параметр с названием `item-query`.
Представьте, что вы хотите, чтобы параметр был `item-query`.
Например:
Как в:
```
http://127.0.0.1:8000/items/?item-query=foobaritems
```
Но `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>.
Тогда для `Query` укажите параметр `deprecated=True`:
Затем передайте параметр `deprecated=True` в `Query`:
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
В документации это будет отображено следующим образом:
Документация будет отображать это так:
<img src="/img/tutorial/query-params-str-validations/image01.png">
## Исключить из OpenAPI
## Исключение параметров из OpenAPI
Чтобы исключить query-параметр из генерируемой OpenAPI схемы (а также из системы автоматической генерации документации), укажите в `Query` параметр `include_in_schema=False`:
Чтобы исключить query-параметр из сгенерированной схемы OpenAPI (и, следовательно, из системы автоматической документации), установите параметр `include_in_schema` для `Query` в `False`:
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Кастомная валидация
Могут быть случаи, когда вам потребуется выполнить **кастомную валидацию**, которая не может быть выполнена с показанными выше параметрами.
В таких случаях вы можете использовать **кастомную функцию валидации**, которая применяется после обычной валидации (например, после проверки что значение является `str`).
Вы можете это сделать, используя <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">Pydantic's `AfterValidator`</a> внутри `Annotated`.
/// tip | Подсказка
Pydantic также имеет <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> и другие. 🤓
///
Например, этот кастомный валидатор проверяет, что идентификатор предмета начинается с `isbn-` для номера книги ISBN или с `imdb-` для идентификатора URL-адреса фильма из IMDB:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
/// info | Дополнительная информация
Это доступно с версии Pydantic 2 и выше. 😎
///
/// tip | Подсказка
Если вам необходимо выполнить любую проверку, требующую связи с **внешним компонентом**, как например база данных или другой API, вам следует вместо этого использовать **FastAPI Dependencies**, вы узнаете о них позже.
Эти кастомные валидаторы предназначены для вещей, которые могут быть проверены с использованием **только** **тех же данных**, которые переданы в запросе.
///
### Понять этот код
Главная идея использовать **`AfterValidator` с функцией внутри `Annotated`**. Не стесняйтесь пропустить эту часть. 🤸
---
Но если вас интересует этот конкретный пример кода и вы все еще заинтересованы, вот некоторые дополнительные детали.
#### Строка с `value.startswith()`
Вы заметили? строка, использующая `value.startswith()`, может принимать кортеж, и она проверит каждое значение в кортеже:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
#### Случайный элемент
С помощью `data.items()` мы получаем <abbr title="Что-то, на чем мы можем выполнять цикл for, как список, множество и т. д.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
Мы преобразуем этот итерируемый объект в полноценный `list` с `list(data.items())`.
Затем с помощью `random.choice()` мы можем получить **случайное значение** из списка, так что мы получаем кортеж с `(id, name)`. Это будет что-то вроде `("imdb-tt0371724", "Автостопом по галактике")`.
Затем мы **присваиваем эти два значения** кортежа переменным `id` и `name`.
Таким образом, если пользователь не предоставил ID предмета, он все равно получит случайное предложение.
...все это мы делаем в **одной простой строке**. 🤯 Разве вы не любите Python? 🐍
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
## Резюме
Вы можете объявлять дополнительные правила валидации и метаданные для ваших параметров запроса.
Вы можете объявлять дополнительные валидации и метаданные для ваших параметров.
Общие метаданные:
Общие валидации и метаданные:
* `alias`
* `title`
* `description`
* `deprecated`
* `include_in_schema`
Специфичные правила валидации для строк:
Валидации, специфичные для строк:
* `min_length`
* `max_length`
* `regex`
* `pattern`
Кастомная валидация с использованием `AfterValidator`.
В рассмотренных примерах показано объявление правил валидации для строковых значений `str`.
В этих примерах вы увидели, как объявлять валидации для значений типа `str`.
В следующих главах вы увидете, как объявлять правила валидации для других типов (например, чисел).
Смотрите следующие главы, чтобы узнать, как объявлять валидации для других типов, таких как числа.

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`, например, из библиотеки <a href="https://docs.python.org/3/library/http.html#http.HTTPStatus" class="external-link" target="_blank">`http.HTTPStatus`</a> в Python.
`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 цифр как часть ответа.
У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
У этих кодов состояния есть название для их распознавания, но важной частью является число.
Кратко о значениях кодов:
Вкратце:
* `1XX` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
* **`2XX`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
* `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
* Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
* Особый случай `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
* **`3XX`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
* **`4XX`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
* Пример – код `404` для статуса "Not Found".
* Для общих ошибок со стороны клиента можно просто использовать код `400`.
* `5XX` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов.
* `100 - 199` предназначены для "Информации". Вы редко используете их напрямую. Ответы с этими кодами состояния не могут иметь тело.
* **`200 - 299`** предназначены для "Успешных" ответов. Это те, которые вы будете использовать чаще всего.
* `200` — код состояния по умолчанию, означающий, что все прошло "ОК".
* Другой пример — `201`, "Создано". Он обычно используется после создания новой записи в базе данных.
* Особый случай `204`, "Нет содержимого". Этот ответ используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
* **`300 - 399`** предназначены для "Перенаправления". Ответы с этими кодами состояния могут иметь или не иметь тело, за исключением `304`, "Не изменено", который не должен иметь тела.
* **`400 - 499`** предназначены для "Ошибки клиента". Это второй по распространенности тип использования.
* Пример `404`, для ответа "Не найдено".
* Для общих ошибок клиента можно использовать `400`.
* `500 - 599` предназначены для ошибок сервера. Вы почти никогда не используете их напрямую. Когда что-то идет не так в вашем приложении или на сервере, автоматически возвращается один из этих кодов состояния.
/// tip | Подсказка
Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank">документацией <abbr title="Mozilla Developer Network">MDN</abbr> об HTTP кодах статуса ответа</a>.
Чтобы узнать больше о каждом коде состояния и их значении, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">документацией MDN о 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 fastapi import status`.
Вы также можете использовать `from starlette import status`.
**FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.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}, вы узнаете, как возвращать другой код состояния, отличный от объявленного здесь по умолчанию.

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

@ -1,18 +1,18 @@
# 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-таблицы, а экземпляры классов представляют строки в этих таблицах.">**ORM**</abbr> библиотеками). FastAPI не принуждает вас к использованию чего-либо конкретного. 😎
Вы можете воспользоваться любой другой библиотекой для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных, нельзя сказать, что FastAPI вас вынуждает использовать что-то конкретное. 😎
///
В основе SQLModel лежит SQLAlchemy, поэтому вы спокойно можете использовать любую базу данных, поддерживаемую SQLAlchemy (и, соответственно, поддерживаемую SQLModel), например:
Поскольку SQLModel основан на SQLAlchemy, можно легко использовать **любую базу данных**, поддерживаемую SQLAlchemy (что делает их также поддерживаемыми SQLModel), такие как:
* PostgreSQL
* MySQL
@ -20,21 +20,21 @@
* Oracle
* 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 environment](../virtual-environments.md){.internal-link target=_blank}, активируйте его и установите `sqlmodel`:
Сначала убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его и затем установили `sqlmodel`:
<div class="termy">
@ -47,9 +47,9 @@ $ pip install sqlmodel
## Создание приложения с единственной моделью
Мы начнем с создания наиболее простой первой версии нашего приложения с одной единственной моделью **SQLModel**.
Мы начнем с создания самой простой, первой версии приложения с одной моделью **SQLModel**.
В дальнейшем с помощью **дополнительных моделей** мы его улучшим и сделаем более безопасным и универсальным. 🤓
Позднее мы улучшим его, повышая безопасность и универсальность, добавив **несколько моделей** ниже. 🤓
### Создание моделей
@ -57,98 +57,97 @@ $ 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` является первичным ключом в таблице базы данных (вы можете подробнее узнать о первичных ключах баз данных в документации по SQLModel).
* `Field(primary_key=True)` указывает SQLModel, что `id` является **первичным ключом** в базе данных SQL (вы можете узнать больше о первичных ключах баз данных в документации SQLModel).
Тип `int | None` сигнализирует для SQLModel, что столбец таблицы базы данных должен иметь тип `INTEGER`, или иметь пустое значение `NULL`.
Тип `int | None` говорит SQLModel, что этот столбец должен иметь тип `INTEGER` в базе данных SQL и быть `NULLABLE`.
* `Field(index=True)` для SQLModel означает, что нужно создать **SQL индекс** для данного столбца. Это обеспечит более быстрый поиск при чтении данных, отфильтрованных по данному столбцу.
* `Field(index=True)` указывает SQLModel, что для этого столбца должен быть создан SQL-индекс, который позволит ускорить поиск в базе данных при чтении данных, отфильтрованных по этому столбцу.
SQLModel будет знать, что данные типа `str`, будут представлены в базе данных как `TEXT` (или `VARCHAR`, в зависимости от типа базы данных).
SQLModel будет считать, что данные, объявленные как `str`, будут храниться в базе данных как столбец типа `TEXT` (или `VARCHAR`, в зависимости от базы данных).
### Создание соединения с базой данных (Engine)
### Создание `Engine`
В SQLModel объект соединения `engine` (по сути это `Engine` из SQLAlchemy) **содержит пул соединений** к базе данных.
Объект `engine` в SQLModel (под капотом это на самом деле `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 базу данных в различных потоках (threads). Это необходимо, когда **один запрос** использует **более одного потока** (например, в зависимостях).
Использование `check_same_thread=False` позволяет FastAPI использовать одну и ту же базу SQLite в разных потоках. Это необходимо, так как один единственный запрос может использовать более одного потока (например, в зависимостях).
Не беспокойтесь, учитывая структуру кода, мы позже позаботимся о том, чтобы использовать **отдельную 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` для каждого запроса. Это как раз и обеспечит использование одной сессии для каждого запроса. 🤓
Затем мы создадим объявленную (`Annotated`) зависимость `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**.
Точно также, вы можете использовать её при объявлении типа значения, возвращаемого функцией, и тогда структурированные данные будут отображены через пользовательский интерфейс автоматически сгенерированной документации FastAPI.
Таким же образом вы можете объявить его как **возвращаемый тип** функции, и тогда структура данных будет отображаться в автоматически созданной документации API.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
Мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их.
Здесь мы используем зависимость `SessionDep` (объект `Session`), чтобы добавить нового `Hero` в экземпляр `Session`, зафиксировать изменения в базе данных, обновить данные в `hero`, а затем вернуть их.
### Чтение данных о героях
### Чтение данных героев
Мы можем **читать** данные героев из базы данных с помощью `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов.
Мы можем **читать** героев `Hero` из базы данных, используя `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` из базы данных.
Мы также можем **удалить** героя `Hero`.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
### Запуск приложения
Вы можете запустить приложение следующим образом:
Вы можете запустить приложение:
<div class="termy">
@ -160,49 +159,49 @@ $ fastapi dev main.py
</div>
Далее перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует модели для создания документации API. Эти же модели используются для сериализации и проверки данных.
Затем перейдите в пользовательский интерфейс `/docs`, вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также использует их для **сериализации** и **проверки** данных.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image01.png">
</div>
## Добавление в приложение дополнительных (вспомогательных) моделей
## Обновление приложения с несколькими моделями
Теперь давайте проведём **рефакторинг** нашего приложения, чтобы сделать его более безопасным и более универсальным.
Теперь давайте немного **отрефакторим** приложение для повышения **безопасности** и **универсальности**.
Обратите внимание, что на данном этапе наше приложение позволяет на уровне клиента определять `id` создаваемого героя (`Hero`). 😱
Если вы посмотрите на предыдущее приложение, в пользовательском интерфейсе вы можете увидеть, что до сих пор оно позволяет клиенту определять `id` для создаваемого `Hero`. 😱
Мы не можем этого допустить, т.к. существует риск переписать уже присвоенные `id` в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда (backend)** или **на уровне базы данных**, но никак **не на уровне клиента**.
Мы не должны этого допускать, это может привести к перезаписи `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`
@ -211,25 +210,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`.
Наконец-то личность наших героев защищена! 🥷
Теперь личность наших героев защищена! 🥷
В модели `HeroPublic` также объявляется поле `id: int`. Мы как бы заключаем договоренность с API клиентом, на то, что передаваемые данные всегда должны содержать поле `id`, и это поле должно содержать целое число (и никогда не содержать `None`).
Кроме того, она снова объявляет `id: int`. Делая это, мы заключаем **контракт** с клиентами API, чтобы они всегда могли ожидать, что `id` будет там и будет `int` (никогда не будет `None`).
/// tip | Подсказка
/// tip | Совет
Модель ответа, гарантирующая наличие поля со значением типа `int` (не `None`), очень полезна при разработке API клиентов. Определенность в передаваемых данных может обеспечить написание более простого кода.
Имейте модель ответа, обеспечивающую доступность значения и всегда `int` (не `None`), это очень полезно для клиентов API. Они могут писать намного проще код, имея эту уверенность.
Также **автоматически генерируемые клиенты** будут иметь более простой интерфейс. И в результате жизнь разработчиков, использующих ваш API, станет значительно легче. 😎
Кроме того, **автоматически сгенерированные клиенты** будут иметь более простые интерфейсы, чтобы разработчикам, работающим с вашим API, было значительно легче. 😎
///
`HeroPublic` содержит все поля `HeroBase`, а также поле `id`, объявленное как `int` (не `None`):
Все поля в `HeroPublic` такие же, как и в `HeroBase`, с `id`, объявленным как `int` (не `None`):
* `id`
* `name`
@ -237,23 +236,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`
@ -261,15 +260,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`:
@ -279,59 +278,59 @@ $ fastapi dev main.py
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
### Создание героя с помощью `HeroCreate` и возвращение результатов с помощью `HeroPublic`
### Создание с помощью `HeroCreate` и возврат `HeroPublic`
Теперь, когда у нас есть дополнительные модели, мы можем обновить те части приложения, которые их используют.
Теперь, когда у нас есть **несколько моделей**, мы можем обновить те части приложения, которые их используют.
Вместе c запросом на создание героя мы получаем объект данных `HeroCreate`, и создаем на его основе объект модели таблицы `Hero`.
В запросе мы получаем *модель данных* `HeroCreate`, и из нее создаем `Hero` *модель таблицы*.
Созданный объект *модели таблицы* `Hero` будет иметь все поля, переданные клиентом, а также поле `id`, сгенерированное базой данных.
Эта новая *модель таблицы* `Hero` будет иметь поля, отправленные клиентом, и также `id`, сгенерированный базой данных.
Далее функция вернёт объект *модели таблицы* `Hero`. Но поскольку, мы объявили `HeroPublic` как модель ответа, то **FastAPI** будет использовать именно её для проверки и сериализации данных.
Затем мы возвращаем ту же *модель таблицы* `Hero` из функции. Но так как мы объявили `response_model` с *моделью данных* `HeroPublic`, **FastAPI** будет использовать `HeroPublic` для проверки и сериализации данных.
{* ../../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`, ваш редактор и linter начали бы жаловаться (и вполне справедливо), что вы возвращаете `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` с данными, переданными клиентом (т.е. **только c данными, переданными клиентом**, исключая любые значения, которые могли бы быть там только потому, что они являются значениями по умолчанию). Для того чтобы сделать это, мы воспользуемся опцией `exclude_unset=True`. В этом главная хитрость. 🪄
В коде мы получаем словарь `dict` с данными, отправленными клиентом, **только данными, отправленными клиентом**, исключаем любые значения, которые были бы там только из-за значений по умолчанию. Чтобы сделать это, используем `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] *}
### Снова запустим приложение
### Снова запустите приложение
Вы можете снова запустить приложение:
@ -345,7 +344,7 @@ $ fastapi dev main.py
</div>
Если вы перейдете в пользовательский интерфейс API `/docs`, то вы увидите, что он был обновлен, и больше не принимает параметра `id` от клиента при создании нового героя, и т.д.
Если вы зайдете в пользовательский интерфейс `/docs`, вы увидите, что он теперь обновлен, и не будет ожидать получить `id` от клиента при создании героя и т.д.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image02.png">
@ -353,6 +352,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>. 🚀

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

@ -1,71 +1,69 @@
# Виртуальная среда
# Виртуальные среды
При работе с проектами в Python рекомендуется использовать **виртуальную среду разработки** (или какой-нибудь другой подобный механизм). Это нужно для того, чтобы изолировать устанавливаемые пакеты для каждого отдельного проекта.
Когда вы работаете над проектами на Python, рекомендуется использовать **виртуальную среду** (или аналогичный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта.
/// info | Дополнительная информация
/// info | Информация
Если вы уже знакомы с виртуальными средами разработки, знаете как их создавать и использовать, то вы можете свободно пропустить данный раздел. 🤓
Если вы уже знаете о виртуальных средах, как их создавать и использовать, вы можете пропустить этот раздел. 🤓
///
/// tip | Подсказка
/// tip | Совет
**Виртуальная среда** и **переменная окружения** это две разные вещи.
**Виртуальная среда** отличается от **переменной окружения**.
**Переменная окружения** это системная переменная, которую могут использовать программы.
**Переменная окружения** это системная переменная, которую могут использовать программы.
**Виртуальная среда** это папка, содержащая файлы.
**Виртуальная среда** — это директория, содержащая некоторые файлы.
///
/// info | Дополнительная информация
/// info | Информация
В этом разделе мы научим вас пользоваться виртуальными средами разработки и расскажем, как они работают.
На этой странице вы узнаете, как использовать **виртуальные среды** и как они работают.
Если же вы готовы воспользоваться инструментом, **который умеет управлять всем, что касается Python-проектов**,
(включая установку Python), то попробуйте <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
Если вы готовы использовать **инструмент, который управляет всем** для вас (включая установку Python), попробуйте <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
///
## Создание проекта
В первую очередь, создайте директорию для вашего проекта.
Сначала создайте директорию для вашего проекта.
Я обычно создаю папку под названием `code` внутри моего домашнего каталога `/home/user`.
Обычно я создаю директорию с названием `code` внутри своего домашнего каталога.
Затем внутри данной папки я создаю отдельную директорию под каждый свой проект.
И внутри этой директории я создаю по одной директории на каждый проект.
<div class="termy">
```console
// Перейдите в домашний каталог
// Перейти в домашний каталог
$ cd
// Создайте отдельную папку под все будущие программные проекты (code)
// Создать директорию для всех проектов
$ mkdir code
// Войдите в директорию code
// Войти в эту директорию
$ cd code
// Создайте директрорию под данный проект (awesome-project)
// Создать директорию для этого проекта
$ mkdir awesome-project
// Перейдите в созданную директорию проекта
// Войти в директорию проекта
$ cd awesome-project
```
</div>
## Создание виртуальной среды разработки
## Создание виртуальной среды
Начиная работу с Python-проектом, сразу же создавайте виртуальную среду разработки
**<abbr title="есть и другие опции, но мы рассмотрим наиболее простой вариант">внутри вашего проекта</abbr>**.
Когда вы впервые начинаете работу над проектом на Python, создайте виртуальную среду **<abbr title="есть другие варианты, это простая рекомендация">внутри вашего проекта</abbr>**.
/// tip | Подсказка
/// tip | Совет
Виртуальная среда разработки создается один раз, и в дальнейшем, работая с проектом, этого больше делать не придется.
Это нужно сделать только **один раз для проекта**, а не каждый раз, когда вы работаете.
///
//// tab | `venv`
Для создания виртуальной среды вы можете воспользоваться модулем `venv`, который является частью встроенной библиотеки Python.
Для создания виртуальной среды вы можете использовать модуль `venv`, который поставляется с Python.
<div class="termy">
@ -77,10 +75,10 @@ $ python -m venv .venv
/// details | Что делает эта команда?
* `python`: использовать программу под именем `python`
* `-m`: вызывать модуль как скрипт, в следующей инструкции мы скажем какой именно модуль вызвать
* `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python
* `.venv`: создать виртуальную среду разработки в новой директории `.venv`
* `python`: используется программа под названием `python`
* `-m`: вызывает модуль как скрипт, далее укажем, какой модуль
* `venv`: используется модуль под названием `venv`, который обычно устанавливается вместе с Python
* `.venv`: создаёт виртуальную среду в новой директории `.venv`
///
@ -88,7 +86,7 @@ $ python -m venv .venv
//// tab | `uv`
Если вы установили <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, то вы можете им воспользоваться для создания виртуальной среды разработки.
Если у вас установлен <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, вы можете использовать его для создания виртуальной среды.
<div class="termy">
@ -98,31 +96,31 @@ $ uv venv
</div>
/// tip | Подсказка
/// tip | Совет
По умолчанию `uv` создаст виртуальную среду разработки в папке под названием `.venv`.
По умолчанию `uv` создаёт виртуальную среду в директории, называемой `.venv`.
Но вы можете это изменить, передав дополнительный аргумент с именем директории.
Но вы можете изменить это, добавив дополнительный аргумент с именем директории.
///
////
Данная команда создаст новую виртуальную среду разработки в папке `.venv`.
Эта команда создаёт новую виртуальную среду в директории, называемой `.venv`.
/// details | `.venv` или другое имя?
Вы можете поместить виртуальную среду разработки в папку с другим именем, но традиционным (конвенциональным) названием является `.venv` .
Вы можете создать виртуальную среду в другой директории, но существует традиция называть её `.venv`.
///
## Активация виртуальной среды разработки
## Активация виртуальной среды
Активируйте виртуальную среду разработки, и тогда любая запускаемая Python-команда или устанавливаемый пакет будут ее использовать.
Активируйте созданную виртуальную среду, чтобы любая выполняемая команда Python или устанавливаемый пакет использовали её.
/// tip | Подсказка
/// tip | Совет
При работе над проектом делайте это **каждый раз** при запуске **новой сессии в терминале**.
Делайте это **каждый раз**, когда начинаете **новую сессию терминала** для работы над проектом.
///
@ -152,7 +150,7 @@ $ .venv\Scripts\Activate.ps1
//// tab | Windows Bash
Или при использовании Bash для Windows (напр. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
Или, если вы используете Bash для Windows (например, <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
@ -164,13 +162,21 @@ $ source .venv/Scripts/activate
////
/// tip | Совет
Каждый раз при установке **нового пакета** в эту среду **активируйте** её снова.
Это гарантирует, что если вы используете **программу терминала (<abbr title="command line interface">CLI</abbr>)**, установленную этим пакетом, вы будете использовать её из вашей виртуальной среды, а не любую другую, установленную глобально, вероятно, с другой версией, чем вам нужно.
///
## Проверка активации виртуальной среды
Проверьте, активна ли виртуальная среда (удостоверимся, что предыдущая команда сработала).
Проверьте, активна ли виртуальная среда (предыдущая команда сработала).
/// tip | Подсказка
/// tip | Совет
Убедитесь в том, что все работает так, как нужно и вы используете именно ту виртуальную среду разработки, которую нужно. Делать это необязательно, но желательно.
Это **не обязательно**, но это хороший способ **убедиться**, что всё работает как ожидалось, и вы используете именно ту виртуальную среду, которую планировали.
///
@ -186,7 +192,7 @@ $ which python
</div>
Если данная команда показывает, что исполняемый файл `python` (`.venv\bin\python`), находится внутри виртуальной среды вашего проекта (у нас это `awesome-project`), значит все отработало как нужно. 🎉
Если показывает, что `python` находится в `.venv/bin/python` внутри вашего проекта (в данном случае `awesome-project`), значит, всё сработало. 🎉
////
@ -202,29 +208,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`, поэтому обновлять `pip` вам ненужно. 😎
Если вы используете <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>, то будете использовать его для установки пакетов вместо `pip`, поэтому обновлять `pip` не нужно. 😎
///
Если для установки пакетов вы используете `pip` (он устанавливается по умолчанию вместе с Python), то обновите `pip` до последней версии.
Если вы используете `pip` для установки пакетов (он по умолчанию поставляется с Python), стоит **обновить** его до последней версии.
Большинство экзотических ошибок, возникающих при установке пакетов, устраняется предварительным обновлением `pip`.
Многие экзотические ошибки при установке пакетов решаются просто обновлением `pip`.
/// tip | Подсказка
/// tip | Совет
Обычно это делается только один раз, сразу после создания виртуальной среды разработки.
Обычно это делается **один раз**, сразу после создания виртуальной среды.
///
Убедитесь в том, что виртуальная среда активирована (с помощью вышеуказанной команды) и запустите следующую команду:
Убедитесь, что виртуальная среда активирована (используя команду выше), и затем выполните:
<div class="termy">
@ -238,17 +244,17 @@ $ python -m pip install --upgrade pip
## Добавление `.gitignore`
Если вы используете **Git** (а вы должны его использовать), то добавьте файл `.gitignore` и исключите из Git всё, что находится в папке `.venv`.
Если вы используете **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 | Совет
Это делается один раз, сразу после создания виртуальной среды разработки.
Это делается **один раз**, сразу после создания виртуальной среды.
///
@ -262,13 +268,13 @@ $ echo "*" > .venv/.gitignore
/// details | Что делает эта команда?
* `echo "*"`: напечатать `*` в консоли (следующий шаг это слегка изменит)
* `>`: все что находится слева от `>` не печатать в консоль, но записать в файл находящийся справа от `>`
* `.gitignore`: имя файла, в который нужно записать текст.
* `echo "*"`: выведет текст `*` в терминал (следующий этап слегка изменит это)
* `>`: всё, что выводится в терминал командой слева от `>`, не выводится, а записывается в файл справа от `>`
* `.gitignore`: имя файла, в который следует записать текст
`*` в Git означает "всё". Т.е. будет проигнорировано всё, что содержится в папке `.venv`.
И `*` для Git означает "всё". Таким образом, он будет игнорировать всё содержимое директории `.venv`.
Данная команда создаст файл `.gitignore` следующего содержания:
Эта команда создаст файл `.gitignore` с содержимым:
```gitignore
*
@ -278,23 +284,23 @@ $ echo "*" > .venv/.gitignore
## Установка пакетов
После установки виртуальной среды, вы можете устанавливать в нее пакеты.
После активации виртуальной среды вы можете устанавливать в неё пакеты.
/// tip | Подсказка
/// tip | Совет
Сделайте это **один раз**, при установке или обновлении пакетов, нужных вашему проекту.
Делайте это **один раз** во время установки или обновления пакетов, необходимых вашему проекту.
Если вам понадобится обновить версию пакета или добавить новый пакет, то вы должны будете **сделать это снова**.
Если вам нужно обновить версию или добавить новый пакет, вы должны будете **сделать это снова**.
///
### Установка пакетов напрямую
Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, то вы можете установить их напрямую.
Если вы торопитесь и не хотите объявлять зависимости проекта в файле, вы можете установить их напрямую.
/// tip | Подсказка
/// tip | Совет
Объявление пакетов, которые использует ваш проект, и их версий в отдельном файле (например, в `requirements.txt` или в `pyproject.toml`) - это отличная идея.
Очень желательно объявлять пакеты и их версии, которые ваш проект использует, в отдельном файле (например, `requirements.txt` или `pyproject.toml`).
///
@ -314,7 +320,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">
@ -329,7 +335,7 @@ $ uv pip install "fastapi[standard]"
### Установка из `requirements.txt`
Если у вас есть `requirements.txt`, то вы можете использовать его для установки пакетов.
Если у вас есть `requirements.txt`, вы можете использовать его для установки пакетов.
//// tab | `pip`
@ -346,7 +352,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">
@ -361,7 +367,7 @@ $ uv pip install -r requirements.txt
/// details | `requirements.txt`
`requirements.txt` с парочкой пакетов внутри выглядит приблизительно так:
Файл `requirements.txt` с несколькими пакетами может выглядеть так:
```requirements.txt
fastapi[standard]==0.113.0
@ -372,7 +378,7 @@ pydantic==2.8.0
## Запуск программы
После активации виртуальной среды разработки вы можете запустить свою программу и она будет использовать версию Python и пакеты, установленные в виртуальной среде.
После активации виртуальной среды вы можете запустить свою программу, и она будет использовать Python внутри вашей виртуальной среды с установленными там пакетами.
<div class="termy">
@ -386,22 +392,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">
@ -411,55 +417,55 @@ $ deactivate
</div>
Таким образом, при запуске `python`, будет использована версия `python` установленная глобально, а не из этой виртуальной среды вместе с установленными в ней пакетами.
Таким образом, при запуске `python`, он не будет использовать версию из этой виртуальной среды с установленными там пакетами.
## Все готово к работе
## Готовность к работе
Теперь вы готовы к тому, чтобы начать работу над своим проектом.
Теперь вы готовы приступить к работе над своим проектом.
/// tip | Подсказка
/// tip | Совет
Хотите разобраться со всем, что написано выше?
Хотите понять всё, что написано выше?
Продолжайте читать. 👇🤓
Продолжайте чтение. 👇🤓
///
## Зачем использовать виртуальную среду?
## Зачем виртуальные среды
Для работы с FastAPI вам потребуется установить <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>.
Для работы с FastAPI вам нужно установить <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>.
После этого вам нужно будет **установить** FastAPI и другие **пакеты**, которые вы собираетесь использовать.
После этого вам потребуется установить FastAPI и другие необходимые **пакеты**.
Для установки пакетов обычно используют `pip`, который устанавливается вместе с Python (или же используют альтернативные решения).
Чтобы установить пакеты, вы обычно используете команду `pip`, которая идет в комплекте с Python (либо аналогичные альтернативы).
Тем не менее, если вы просто используете `pip` напрямую, то пакеты будут установлены в **глобальное Python-окружение** (глобально установленный Python).
Тем не менее, если вы просто используете `pip` напрямую, пакеты будут устанавливаться в ваш **глобальный Python-окружение** (глобальная установка Python).
### Проблема
Так в чем же проблема с установкой пакетов в глобальную среду Python?
Так в чём проблема установки пакетов в глобальную среду Python?
В какой-то момент вам, вероятно, придется писать множество разных программ, которые используют различные пакеты. 😱
В какой-то момент вы вероятно напишете множество различных программ, зависящих от **разных пакетов**. Некоторые из этих проектов будут зависеть от **разных версий** одного и того же пакета. 😱
Например, вы создаете проект `philosophers-stone`, который зависит от пакета под названием **`harry`, версии `1`**. Таким образом, вам нужно установить `harry`.
Например, вы могли бы создать проект, называемый `philosophers-stone`, который зависит от другого пакета **`harry`, используя версию `1`**. По этому вам нужно установить `harry`.
```mermaid
flowchart LR
stone(philosophers-stone) -->|requires| harry-1[harry v1]
```
Затем, в какой-то момент, вы создаете другой проект под названием `prisoner-of-azkaban`, и этот проект тоже зависит от `harry`, но он уже использует **`harry` версии `3`**.
Затем, в какой-то момент позже, вы создаёте другой проект, называемый `prisoner-of-azkaban`, и этот проект тоже зависит от `harry`, но ему нужна версия **`harry` `3`**.
```mermaid
flowchart LR
azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
```
Проблема заключается в том, что при установке в глобальное окружение, а не в локальную виртуальную среду разработки, вам нужно будет выбирать, какую версию пакета `harry` устанавливать.
Но теперь проблема в том, если вы устанавливаете пакеты глобально (в глобальной среде) вместо локальной **виртуальной среды**, вы должны выбрать, какую версию `harry` установить.
Если вам нужен `philosophers-stone`, то вам нужно сначала установить `harry` версии `1`:
Если вы хотите запустить `philosophers-stone`, вы должны сначала установить `harry` версии `1`, например, с помощью:
<div class="termy">
@ -469,7 +475,7 @@ $ pip install "harry==1"
</div>
И тогда в вашем глобальном окружении Python будет установлен `harry` версии `1`:
И в итоге у вас установлена `harry` версии `1` в глобальной среде Python.
```mermaid
flowchart LR
@ -481,7 +487,7 @@ flowchart LR
end
```
Но если позднее вы захотите запустить `prisoner-of-azkaban`, то вам нужно будет удалить `harry` версии 1, и установить `harry` версии `3` (при установке пакета версии `3` поверх пакета версии `1`, пакет версии `1` удаляется автоматически).
Но затем, если вы хотите запустить `prisoner-of-azkaban`, вы должны удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`).
<div class="termy">
@ -491,9 +497,9 @@ $ pip install "harry==3"
</div>
И тогда, в вашей глобальной среде окружения Python, будет установлен пакет `harry` версии `3`.
И вы получили `harry` версии `3`, установленный в вашей глобальной среде Python.
И когда вы снова попытаетесь запустить `philosophers-stone`, то существует вероятность того, что он не будет работать, так как он использует `harry` версии `1`.
И если вы попробуете снова запустить `philosophers-stone`, то есть вероятность, что он **не будет работать**, так как зависит от `harry` версии `1`.
```mermaid
flowchart LR
@ -510,49 +516,49 @@ flowchart LR
end
```
/// tip | Подсказка
/// tip | Совет
В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новые версии, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно.
В Python-пакетах обычно стараются изо всех сил **избегать критических изменений** в **новых версиях**, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, работает ли всё правильно.
///
Теперь представьте, что это происходит со многими другими пакетами, которые используются в ваших проектах. С этим очень сложно справиться. И скорее всего, в конечном итоге вы будете запускать некоторые проекты с некоторыми несовместимыми зависимостями и не будете знать, почему что-то не работает.
Теперь представьте, что это происходит с **многими** другим пакеты, от которых зависят все ваши **проекты**. С этим очень сложно справиться. И вы, вероятно, в конечном итоге запустите некоторые проекты с некоторыми **несовместимыми версиями** пакетов и не будете знать, почему что-то не работает.
Кроме того, в зависимости от вашей операционной системы (напр. Linux, Windows, macOS), она может поставляться с уже установленным Python. Вероятно, что в этом случае в ней уже установлены системные пакеты определенных версий. Если вы устанавливаете пакеты глобально, то вы можете **поломать** программы, являющиеся частью ОС.
Кроме того, в зависимости от вашей операционной системы (например, Linux, Windows, macOS), она могла поставляться с уже установленным Python. И в этом случае она вероятно имела некоторые пакеты, предварительно установленные с определёнными версиями, **необходимыми вашей системой**. Если вы устанавливаете пакеты в глобальную среду Python, вы можете в итоге **сломать** некоторые программы, которые были полностью частью вашей операционной системы.
## Куда устанавливаются пакеты?
## Где устанавливаются пакеты
Когда вы устанавливаете Python, то на вашей машине создается некоторое количество директорий, содержащих некоторое количество файлов.
Когда вы устанавливаете Python, это создаёт на вашем компьютере некоторые каталоги с некоторыми файлами.
Среди них есть каталоги, отвечающие за хранение всех устанавливаемых вами пакетов.
Некоторые из этих каталогов являются теми, которые хранят все установленные вами пакеты.
Когда вы запустите команду:
Когда вы запускаете:
<div class="termy">
```console
// Не запускайте эту команду, это просто пример 🤓
// Не запускайте это сейчас, это лишь пример 🤓
$ pip install "fastapi[standard]"
---> 100%
```
</div>
То будет скачан сжатый файл, содержащий код FastAPI, обычно скачивание происходит с <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>.
Это загрузит сжатый файл с кодом FastAPI, обычно с <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>.
Также будут скачаны файлы, содержащие пакеты, которые использует FastAPI.
Он также **загрузит** файлы для других пакетов, от которых зависит FastAPI.
Затем все файлы будут извлечены и помещены в директорию на вашем компьютере.
Затем он **извлечёт** все эти файлы и поместит их в директорию на вашем компьютере.
По умолчанию эти файлы будут загружены и извлечены в один из каталогов установки Python, т.е. в глобальную среду.
По умолчанию, он сохранит загруженные и извлечённые файлы в директории, которая идёт в комплекте с вашей установкой Python, то есть в **глобальной среде**.
## Что такое виртуальная среда разработки?
## Что такое виртуальные среды
Решением проблемы размещения всех пакетов в глобальной среде будет использование отдельной виртуальной среды под каждый проект, над которым вы работаете.
Решением проблем использования всех пакетов в глобальной среде является использование **виртуальной среды для каждого проекта**, над которым вы работаете.
Виртуальная среда это обычная папка, очень похожая на глобальную, куда вы можете устанавливать пакеты для вашего проекта.
Виртуальная среда — это **директория**, очень похожая на глобальную, в которой вы можете устанавливать пакеты для конкретного проекта.
Таким образом, каждый проект будет иметь свою отдельную виртуальную среду разработки (в директории `.venv`) вместе со своими пакетами.
Таким образом, каждый проект будет иметь собственную виртуальную среду (`.venv` директории) со своими пакетами.
```mermaid
flowchart TB
@ -571,9 +577,9 @@ flowchart TB
stone-project ~~~ azkaban-project
```
## Что означает активация виртуальной среды?
## Что означает активация виртуальной среды
Когда вы активируете виртуальную среду разработки, например, так:
Когда вы активируете виртуальную среду, например, используя:
//// tab | Linux, macOS
@ -601,7 +607,7 @@ $ .venv\Scripts\Activate.ps1
//// tab | Windows Bash
Или если вы воспользуетесь Bash под Windows (напр. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
Или, если вы используете Bash для Windows (например, <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
@ -613,20 +619,19 @@ $ source .venv/Scripts/activate
////
Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд.
Одной из таких переменных является `PATH`.
Одна из этих переменных — это переменная `PATH`.
/// tip | Подсказка
/// tip | Совет
Вы можете узнать больше о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
///
При активации виртуальной среды путь `.venv/bin` (для Linux и macOS) или `.venv\Scripts` (для Windows) добавляется в переменную окружения `PATH`.
Активация виртуальной среды добавляет её путь `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) в переменную окружения `PATH`.
Предположим, что до активации виртуальной среды переменная `PATH` выглядела так:
Предположим, что до активации среды переменная `PATH` выглядела так:
//// tab | Linux, macOS
@ -634,7 +639,7 @@ $ source .venv/Scripts/activate
/usr/bin:/bin:/usr/sbin:/sbin
```
Это означает, что система ищет программы в следующих каталогах:
Это означает, что система будет искать программы в:
* `/usr/bin`
* `/bin`
@ -649,13 +654,13 @@ $ source .venv/Scripts/activate
C:\Windows\System32
```
Это означает, что система ищет программы в:
Это означает, что система будет искать программы в:
* `C:\Windows\System32`
////
После активации виртуальной среды переменная окружение `PATH` будет выглядеть примерно так:
После активации виртуальной среды переменная `PATH` будет выглядеть примерно так:
//// tab | Linux, macOS
@ -663,21 +668,21 @@ C:\Windows\System32
/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
Это означает, что система теперь будет искать программы в:
Это означает, что система теперь начнёт искать программы сначала в:
```plaintext
/home/user/code/awesome-project/.venv/bin
```
прежде чем начать искать в других каталогах.
прежде чем искать в других каталогах.
Таким образом, когда вы введете в консоль `python`, система будет искать Python в
Таким образом, когда вы вводите в терминале `python`, система найдёт программу Python в
```plaintext
/home/user/code/awesome-project/.venv/bin/python
```
и будет использовать именно его.
и будет использовать её.
////
@ -687,31 +692,31 @@ C:\Windows\System32
C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
```
Это означает, что система в первую очередь начнет искать программы в:
Это означает, что система теперь начнёт искать программы сначала в:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts
```
прежде чем начать искать в других директориях.
прежде чем искать в других каталогах.
Таким образом, если вы введете в консоль команду `python`, то система найдет Python в:
Таким образом, когда вы вводите в терминале `python`, система найдёт программу Python в
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
и использует его.
и будет использовать её.
////
Очень важной деталью является то, что путь к виртуальной среде будет помещен в самое начало переменной `PATH`. Система обнаружит данный путь к Python раньше, чем какой-либо другой. Таким образом, при запуске команды `python`, будет использован именно Python из виртуальной среды разработки, а не какой-нибудь другой (например, Python из глобальной среды)
Важной деталью является то, что путь к виртуальной среде будет помещён в **начало** переменной `PATH`. Система найдёт его **до** того, как найдёт какой-либо другой Python. Таким образом, при запуске команды `python` будет использоваться Python **из виртуальной среды**, а не любой другой `python` (например, `python` из глобальной среды).
Активация виртуальной среды разработки также меняет и несколько других вещей, но данная функция является основной.
Активация виртуальной среды также изменяет несколько других вещей, но это одна из самых важных функцией.
## Проверка виртуальной среды
Когда вы проверяете активна ли виртуальная среда разработки, например, так:
Когда вы проверяете, активна ли виртуальная среда, например, используя:
//// tab | Linux, macOS, Windows Bash
@ -741,31 +746,31 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
////
Это означает, что будет использоваться `python` **из виртуальной среды разработки**.
Это означает, что программа `python`, которая будет использоваться, это та, что находится **в виртуальной среде**.
Вы используете `which` для Linux и macOS и `Get-Command` для Windows PowerShell.
Вы используете `which` на Linux и macOS и `Get-Command` на Windows PowerShell.
Эта команда работает следующим образом: она проверяет переменную окружения `PATH`, проходя по очереди каждый указанный путь в поисках программы под названием `python`. И когда она её находит, то возвращает путь к данной программе.
Команда работает следующим образом: она проходит через переменную окружения `PATH`, проходя **каждый путь в порядке** поиска программы под названием `python`. После того, как она найдёт её, она **отобразит путь** к этой программе.
Основной момент при вызове команды `python` состоит в том, какой именно "`python`" будет запущен.
Самая важная часть заключается в том, что когда вы вызываете `python`, это та самая программа "`python`", которая будет выполнена.
Таким образом, вы можете убедиться, что используете правильную виртуальную среду разработки.
Таким образом, вы можете убедиться, что находитесь в правильной виртуальной среде.
/// tip | Подсказка
/// tip | Совет
Легко активировать одну виртуальную среду, вызвать один Python и **перейти к следующему проекту**.
Легко активировать одну виртуальную среду, получить один Python, а затем **перейти к другому проекту**.
И следующий проект не будет работать потому, что вы используете **неправильный Python** из виртуальной среды другого проекта.
И второй проект **не будет работать**, потому что вы используете **неправильный Python** из виртуальной среды для другого проекта.
Так что, будет нелишним проверить, какой `python` вы используете. 🤓
Полезно иметь возможность проверять, какой `python` используется. 🤓
///
## Зачем деактивируют виртуальную среду?
## Зачем деактивировать виртуальную среду
Предположим, что вы работаете над проектом `philosophers-stone`, **активируете виртуальную среду разработки**, устанавливаете пакеты и работаете с данной средой.
Например, вы можете работать над проектом `philosophers-stone`, **активируя эту виртуальную среду**, устанавливая пакеты и работая в этой среде.
И позже вам понадобилось поработать с **другим проектом** `prisoner-of-azkaban`.
А затем вы хотите работать над **другим проектом** `prisoner-of-azkaban`.
Вы переходите к этому проекту:
@ -777,7 +782,7 @@ $ cd ~/code/prisoner-of-azkaban
</div>
Если вы не деактивировали виртуальное окружение проекта `philosophers-stone`, то при запуске `python` через консоль будет вызван Python из `philosophers-stone`
Если вы не деактивируете виртуальную среду для `philosophers-stone`, то когда вы запускаете `python` в терминале, он попытается использовать Python из `philosophers-stone`.
<div class="termy">
@ -786,7 +791,7 @@ $ cd ~/code/prisoner-of-azkaban
$ python main.py
// Error importing sirius, it's not installed 😱
// Ошибка при импорте sirius, он не установлен 😱
Traceback (most recent call last):
File "main.py", line 1, in <module>
import sirius
@ -794,46 +799,46 @@ Traceback (most recent call last):
</div>
Но если вы деактивируете виртуальную среду разработки и активируете новую среду для `prisoner-of-askaban`, то вы тогда запустите Python из виртуального окружения `prisoner-of-azkaban`.
Но если вы деактивируете виртуальную среду и активируете новую для `prisoner-of-askaban`, то когда вы запускаете `python`, он будет использоваться Python из виртуальной среды в проекте `prisoner-of-azkaban`.
<div class="termy">
```console
$ cd ~/code/prisoner-of-azkaban
// Вам не требуется находится в старой директории для деактивации среды разработки, вы можете это сделать откуда угодно, даже из каталога другого проекта, в который вы перешли. 😎
// Вам не нужно находиться в старой директории для деактивации, вы можете сделать это из любого места, даже после перехода к другому проекту 😎
$ deactivate
// Активируйте виртуальную среду разработки в prisoner-of-azkaban/.venv 🚀
// Активируйте виртуальную среду в `prisoner-of-azkaban/.venv` 🚀
$ source .venv/bin/activate
// Тепреь, когда вы запустите python, он найдет пакет sirius, установленный в виртуальной среде ✨
// Теперь, когда вы запускаете python, он найдёт пакет sirius, установленный в этой виртуальной среде ✨
$ python main.py
Я торжественно клянусь в этом! 🐺
Я торжественно клянусь 🐺
```
</div>
## Альтернативы
Это простое руководство поможет вам начать работу и научит тому, как всё работает **изнутри**.
Это простое руководство поможет вам начать работу и научит тому, как всё работает **внутри**.
Существует много альтернативных решений для работы с виртуальными средами разработки, с программными зависимостями, а также с проектами.
Существуют также **альтернативные** решения для управления виртуальными средами разработки, зависимостями пакетов (требования), проектами.
Когда вы будете готовы использовать единый инструмент для управления проектом, программными зависимостями, виртуальными средами разработки и т.д., то я рекомендую вам попробовать <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
Когда вы будете готовы и захотите использовать инструмент для **управления всем проектом**, зависимостями пакетов, виртуальными средами и т.д., я бы рекомендовал вам попробовать <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>.
`uv` может очень многое. Он умеет:
`uv` может делать много всего, он может:
* **Устанавливать Python**, включая установку различных версий
* Управлять средой виртуального окружения вашего проекта
* **Установить Python** для вас, включая разные версии
* Управлять **виртуальной средой** для ваших проектов
* Устанавливать **пакеты**
* Управлять пакетами и их версиями внутри вашего проекта
* Удостовериться, что вы используете **точный** набор пакетов и версий при установке, включая зависимости. Таким образом, вы можете быть уверенны, что проект, запускается в production, точно также, как и при разработке, этот механизм называется *locking*
* Многие другие вещи
* Управлять зависимостями пакетов **и версиями** для вашего проекта
* Обеспечить наличие **точного** набора пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что ваш проект будет работать в production точно так же, как и на вашем компьютере во время разработки, это называется *locking*
* И многое другое
## Заключение
Если вы прочитали и поняли всё это, то теперь вы знаете **гораздо больше** о виртуальных средах разработки, чем многие другие разработчики. 🤓
Если вы прочитали и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных средах, чем многие другие разработчики. 🤓
Скорее всего, знание этих деталей будет полезно вам в будущем. Когда вы будете отлаживать что-то, кажущееся сложным, вы будете знать, **как это работает под капотом**. 😎
Знание этих деталей, скорее всего, будет полезно вам в будущем, когда вы будете отлаживать что-то, что кажется сложным, но вы будете знать, **как всё работает внутри**. 😎

Loading…
Cancel
Save