From 634e54aa749a0ef7017a6947b9942164243b3cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 27 Jul 2025 12:30:02 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=8C=90Update=20Russian=20translations?= =?UTF-8?q?=20that=20were=20changed=20after=20the=20last=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ru/docs/async.md | 445 ++++++++---------- docs/ru/docs/benchmarks.md | 45 +- docs/ru/docs/deployment/manually.md | 176 ++++--- docs/ru/docs/help-fastapi.md | 255 +++++----- docs/ru/docs/index.md | 266 ++++++----- docs/ru/docs/project-generation.md | 112 ++--- docs/ru/docs/tutorial/body-multiple-params.md | 72 +-- docs/ru/docs/tutorial/cors.md | 67 +-- docs/ru/docs/tutorial/extra-models.md | 96 ++-- docs/ru/docs/tutorial/first-steps.md | 242 +++++----- docs/ru/docs/tutorial/handling-errors.md | 14 +- docs/ru/docs/tutorial/index.md | 88 ++-- docs/ru/docs/tutorial/middleware.md | 87 ++-- .../tutorial/query-params-str-validations.md | 370 ++++++++------- docs/ru/docs/tutorial/response-status-code.md | 72 +-- docs/ru/docs/tutorial/sql-databases.md | 221 +++++---- docs/ru/docs/virtual-environments.md | 345 +++++++------- 17 files changed, 1468 insertions(+), 1505 deletions(-) diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md index 6c5d982df..1f467f646 100644 --- a/docs/ru/docs/async.md +++ b/docs/ru/docs/async.md @@ -1,18 +1,18 @@ # Конкурентность и async / await -Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций обработки пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма. +Подробности о синтаксисе `async def` для *функций обработки пути* и некоторые сведения об асинхронном коде, конкурентности и параллелизме. -## Нет времени? +## В спешке? -TL;DR: +TL;DR: -Допустим, вы используете сторонюю библиотеку, которая требует вызова с ключевым словом `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(): ## Асинхронный код -Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖, -что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝. +Асинхронный код просто значит, что язык 💬 имеет способ сообщить компьютеру / программе 🤖, что в какой-то момент в коде, ему 🤖 нужно будет дождаться, пока *что-то ещё* завершится где-то ещё. Пусть это *что-то ещё* называется "медленный файл" 📝. -И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач. +Так что, в это время, компьютер может выполнять какую-то другую работу, пока "медленный файл" 📝 заканчивается. -Но при каждой возможности компьютер / программа 🤖 будет возвращаться обратно. Например, если он 🤖 опять окажется в режиме ожидания, или когда закончит всю работу. В этом случае компьютер 🤖 проверяет, не завершена ли какая-нибудь из текущих задач. +Потом компьютер / программа 🤖 будет возвращаться каждый раз, когда у него будет шанс, потому что он снова ждет, или когда он 🤖 закончит всю работу, которую у него была к тому моменту. И он 🤖 проверит, не завершилась ли какая-либо из задач, чтобы выполнить то, что нужно. -Потом он 🤖 берёт первую выполненную задачу (допустим, наш "медленный файл" 📝) и продолжает работу, производя с ней необходимые действия. +Затем он 🤖 берёт первую задачу, которая завершилась (например, наш "медленный файл" 📝) и продолжает выполнение того, что ему надо было сделать. -Вышеупомянутое "что-то ещё", завершения которого приходится ожидать, обычно относится к достаточно "медленным" операциям I/O (по сравнению со скоростью работы процессора и оперативной памяти), например: +Этот "ожидать чего-то ещё" обычно относится к операциям I/O, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например: -* отправка данных от клиента по сети -* получение клиентом данных, отправленных вашей программой по сети -* чтение системой содержимого файла с диска и передача этих данных программе -* запись на диск данных, которые программа передала системе -* обращение к удалённому API +* ожидание данных от клиента, отправленных через сеть +* ожидание, когда данные, отправленные программой, будут получены клиентом через сеть +* ожидание, когда содержимое файла на диске будет прочитано системой и передано вашей программе +* ожидание, когда данные, которые ваша программа передала системе, будут записаны на диск +* удалённая операция API * ожидание завершения операции с базой данных -* получение результатов запроса к базе данных +* ожидание, когда запрос к базе данных вернёт результаты * и т. д. -Поскольку в основном время тратится на ожидание выполнения операций I/O, -их обычно называют операциями, ограниченными скоростью ввода-вывода. +Поскольку основное время выполнения тратится на ожидание операций I/O, их называют операциями, "связанными с вводом-выводом" (I/O bound). -Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и, -будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу. +Это называется "асинхронным", потому что компьютер / программе не нужно "синхронизироваться" с медленной задачей и ожидать момент, когда задача завершится, ничего не делая, чтобы затем взять результат задачи и продолжить работу. -Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд), -пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться, -забрать результаты выполнения и начать их обрабатывать. +Вместо этого, в "асинхронной" системе завершённая задача может чуть-чуть подождать (несколько микросекунд), пока компьютер / программа завершит выполнение того, что она занималась, а потом вернуться, чтобы взять результаты и продолжить их обработку. -"Синхронное" исполнение (в противовес "асинхронному") также называют "последовательным", -потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче, -даже если в процессе приходится ждать. +Для "синхронного" (в отличие от "асинхронного") часто используют термин "последовательный", потому что компьютер / программа проходит все шаги последовательно перед переключением на другую задачу, даже если они включают в себя ожидание. ### Конкурентность и бургеры -Тот **асинхронный** код, о котором идёт речь выше, иногда называют **"конкурентностью"**. Она отличается от **"параллелизма"**. +Эту идею **асинхронного** кода, описанную выше, иногда также называют **"конкурентностью"**. Это отличается от **"параллелизма"**. -Да, **конкурентность** и **параллелизм** подразумевают, что разные вещи происходят примерно в одно время. +**Конкурентность** и **параллелизм** оба подразумевают, что "разные вещи происходят более или менее в одно время". -Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное. +Но детали между *конкурентностью* и *параллелизмом* достаточно разные. -Чтобы это понять, представьте такую картину: +Чтобы увидеть разницу, представьте следующую историю о бургерах: ### Конкурентные бургеры - +Вы идёте с вашей возлюбленной в фастфуд, становитесь в очередь, пока кассир принимает заказы у людей перед вами. 😍 -Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами. + -Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе. +Затем наступает ваша очередь, вы заказываете 2 очень вкусных бургеров для вашей возлюбленной и для вас. 🍔🍔 -Отдаёте деньги 💸. + -Кассир 💁 что-то говорит поварам на кухне 👨‍🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔 -(но пока они заняты бургерами предыдущих клиентов). +Кассир что-то говорит повару на кухне, чтобы они знали, что надо приготовить ваши бургеры (даже если они в данный момент готовят бургеры для предыдущих клиентов). -Кассир 💁 отдаёт вам чек с номером заказа. + -В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍 -(поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨). +Вы платите. 💸 -Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время, -восхищаясь её великолепием, красотой и умом ✨😍✨. +Кассир даёт вам номер вашего заказа. -Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете, -какой номер горит над прилавком, и не подошла ли уже ваша очередь. + -И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик. +В ожидании еды, вы идёте с вашей возлюбленной выбрать столик, садитесь и долго разговариваете с вашей возлюбленной (поскольку ваши бургеры очень вкусные и их приготовление занимает некоторое время). -Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨. +Сидя за столиком с вашей возлюбленной, пока вы ждёте бургеры, вы тратите это время, чтобы восхищаться тем, насколько ваша возлюбленная замечательная, милая и умная ✨😍✨. + + + +Во время ожидания и разговора с вашей возлюбленной время от времени вы проверяете номер, отображаемый на стойке, чтобы увидеть, не наступило ли ваше ожидание. + +Затем в какой-то момент это наконец ваша очередь. Вы идёте к стойке, забираете свои бургеры и возвращаетесь к столу. + + + +Вы и ваша возлюбленная едите бургеры и наслаждаетесь временем вместе. ✨ + + + +/// info | Информация + +Прекрасные иллюстрации от Кетрины Томпсон. 🎨 + +/// --- -А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖. +Представьте, что в этой истории вы — компьютер / программа 🤖. -В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете. -Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного. +В очереди вы бездействуете 😴, ожидая своей очереди, особо ничего "продуктивного" не делая. Но очередь быстро движется, так как кассир только берёт заказы (а не готовит их), так что это нормально. -Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д. +Затем, когда наступает ваша очередь, вы делаете настоящую "продуктивную" работу, обрабатываете меню, решаете, что хотите, узнаёте выбор вашей возлюбленной, оплачиваете, проверяете, что даёте правильную сумму или карту, проверяете, правильно ли с вас взяли оплату, содержится ли в заказе всё, что нужно, и так далее. -И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸, -поскольку теперь нужно ждать 🕙, когда заказ приготовят. +Но потом, хотя вы всё еще не получили свои бургеры, ваша работа с кассиром "на паузе" ⏸, потому что вы должны ждать 🕙, пока приготовятся ваши бургеры. -Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание -на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень -"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍. +Но уходя от стойки и садясь за столик с номером вашего заказа, вы можете переключить 🔀 своё внимание на свою возлюбленную, и "работать" ⏯ 🤓 над этим. Таким образом, вы снова делаете что-то очень "продуктивное", как флирт с вашей возлюбленной 😍. -В какой-то момент кассир 💁 поместит на табло ваш номер, подразумевая, что бургеры готовы 🍔, но вы не станете подскакивать как умалишённый, лишь только увидев на экране свою очередь. Вы уверены, что ваши бургеры 🍔 никто не утащит, ведь у вас свой номерок, а у других свой. +Кассир 💁 говорит "я закончил делать бургеры" через показ номера вашего заказа на табло, но вы не вскакиваете, как сумасшедший, когда отображаемый номер меняется на номер вашей очереди. Вы знаете, что никто не украдёт у вас бургеры, потому что у вас есть номер вашего заказа, а у других — свои. -Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓), -и мило улыбнувшись, скажете, что идёте забирать заказ ⏸. +Поэтому вы ждёте, пока ваша возлюбленная закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓), мило улыбаетесь и говорите, что идёте забирать бургеры ⏸. -И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹. -В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹. +Затем вы идёте к стойке 🔀, к первоначальной задаче, которая завершена ⏯, берете бургеры, говорите спасибо и возвращаетесь за столик. Это завершает эту часть / задание взаимодействия с кассиром ⏹. Это, в свою очередь, создаёт новую задачу — "есть бургеры" 🔀 ⏯, но предыдущая — "получить бургеры" завершена ⏹. ### Параллельные бургеры -Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры". +Теперь представим, что это не "Конкурентные бургеры", а "Параллельные бургеры". -И вот вы идёте со своей возлюбленной 😍 отведать параллельного фастфуда 🍔. +Вы идёте с вашей возлюбленной попробовать параллельный фастфуд. -Вы становитесь в очередь пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами. +Вы стоите в очереди, пока несколько (скажем, 8) кассиров, которые одновременно являются поварами, принимают заказы у людей перед вами. -При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый -из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ. +Все перед вами ожидают, когда их бургеры будут готовы до того, как они покинут кассу, поскольку каждый из 8 кассиров сразу идет и готовит бургер, прежде чем получить следующий заказ. -Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе. + -Ни о чём не жалея, расплачиваетесь 💸. +Затем, наконец, наступает ваша очередь, вы заказываете 2 очень вкусных бургера для вашей возлюбленной и вас. -И кассир уходит на кухню 👨‍🍳. +Вы оплачиваете 💸. -Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет. + -Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь, -у вас не получается уделять должного внимание своей даме сердца 😞. +Кассир идёт на кухню. -Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки, -когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой. +Вы ждёте, стоя перед прилавком 🕙, чтобы никто не забрал ваши бургеры перед вами, так как номеров заказа нет. -Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой. + -Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик. +Поскольку вы и ваша возлюбленная заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они прибудут, вы не можете уделить внимания вашей возлюбленной. 😞 -Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹. +Это "синхронная" работа: вы "синхронизированы" с кассиром/поваром 👨‍🍳. Вам приходится ждать 🕙 и быть там в точный момент, когда кассир/повар 👨‍🍳 завершает приготовление бургеров и отдаёт их вам, иначе кто-то может их взять. -Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞. + ---- +Затем ваш кассир/повар 👨‍🍳 наконец возвращается с вашими бургерами, после долгого ожидания 🕙 перед стойкой. -В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍), -на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе". + -В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. -Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳. +Вы берёте ваши бургеры и идёте за столик с вашей возлюбленной. -Несмотря на обилие работников, опыт в итоге получился не из лучших 😞. +Вы их просто кушаете, и всё. ⏹ + + + +Обменяться словами или пофлиртовать не очень получилось, так как больше времени было потрачено на ожидание 🕙 перед стойкой. 😞 + +/// info | Информация + +Прекрасные иллюстрации от Кетрины Томпсон. 🎨 + +/// --- -Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире. +В этом сценарии с параллельными бургерами вы — это компьютер / программа 🤖 с двумя процессорами (вы и ваша возлюбленная), оба долгое время ожидающие 🕙 и посвящающие своё внимание ⏯ быть "ожидающими у кассы" 🕙. + +В этом фастфуд-магазине 8 процессоров (кассиров/поваров). Хотя в магазине конкурентных бургеров могло быть только 2 (один кассир и один повар). -Вот более реалистичный пример. Представьте себе банк. +Но всё же, окончательный опыт не самый лучший. 😞 -До недавних пор в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙. +--- -Каждый кассир обслуживал одного клиента, потом следующего 👨‍💼⏯. +Это была бы параллельная аналогичная история для бургеров. 🍔 -Нужно было долгое время 🕙 стоять перед окошком вместе со всеми, иначе пропустишь свою очередь. +Для более "реального" примера этого, представьте банк. -Сомневаюсь, что у вас бы возникло желание прийти с возлюбленной 😍 в банк 🏦 оплачивать налоги. +До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинная очередь 🕙🕙🕙🕙🕙🕙🕙🕙. -### Выводы о бургерах +Все кассиры занимались каждым клиентом один за другим 👨‍💼⏯. -В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙, -поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯. +И вам долгое время приходилось ждать 🕙 в очереди, иначе потеряете свою очередь. -И то же самое с большинством веб-приложений. +Скорее всего, вам бы не захотелось брать вашу возлюбленную 😍 с собой для быстрого похода в банк 🏦. -Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению. +### Заключение о бургерах -Потом снова ждать 🕙, пока вернётся ответ. +В этом сценарии "быстрого питания с бургерами с вашей возлюбленной", так как там много ожидания 🕙, имеет много больше смысла иметь конкурентную систему ⏸🔀⏯. - -Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени. +И это и есть случай для большинства веб-приложений. -Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API. +Много, много пользователей, но ваш сервер ожидает 🕙, чтобы они отправили свои запросы через своё не очень хорошее соединение. -Большинство популярных фреймворков (включая Flask и Django) создавались -до появления в Python новых возможностей асинхронного программирования. Поэтому -их можно разворачивать с поддержкой параллельного исполнения или асинхронного -программирования старого типа, которое не настолько эффективно. +И потом снова ждёт 🕙, чтобы ответы вернулись. -При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером -(ASGI) -была разработана командой Django для внедрения поддержки веб-сокетов. +Это "ожидание" 🕙 измеряется в микросекундах, но в итоге, если всё сложить, это много времени ожидания. -Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный), -и в этом преимущество Go как языка программирования. +Вот почему имеет смысл использовать асинхронный код ⏸🔀⏯ для веб-API. -И тот же уровень производительности даёт **FastAPI**. +Эта форма асинхронности является тем, что сделало NodeJS популярным (хотя NodeJS не параллелен) и это то, что делает Go мощным языком программирования. -Поскольку можно использовать преимущества параллелизма и асинхронности вместе, -вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков -и на уровне с Go, который является компилируемым языком близким к C (всё благодаря Starlette). +И это тот же уровень производительности, который вы получаете с **FastAPI**. -### Получается, конкурентность лучше параллелизма? +И так как у вас может быть параллелизм и асинхронность одновременно, вы получаете более высокую производительность, чем большинство протестированных NodeJS фреймворков, и сопоставимо с Go, который является компилируемым языком, ближе к C (всё это благодаря Starlette). -Нет! Мораль истории совсем не в этом. +### Конкуренция лучше параллелизма? -Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание. -Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях. +Нет! Это не мораль истории. -Давайте посмотрим с другой стороны, представьте такую картину: +Конкурентность отличается от параллелизма. И она лучше в **конкретных** сценариях, которые включают много ожидания. Из-за этого, обычно она намного лучше, чем параллелизм для разработки веб-приложений. Но не всегда и не для всего. -> Вам нужно убраться в большом грязном доме. +Так что, чтобы уравновесить это, представьте себе следующий короткий рассказ: + +> Вам нужно убрать большой, грязный дом. *Да, это вся история*. --- -Тут не нужно нигде ждать 🕙, просто есть куча работы в разных частях дома. +Тут нет ожидания 🕙 нигде, просто много работы по разным местам дома. -Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня, -но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете. +Вы могли бы иметь очереди как в примере с бургерами, сначала гостиная, затем кухня, но так как вы не ждете 🕙 чего-либо, а просто убираете и убираете, очереди никак не повлияют на это. -И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё, -и работы будет сделано тоже одинаковое количество. +Добавление или отсутствие очередей (конкурентности) не увеличит или уменьшит время завершения работы, и вы выполните то же количество работы. -Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, -и каждый из них (вместе с вами) взялся бы за свой участок дома, -с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**. +Но в этом случае, если бы вы могли пригласить 8 бывших кассиров/поваров/теперь-уборщиков, и каждый из них (вместе с вами) мог бы взяться за зону дома, чтобы ее убрать, вы могли бы сделать всю работу **параллельно**, с дополнительной помощью, и закончить намного быстрее. -В описанном сценарии каждый уборщик (включая вас) был бы исполнителем, занятым на своём участке работы. +В этой ситуации каждый из уборщиков (включая вас) будет процессором, выполняющим свою часть работы. -И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание), -а работу в компьютере делает ЦП, -такие задачи называют ограниченными производительностью процессора. +И поскольку основная часть времени выполнения уходит на реальную работу (вместо ожидания), и работа в компьютере выполняется ЦП, такие задачи называют "ограниченными производительностью процессора" (CPU bound). --- -Ограничение по процессору проявляется в операциях, где требуется выполнять сложные математические вычисления. +Общие примеры операций, связанные с производительностью процессора, — это те, которые требуют сложных математических вычислений. Например: * Обработка **звука** или **изображений**. -* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета, -обработка обычно требует проведения расчётов по всем пикселям сразу. -* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов". -Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить. -* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание. -Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется -специальный процессор для создания и / или использования построенных таким образом моделей. +* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения / цвета, обработка этого обычно требует вычисления чего-то на этих пикселях, все одновременно. +* **Машинное обучение**: оно обычно требует множества умножений "матриц" и "векторов". Представьте огромную таблицу с числами в Экселе и умножение всех их вместе одновременно. +* **Глубокое обучение**: это подполе Машинного обучения, так что, то же самое применимо. Просто здесь не одна таблица чисел для умножения, а огромное их множество, и в многих случаях используется специальный процессор для создания и / или использования этих моделей. -### Конкурентность + параллелизм: Веб + машинное обучение +### Конкурентность + параллелизм: Веб + Машинное обучение -**FastAPI** предоставляет возможности конкуретного программирования, -которое очень распространено в веб-разработке (именно этим славится NodeJS). +С **FastAPI** вы можете использовать преимуществ конкурентности, который очень распространён в веб-разработке (та же главная привлекательность NodeJS). -Кроме того вы сможете использовать все преимущества параллелизма и -многопроцессорности (когда несколько процессов работают параллельно), -если рабочая нагрузка предполагает **ограничение по процессору**, -как, например, в системах машинного обучения. +Но вы также можете использовать преимущества параллелизма и многопроцессорности (имеющих несколько процессов, работающих параллельно) для рабочих нагрузок, зависимых от **производительности процессора**, таких как в системах Машинного обучения. -Необходимо также отметить, что Python является главным языком в области -**дата-сайенс**, -машинного обучения и, особенно, глубокого обучения. Всё это делает 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 может пока переключиться на выполнение других задач 🔀 ⏯ -(например получение следующего запроса). +Ключ здесь — `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`, вам нужно "ожидать" её. -Поэтому такое не сработает: +Когда вы хотите вызвать функцию `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`. - -Но выполнение такой функции необходимо "ожидать" с помощью `await`. -Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`. +Но в то же время функции, определённые с помощью `async def`, должны быть "ожиданы". Поэтому, функции с `async def` могут вызываться только внутри функций, определённых с `async def`. -Но как же тогда появилась первая курица? В смысле... как нам вызвать первую асинхронную функцию? +Так что как же насчёт яйца и курицы, как вызвать первую `async` функцию? -При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*, -и дальше с этим разберётся FastAPI. +Если вы работаете с **FastAPI**, вы можете не заботиться об этом, потому что эта "первая" функция будет вашей *функцией обработки пути*, и FastAPI будет знать, как сделать всё правильно. -Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI. +Но если вы хотите использовать `async` / `await` без FastAPI, вы тоже можете это сделать. ### Пишите свой асинхронный код -Starlette (и **FastAPI**) основаны на AnyIO, что делает их совместимыми как со стандартной библиотекой asyncio в Python, так и с Trio. +Starlette (и **FastAPI**) базируются на AnyIO, что делает их совместимыми как со стандартной библиотекой Python asyncio, так и с Trio. + +В частности, вы можете напрямую использовать AnyIO для ваших продвинутых случаев использования конкурентности, которые требуют более сложных паттернов в вашем собственном коде. -В частности, вы можете напрямую использовать AnyIO в тех проектах, где требуется более сложная логика работы с конкурентностью. +И даже если вы не использовали FastAPI, вы всё равно могли бы написать свои собственные асинхронные приложения с помощью AnyIO, чтобы они были высоко совместимыми и получали все его преимущества (например, структурированная конкурентность). -Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью AnyIO, чтобы они были максимально совместимыми и получали его преимущества (например *структурную конкурентность*). +Я создал другую библиотеку поверх AnyIO, как тонкий слой поверх него, чтобы немного улучшить аннотации типов и получить лучшую **автодополнения**, **ошибки в строках кода** и т. д. Она также имеет дружный вводный материал и учебник, который поможет вам **понять** и писать **свой собственный асинхронный код**: Asyncer. Он будет особенно полезен, если вам нужно **сочетать асинхронный код с обычным** (блокирующим/синхронным) кодом. -### Другие виды асинхронного программирования +### Другие формы асинхронного кода -Стиль написания кода с `async` и `await` появился в языке Python относительно недавно. +Этот стиль использования `async` и `await` относительно новый в языке. -Но он сильно облегчает работу с асинхронным кодом. +Но он сильно упрощает работу с асинхронным кодом. -Ровно такой же синтаксис (ну или почти такой же) недавно был включён в современные версии JavaScript (в браузере и NodeJS). +Этот же синтаксис (или почти идентичный) также был недавно включен в современные версии JavaScript (в браузерах и NodeJS). -До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать. +Но раньше обработка асинхронного кода была намного более сложной и трудной. -В предыдущих версиях Python для этого использовались потоки или Gevent. Но такой код намного сложнее понимать, отлаживать и мысленно представлять. +В предыдущих версиях Python, вы могли использовать потоки или Gevent. Но код в этом случае был намного сложнее для понимания, отладки и осмысления. -Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели -"обратные вызовы". Что выливалось в -ад обратных вызовов. +В предыдущих версиях NodeJS / Javascript для браузеров, для этого использовались "обратные вызовы". Что приводило к аду обратных вызовов. ## Сопрограммы -**Корути́на** (или же сопрограмма) — это крутое словечко для именования той сущности, -которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию, -но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`. +**Сопрограмма** — это просто очень крутое слово для обозначения того, что возвращается функцией `async def`. Python знает, что это что-то вроде функции, которую можно запустить, и которая закончится в какой-то момент, но которая может быть также поставлена на паузу ⏸, когда внутри встречается `await`. -Всю функциональность асинхронного программирования с использованием `async` и `await` -часто обобщают словом "корутины". Они аналогичны "горутинам", ключевой особенности -языка 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 ожидает её выполнения, запустив функцию во внешнем -пуле потоков, а не напрямую (это бы заблокировало сервер). +Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def` вместо `async def`, она выполняется во внешнем пуле потоков, который затем ожидается, вместо того, чтобы быть вызванной напрямую (так как это заблокировало бы сервер). -Если ранее вы использовали другой асинхронный фреймворк, который работает иначе, -и привыкли объявлять простые вычислительные *функции* через `def` ради -незначительного прироста скорости (порядка 100 наносекунд), обратите внимание, -что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит -`async def`, если только *функция обработки пути* не использует код, приводящий -к блокировке I/O. - +Если вы приходите из другого асинхронного фреймворка, который работает не так, как описано выше, и вы привыкли определять тривиальные вычислительные *функции обработки пути* с простым `def` для маленького прироста производительности (около 100 наносекунд), обратите внимание, что в **FastAPI** эффект будет полностью противоположным. В этих случаях лучше использовать `async def`, если только ваши *функции обработки пути* не используют код, который выполняет блокирующий I/O. - -Но в любом случае велика вероятность, что **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` для этой функции, когда вы вызываете её в вашем коде. --- - -Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали. +Еще раз повторим, что все эти технические подробности вероятно будут полезны, если вы специально искали их. -В противном случае просто ознакомьтесь с основными принципами в разделе выше: Нет времени?. +В противном случае вы должны обратиться к руководящим принципам из раздела выше: В спешке?. diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md index 259dca8e6..4846e9bd6 100644 --- a/docs/ru/docs/benchmarks.md +++ b/docs/ru/docs/benchmarks.md @@ -1,37 +1,36 @@ -# Замеры производительности +# Результаты производительности -Независимые тесты производительности приложений от TechEmpower показывают, что **FastAPI** под управлением Uvicorn один из самых быстрых Python-фреймворков и уступает только Starlette и Uvicorn (которые используются в FastAPI). (*) +Независимые тесты производительности TechEmpower показывают, что приложения на **FastAPI**, работающие под управлением Uvicorn, это один из самых быстрых Python-фреймворков, уступающий лишь 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 и т.п. Фреймворками с интегрированной автоматической проверкой данных, сериализацией и документацией. diff --git a/docs/ru/docs/deployment/manually.md b/docs/ru/docs/deployment/manually.md index 9b1d32be8..67460d54b 100644 --- a/docs/ru/docs/deployment/manually.md +++ b/docs/ru/docs/deployment/manually.md @@ -1,163 +1,157 @@ -# Запуск сервера вручную - Uvicorn +# Запуск сервера вручную -Для запуска приложения **FastAPI** на удалённой серверной машине вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**. +## Использование команды `fastapi run` -Существует три наиболее распространённые альтернативы: +Коротко говоря, используйте `fastapi run`, чтобы запустить ваше приложение FastAPI: -* Uvicorn: высокопроизводительный ASGI сервер. -* Hypercorn: ASGI сервер, помимо прочего поддерживающий HTTP/2 и Trio. -* Daphne: ASGI сервер, созданный для Django Channels. - -## Сервер как машина и сервер как программа - -В этих терминах есть некоторые различия и вам следует запомнить их. 💡 - -Слово "**сервер**" чаще всего используется в двух контекстах: +
-- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина). -- программа, запущенная на таком компьютере (например, Uvicorn). +```console +$ fastapi run main.py -Просто запомните, если вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов. + FastAPI Запуск серверной программы для продакшена 🚀 -Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором вы запускаете программы. + Поиск структуры файлов пакета из директорий + с файлами __init__.py + Импорт из /home/user/code/awesomeapp -## Установка программного сервера + module 🐍 main.py -Вы можете установить сервер, совместимый с протоколом ASGI, так: + code Импорт объект приложения FastAPI из модуля при помощи + следующего кода: -//// tab | Uvicorn + from main import app -* Uvicorn, очень быстрый ASGI сервер, основанный на библиотеках uvloop и httptools. + app Использование строки импорта: main:app -
+ server Сервер запущен на http://0.0.0.0:8000 + server Документация доступна по адресу http://0.0.0.0:8000/docs -```console -$ pip install "uvicorn[standard]" + Логи: ----> 100% + INFO Запущен серверный процесс [2306215] + INFO Ожидание запуска приложения. + INFO Запуск приложения завершён. + INFO Uvicorn работает на http://0.0.0.0:8000 (нажмите CTRL+C + для завершения) ```
-/// tip | Подсказка - -С опцией `standard`, Uvicorn будет устанавливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями. +Это подойдёт для большинства случаев. 😎 -В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ. +Вы можете использовать эту команду, чтобы например запустить ваше **FastAPI**-приложение в контейнере, на сервере и т.д. -/// - -//// +## ASGI-сервера -//// tab | Hypercorn +Давайте углубимся в детали. -* Hypercorn, ASGI сервер, поддерживающий протокол HTTP/2. - -
+FastAPI использует стандарт для создания Python веб-фреймворков и серверов, называемый ASGI. FastAPI — это ASGI веб-фреймворк. -```console -$ pip install hypercorn - ----> 100% -``` +Основное, что вам нужно для запуска **FastAPI** приложения (или любого другого ASGI приложения) на удалённой серверной машине — это программа ASGI сервера, такая как **Uvicorn**, именно она используется по умолчанию в команде `fastapi`. -
+Среди альтернатив: -...или какой-либо другой ASGI сервер. +* Uvicorn: высокопроизводительный ASGI сервер. +* Hypercorn: ASGI сервер, поддерживающий HTTP/2 и Trio среди прочего. +* Daphne: ASGI сервер, созданный для Django Channels. +* Granian: HTTP сервер на Rust для Python приложений. +* NGINX Unit: лёгкая и многофункциональная среда выполнения веб-приложений от NGINX. -//// +## Сервер как машина и сервер как программа -## Запуск серверной программы +Есть небольшая деталь о названиях, которую нужно иметь в виду. 💡 -Затем запустите ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`: +Слово "**сервер**" обычно используется для обозначения как удалённого/облачного компьютера (физическая или виртуальная машина), так и программы, запущенной на этой машине (например, Uvicorn). -//// tab | Uvicorn +Просто помните, что когда вы видите "сервер" в общем случае, это может обозначать что-то из этих двух вещей. -
+Когда речь идёт о удалённой машине, её часто называют **сервер**, но также **машина**, **ВМ** (виртуальная машина), **нода**. Все они относятся к каким-то удалённым машинам, обычно под управлением Linux, на которых вы запускаете программы. -```console -$ uvicorn main:app --host 0.0.0.0 --port 80 +## Установка программы сервера -INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) -``` +Когда вы устанавливаете FastAPI, он поставляется с сервером для продакшена, Uvicorn, и вы можете запустить его с помощью команды `fastapi run`. -
+Но вы также можете установить ASGI-сервер вручную. -//// +Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и тогда можете установить серверное приложение. -//// tab | Hypercorn +Например, чтобы установить Uvicorn:
```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% ```
-//// +Аналогичный процесс будет применен для любой другой программы ASGI сервера. -/// warning | Предупреждение +/// tip | Подсказка -Не забудьте удалить опцию `--reload`, если ранее пользовались ею. +Добавив `standard`, Uvicorn установит и будет использовать некоторые рекомендованные дополнительные зависимости. -Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности. +Среди них `uvloop`, высокопроизводительная замена для `asyncio`, которая предоставляет значительное увеличение производительности при использовании асинхронности. -Она сильно помогает во время **разработки**, но **не следует** использовать её при **реальной работе** приложения. +Когда вы устанавливаете FastAPI чем-то вроде `pip install "fastapi[standard]"`, вы также получаете `uvicorn[standard]`. /// -## Hypercorn с Trio - -Starlette и **FastAPI** основаны на AnyIO, которая делает их совместимыми как с asyncio - стандартной библиотекой Python, так и с Trio. - - -Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с `uvloop`, высокопроизводительной заменой `asyncio`. +## Запуск программы сервера -Но если вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨ - -### Установка Hypercorn с Trio - -Для начала, вам нужно установить Hypercorn с поддержкой Trio: +Если вы установили ASGI-сервер вручную, вам обычно нужно будет передать строку импорта в специальном формате, чтобы он импортировал ваше FastAPI-приложение:
```console -$ pip install "hypercorn[trio]" ----> 100% +$ uvicorn main:app --host 0.0.0.0 --port 80 + +INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) ```
-### Запуск с Trio +/// note | Примечание -Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`: +Команда `uvicorn main:app` относится к: -
+* `main`: файл `main.py` (Python "модуль"). +* `app`: объект, созданный внутри `main.py` строкой `app = FastAPI()`. -```console -$ hypercorn main:app --worker-class trio +Это эквивалентно: + +```Python +from main import app ``` -
+/// + +Каждая альтернативная программа 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 +* Запуск при старте системы +* Перезапуски +* Репликация (число запущенных процессов) +* Память +* Предыдущие шаги перед стартом -Я расскажу вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀 +Я расскажу вам больше о каждой из этих концепций, как их рассматривать и приведу конкретные примеры стратегий для их решения в следующих главах. 🚀 diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md index 474b3d689..ef290a4df 100644 --- a/docs/ru/docs/help-fastapi.md +++ b/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 -Подписаться на @fastapi в **Twitter** для получения наисвежайших новостей о **FastAPI**. 🐦 +Подписывайтесь на @fastapi в **Twitter**, чтобы получать последние новости о **FastAPI**. 🐦 -## Добавить **FastAPI** звезду на GitHub +## Добавить звезду **FastAPI** на GitHub -Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): https://github.com/fastapi/fastapi. ⭐️ +Вы можете "поставить звезду" FastAPI на GitHub (нажав на кнопку звезды вверху справа): https://github.com/fastapi/fastapi. ⭐️ -Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих. +Чем больше звёзд, тем легче другим пользователям найти проект и увидеть, что он уже был полезен многим. -## Отслеживать свежие выпуски в репозитории на GitHub +## Отслеживать обновления в репозитории на GitHub -Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 +Вы можете "отслеживать" FastAPI на GitHub (нажав на кнопку "watch" вверху справа): https://github.com/fastapi/fastapi. 👀 -Там же Вы можете указать в настройках - "Releases only". +Там вы можете выбрать "Releases only". -С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями. +Таким образом, вы будете получать уведомления (на ваш email) каждый раз, когда будет выходить новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми функциями. ## Связаться с автором -Можно связаться со мной (Себястьян Рамирез / `tiangolo`), автором FastAPI. +Вы можете связаться со мной (Себастьян Рамирес / `tiangolo`), автором. Вы можете: * Подписаться на меня на **GitHub**. - * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам. - * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,. + * Ознакомиться с другими проектами с открытым исходным кодом, которые я создал и которые могут быть полезны вам. + * Подписывайтесь на меня, чтобы узнавать о моих новых проектах с открытым исходным кодом. * Подписаться на меня в **Twitter** или в Mastodon. - * Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это). - * Получать уведомления, когда я делаю объявления и представляю новые инструменты. - * Вы также можете подписаться на @fastapi в Twitter (это отдельный аккаунт). -* Подписаться на меня в **Linkedin**. - * Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷‍♂). -* Читать, что я пишу (или подписаться на меня) в **Dev.to** или в **Medium**. - * Читать другие идеи, статьи и читать об инструментах созданных мной. - * Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое. + * Расскажите мне, как вы используете FastAPI (мне нравится об этом слышать). + * Узнавать о моих объявлениях или новых инструментах. + * Вы также можете подписаться на @fastapi в Twitter (отдельный аккаунт). +* Следите за мной на **LinkedIn**. + * Узнавайте о моих объявлениях или новых инструментах (хотя я чаще использую Twitter 🤷‍♂). +* Читайте, что я пишу (или подписывайтесь на меня) на **Dev.to** или на **Medium**. + * Читайте другие идеи, статьи и узнавайте о созданных мной инструментах. + * Подпишитесь на меня, чтобы знать, когда я публикую что-то новое. -## Оставить сообщение в Twitter о **FastAPI** +## Написать твит о **FastAPI** -Оставьте сообщение в Twitter о **FastAPI** и позвольте мне и другим узнать - почему он Вам нравится. 🎉 +Напишите твит о **FastAPI**, и позвольте мне и другим узнать, почему он вам нравится. 🎉 -Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п. +Мне нравится слышать о том, как используется **FastAPI**, что вам в нём понравилось, в каком проекте/компании вы его используете и т.п. ## Оставить голос за FastAPI -* Голосуйте за **FastAPI** в Slant. -* Голосуйте за **FastAPI** в AlternativeTo. -* Расскажите, как Вы используете **FastAPI** на StackShare. +* Голосуйте за **FastAPI** на Slant. +* Голосуйте за **FastAPI** на AlternativeTo. +* Создайте отзыв о **FastAPI** на StackShare. -## Помочь другим с их проблемами на GitHub +## Помогите другим с вопросами на GitHub -Вы можете посмотреть, какие проблемы испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓 +Вы можете попытаться помочь другим с их вопросами в: -Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. 🎉 +* Обсуждения GitHub +* Проблемы GitHub -Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗 +Во многих случаях вы уже можете знать ответы на эти вопросы. 🤓 -Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге. +Если вы будете помогать многим людям с их вопросами, вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 + +Просто помните, самое важное: старайтесь быть добрыми. Люди приходят со своими разочарованиями и часто не задают вопросы так, как следовало бы, но старайтесь быть как можно добрее. 🤗 + +Идея сообщества **FastAPI** заключается в том, чтобы быть добрыми и гостеприимными. В то же время, не терпите издевательства или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге. --- -Как помочь другим с их проблемами: +Вот как помочь другим с вопросами (в обсуждениях или проблемах): ### Понять вопрос -* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего. +* Убедитесь, что вы поняли, какова **цель** и заслуга человека, задающего вопрос. + +* Затем убедитесь, что вопрос (в большинстве случаев это вопрос) **ясен**. -* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**. +* Во многих случаях вопрос касается выдуманного решения пользователя, но существует **лучшее** решение. Если вы сможете понять основную проблему и контекст лучше, вы сможете предложить альтернативное **решение**. -* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**. +* Если вопрос вам не ясен, попросите больше **деталей**. -* Ежели вопрос Вам непонятен, запросите больше **деталей**. +### Воспроизведите проблему -### Воспроизвести проблему +В большинстве случаев и вопросов что-то связано с **исходным кодом** пользователя. -В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего. +Во многих случаях они скопируют только фрагмент кода, но этого недостаточно для того, чтобы **воспроизвести проблему**. -И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**. +* Вы можете попросить их предоставить минимальный, воспроизводимый пример, который вы можете **копировать и вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, которое они наблюдают, или чтобы лучше понять их контекст. -* Попросите предоставить минимальный воспроизводимый пример, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая. +* Если вы чувствуете щедрость, вы можете попробовать **создать пример** самостоятельно, только на основе описания проблемы. Просто помните, что это может занять много времени и, возможно, лучше сначала попросить их прояснить проблему. -* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы. +### Предложите решения -### Предложить решение +* После того, как вы смогли понять вопрос, вы можете предложить возможный **ответ**. -* После того как Вы поняли вопрос, Вы можете дать **ответ**. +* Во многих случаях лучше понять их **основную проблему или контекст**, так как может быть лучшее решение, чем то, которое они пытаются использовать. -* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать. +### Попросить закрыть -### Попросить закрыть проблему +Если они ответят, с большой вероятностью вы решили их проблему, поздравляю, **вы герой**! 🦸 -Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸 +* Теперь, если это решило их проблему, вы можете попросить их: -* В таком случае, если вопрос решён, попросите **закрыть проблему**. + * В обсуждениях на GitHub: отметить комментарий как **ответ**. + * В проблемах на GitHub: **закрыть** проблему. ## Отслеживать репозиторий на GitHub -Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 +Вы можете "отслеживать" FastAPI на GitHub (нажав на кнопку "watch" вверху справа): https://github.com/fastapi/fastapi. 👀 -Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы. +Если вы выберете "Watching" вместо "Releases only", вы получите уведомления, когда кто-то создаёт новую проблему или задаёт вопрос. Вы также можете уточнить, что хотите получать уведомления только о новых проблемах, обсуждениях или PR и т.д. -Тогда Вы можете попробовать решить эту проблему. +Затем вы можете попытаться помочь решить эти вопросы. -## Запросить помощь с решением проблемы +## Задавать вопросы -Вы можете создать новый запрос с просьбой о помощи в репозитории на GitHub, например: +Вы можете создать новый вопрос в репозитории 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, которые Вы создали или нашли изменив этот файл. - * Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела. -* Помочь с [переводом документации](contributing.md#_8){.internal-link target=_blank} на Ваш язык. - * Вы также можете проверять переводы сделанные другими. -* Предложить новые разделы документации. -* Исправить существующуе проблемы/баги. +* Чтобы исправить ошибку в документации. +* Чтобы поделиться статьей, видео или подкастом, который вы создали или нашли, о FastAPI, редактируя этот файл. + * Убедитесь, что добавили ссылку в начало соответствующего раздела. +* Чтобы помочь [перевести документацию](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**, обеспечивая его дальнейшее **развитие быстрее и лучше**. 🚀 -## Подключиться к чату +## Присоединяйтесь к чату -Подключайтесь к 👥 чату в Discord 👥 и общайтесь с другими участниками сообщества FastAPI. +Присоединяйтесь к 👥 чат-серверу Discord 👥 и общайтесь с другими в сообществе FastAPI. /// tip | Подсказка -Вопросы по проблемам с фреймворком лучше задавать в GitHub issues, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. +Задавайте вопросы в Обсуждениях GitHub, так у вас будет намного больше шансов получить помощь от [Экспертов 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. -С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄 +С другой стороны, в чаты подключены тысячи пользователей, поэтому есть большая вероятность, что вы найдёте там кого-то, с кем могли бы поговорить почти в любое время. 😄 ## Спонсировать автора -Вы также можете оказать мне финансовую поддержку посредством спонсорства через GitHub. - -Там можно просто купить мне кофе ☕️ в знак благодарности. 😄 - -А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉 - -## Спонсировать инструменты, на которых зиждется мощь FastAPI - -Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic. - -Им тоже можно оказать спонсорскую поддержку: - -* Samuel Colvin (Pydantic) -* Encode (Starlette, Uvicorn) +Если ваш **продукт/компания** зависит от **FastAPI** или связана с ним и вы хотите достичь его пользователей, вы можете спонсировать автора (меня) через спонсоров GitHub. В зависимости от уровня, вы можете получить некоторые дополнительные преимущества, такие как награда в документации. 🎁 --- -Благодарствую! 🚀 +Спасибо! 🚀 diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index a9546cf1e..2e0f6b684 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -8,7 +8,7 @@ FastAPI

- Готовый к внедрению высокопроизводительный фреймворк, простой в изучении и разработке. + Фреймворк FastAPI: высокая производительность, простота освоения, быстрая разработка, готов к использованию в производстве

@@ -33,20 +33,20 @@ --- -FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API используя Python, в основе которого лежит стандартная аннотация типов Python. +FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API, использующий Python и стандартные аннотации типов Python. Ключевые особенности: -* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков Python](#_10). -* **Быстрота разработки**: Увеличьте скорость разработки примерно на 200–300%. * -* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). * -* **Интуитивно понятный**: Отличная поддержка редактора. Автозавершение везде. Меньше времени на отладку. -* **Лёгкость**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации. -* **Краткость**: Сведите к минимуму дублирование кода. Каждый объявленный параметр - определяет несколько функций. Меньше ошибок. -* **Надежность**: Получите готовый к работе код. С автоматической интерактивной документацией. -* **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: OpenAPI (ранее известном как Swagger) и JSON Schema. +* **Быстрый**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков на Python](#performance). +* **Быстрая разработка**: Повышает скорость разработки примерно на 200–300%. * +* **Меньше ошибок**: Уменьшает количество ошибок, вносимых разработчиком, на 40%. * +* **Интуитивно понятный**: Отличная поддержка редактора. Автозаполнение везде. Меньше времени на отладку. +* **Простой**: Разработан для простоты использования и изучения. Меньше времени на чтение документации. +* **Краткий**: Сведите к минимуму дублирование кода. Множество функций из каждого объявления параметра. Меньше ошибок. +* **Надежный**: Получите готовый к производству код. С автоматической интерактивной документацией. +* **На основе стандартов**: Основан на (и полностью совместим с) открытых стандартах API: OpenAPI (ранее известный как Swagger) и JSON Schema. -* оценка на основе тестов внутренней команды разработчиков, создающих производственные приложения. +* оценка, основанная на тестах внутренней команды разработчиков, создающих производственные приложения. ## Спонсоры @@ -67,88 +67,86 @@ FastAPI — это современный, быстрый (высокопрои ## Отзывы -"_В последнее время я много где использую **FastAPI**. [...] На самом деле я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._" +"_[...] В последнее время я много использую **FastAPI**. [...] На самом деле, я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._"

Kabir Khan - Microsoft (ref)
--- -"_Мы использовали библиотеку **FastAPI** для создания сервера **REST**, к которому можно делать запросы для получения **прогнозов**. [для Ludwig]_" +"_Мы приняли библиотеку **FastAPI** для создания сервера **REST**, к которому можно обращаться для получения **прогнозов**. [для Ludwig]_"
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
--- -"_**Netflix** рада объявить о выпуске опенсорсного фреймворка для оркестровки **антикризисного управления**: **Dispatch**! [создана с помощью **FastAPI**]_" +"_**Netflix** рада объявить о выпуске фреймворка для оркестрации **кризисного управления**: **Dispatch**! [создан с использованием **FastAPI**]_"
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
--- -"_Я в полном восторге от **FastAPI**. Это так весело!_" +"_Меня невероятно радует **FastAPI**. Это так весело!_" -
Brian Okken - Python Bytes podcast host (ref)
+
Brian Okken - Python Bytes ведущий подкаста (ref)
--- -"_Честно говоря, то, что вы создали, выглядит очень солидно и отполировано. Во многих смыслах я хотел, чтобы **Hug** был именно таким — это действительно вдохновляет, когда кто-то создаёт такое._" +"_Честно говоря, то, что вы создали, выглядит очень солидно и отшлифовано. В многих отношениях это то, чем я хотел, чтобы было **Hug** — это действительно вдохновляет, когда кто-то создает такое._" -
Timothy Crosley - Hug creator (ref)
+
Timothy Crosley - Hug создатель (ref)
--- -"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания REST API, ознакомьтесь с **FastAPI** [...] Он быстрый, лёгкий и простой в изучении [...]_" +"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания REST API, ознакомьтесь с **FastAPI** [...] Это быстрый, простой в использовании и в изучении фреймворк [...]_" -"_Мы перешли на **FastAPI** для наших **API** [...] Я думаю, вам тоже понравится [...]_" +"_Мы перешли на **FastAPI** для наших **API** [...] Думаю, он вам понравится [...]_" -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+
Ines Montani - Matthew Honnibal - Explosion AI основатели - spaCy создатели (ref) - (ref)
--- -## **Typer**, интерфейс командной строки для FastAPI +"_Если кто-то хочет создать производственный Python API, я бы очень рекомендовал **FastAPI**. Он **замечательно спроектирован**, **прост в использовании** и **очень масштабируем**, он стал **ключевым компонентом** в нашей стратегии разработки API. Благодаря нему автоматизация и сервисы, такие как наш Виртуальный Инженер TAC, стали возможными._" - - -Если вы создаете приложение CLI для использования в терминале вместо веб-API, ознакомьтесь с **Typer**. +
Deon Pillsbury - Cisco (ref)
-**Typer** — младший брат FastAPI. И он предназначен для использования в качестве **интерфейса командной строки для FastAPI**. ⌨️ 🚀 +--- -## Зависимости +## **Typer**, FastAPI для CLI -FastAPI стоит на плечах гигантов: + -* Starlette для части связанной с вебом. -* Pydantic для части связанной с данными. +Если вы создаете приложение для CLI, используемое в терминале вместо веб API, ознакомьтесь с **Typer**. -## Установка +**Typer** — младший брат FastAPI. Он предназначен быть **FastAPI для CLI**. ⌨️ 🚀 -
+## Требования -```console -$ pip install fastapi +FastAPI опирается на гигантов: ----> 100% -``` +* Starlette для веб-компонентов. +* Pydantic для работы с данными. -
+## Установка -Вам также понадобится сервер ASGI для производства, такой как Uvicorn или Hypercorn. +Создайте и активируйте виртуальное окружение, а затем установите FastAPI:
```console -$ pip install "uvicorn[standard]" +$ pip install "fastapi[standard]" ---> 100% ```
+**Примечание**: Убедитесь, что вы обернули `"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): **Примечание**: -Если вы не знаете, проверьте раздел _"Торопитесь?"_ в документации об `async` и `await`. +Если вы не уверены, ознакомьтесь с разделом _"Торопитесь?"_ о `async` и `await` в документации. @@ -204,31 +202,45 @@ async def read_item(item_id: int, q: Union[str, None] = None):
```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: Запуск приложения завершён. ```
-О команде uvicorn main:app --reload... +О команде fastapi dev main.py... -Команда `uvicorn main:app` относится к: +Команда `fastapi dev` читает ваш файл `main.py`, определяет **FastAPI** приложение в нем и запускает сервер, используя Uvicorn. -* `main`: файл `main.py` (модуль Python). -* `app`: объект, созданный внутри `main.py` с помощью строки `app = FastAPI()`. -* `--reload`: перезапуск сервера после изменения кода. Делайте это только во время разработки. +По умолчанию, `fastapi dev` запускается с активированной функцией автообновления для локальной разработки. + +Вы можете узнать больше об этом в документации FastAPI CLI.
### Проверка -Откройте браузер на http://127.0.0.1:8000/items/5?q=somequery. +Откройте ваш браузер на http://127.0.0.1:8000/items/5?q=somequery. Вы увидите следующий JSON ответ: @@ -238,10 +250,10 @@ INFO: Application startup complete. Вы уже создали API, который: -* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`. -* И первый и второй _путь_ используют `GET` операции (также известные как HTTP _методы_). -* _путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`. -* _путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`. +* Получает HTTP-запросы в _пути_ `/` и `/items/{item_id}`. +* Оба _пути_ принимают операции `GET` (также известные как HTTP методы). +* _Путь_ `/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 -Перейдите на http://127.0.0.1:8000/docs. +Теперь перейдите на http://127.0.0.1:8000/docs. -* Интерактивная документация 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 А теперь перейдите на http://127.0.0.1:8000/redoc. -* Альтернативная документация также будет отражать новый параметр и тело запроса: +* Альтернативная документация также отразит новый параметр запроса и тело: ![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. -* Преобразование входных данных: поступающие из сети в объекты Python с соблюдением типов. Чтение из: + * Проверку типов. +* Валидацию данных: + * Автоматические и чёткие ошибки, когда данные недействительны. + * Валидацию даже для глубоко вложенных объектов JSON. +* Преобразование входных данных: поступающих из сети в данные и типы Python. Чтение из: * JSON. * Параметров пути. * Параметров запроса. @@ -359,8 +371,8 @@ item: Item * Заголовков. * Форм. * Файлов. -* Преобразование выходных данных: преобразование объектов Python в данные передаваемые по сети интернет (такие как JSON): - * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т.д.). +* Преобразование выходных данных: преобразование данных и типов 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) Более полный пример с дополнительными функциями см. в Учебное руководство - Руководство пользователя. -**Осторожно, спойлер**: руководство пользователя включает в себя: +**Внимание, спойлер**: учебное руководство - Руководство пользователя включает: * Объявление **параметров** из других мест, таких как: **заголовки**, **cookies**, **поля формы** и **файлы**. * Как установить **ограничительные проверки** такие как `maximum_length` или `regex`. -* Очень мощная и простая в использовании система **внедрения зависимостей**. -* Безопасность и аутентификация, включая поддержку **OAuth2** с **токенами JWT** и **HTTP Basic** аутентификацию. -* Более продвинутые (но столь же простые) методы объявления **глубоко вложенных моделей JSON** (спасибо Pydantic). +* Очень мощная и простая в использовании система **Внедрение Зависимостей**. +* Безопасность и аутентификация, включая поддержку **OAuth2** с **токенами JWT** и **HTTP Basic** авторизация. +* Более продвинутые (но столь же простые) методы объявления **глубоко вложенных моделей JSON** (благодаря Pydantic). * **GraphQL** интеграция с Strawberry и другими библиотеками. -* Множество дополнительных функций (благодаря Starlette), таких как: - * **Веб-сокеты** - * очень простые тесты на основе HTTPX и `pytest` +* Много дополнительных функций (благодаря Starlette), как например: + * **WebSockets** + * невероятно простые тесты, основанные на HTTPX и `pytest` * **CORS** - * **Cookie сеансы(сессии)** + * **Сеансы Cookies** * ...и многое другое. ## Производительность -Независимые тесты TechEmpower показывают приложения **FastAPI**, работающие под управлением Uvicorn, как один из самых быстрых доступных фреймворков Python, уступающий только самим Starlette и Uvicorn (используемых внутри FastAPI). (*) +Независимые бенчмарки TechEmpower демонстрируют приложения **FastAPI**, работающие под Uvicorn, как один из самых быстрых доступных фреймворков на Python, уступающий только самим Starlette и Uvicorn (используемых внутри FastAPI). (*) -Чтобы узнать больше об этом, см. раздел Тесты производительности. +Чтобы узнать больше об этом, см. раздел Бенчмарки. -## Необязательные зависимости +## Зависимости + +FastAPI зависит от Pydantic и Starlette. + +### Зависимости `standard` + +Когда вы устанавливаете FastAPI с использованием `pip install "fastapi[standard]"`, он поставляется с `standard` группой необязательных зависимостей: Используется Pydantic: @@ -447,20 +465,38 @@ item: Item Используется Starlette: -* HTTPX - Обязательно, если вы хотите использовать `TestClient`. +* httpx - Обязательно, если вы хотите использовать `TestClient`. * jinja2 - Обязательно, если вы хотите использовать конфигурацию шаблона по умолчанию. -* python-multipart - Обязательно, если вы хотите поддерживать форму "парсинга" с помощью `request.form()`. -* itsdangerous - Обязательно, для поддержки `SessionMiddleware`. -* pyyaml - Обязательно, для поддержки `SchemaGenerator` Starlette (возможно, вам это не нужно с FastAPI). +* python-multipart - Обязательно, если вы хотите поддерживать "парсинг" форм, с `request.form()`. + +Используется FastAPI: + +* uvicorn - сервер, который загружает и обслуживает ваше приложение. Это включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), нужные для высокопроизводительного сервиса. +* `fastapi-cli[standard]` - для предоставления команды `fastapi`. + * Это включает `fastapi-cloud-cli`, который позволяет развернуть ваше FastAPI приложение на FastAPI Cloud. + +### Без `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: + +* pydantic-settings - для управления настройками. +* pydantic-extra-types - для добавления типов, которые могут быть использованы с Pydantic. + +Дополнительные необязательные зависимости FastAPI: -* uvicorn - сервер, который загружает и обслуживает ваше приложение. * orjson - Обязательно, если вы хотите использовать `ORJSONResponse`. * ujson - Обязательно, если вы хотите использовать `UJSONResponse`. -Вы можете установить все это с помощью `pip install "fastapi[all]"`. - ## Лицензия Этот проект распространяется на условиях лицензии MIT. diff --git a/docs/ru/docs/project-generation.md b/docs/ru/docs/project-generation.md index efd6794ad..a9c50f78c 100644 --- a/docs/ru/docs/project-generation.md +++ b/docs/ru/docs/project-generation.md @@ -1,84 +1,28 @@ -# Генераторы проектов - Шаблоны - -Чтобы начать работу быстрее, Вы можете использовать "генераторы проектов", в которые включены множество начальных настроек для функций безопасности, баз данных и некоторые эндпоинты API. - -В генераторе проектов всегда будут предустановлены какие-то настройки, которые Вам следует обновить и подогнать под свои нужды, но это может быть хорошей отправной точкой для Вашего проекта. - -## Full Stack FastAPI PostgreSQL - -GitHub: https://github.com/tiangolo/full-stack-fastapi-postgresql - -### Full Stack FastAPI PostgreSQL - Особенности - -* Полностью интегрирован с **Docker** (основан на Docker). -* Развёртывается в режиме Docker Swarm. -* Интегрирован с **Docker Compose** и оптимизирован для локальной разработки. -* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn. -* Бэкенд построен на фреймворке **FastAPI**: - * **Быстрый**: Высокопроизводительный, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). - * **Интуитивно понятный**: Отличная поддержка редактора. Автодополнение кода везде. Меньше времени на отладку. - * **Простой**: Разработан так, чтоб быть простым в использовании и изучении. Меньше времени на чтение документации. - * **Лаконичный**: Минимизировано повторение кода. Каждый объявленный параметр определяет несколько функций. - * **Надёжный**: Получите готовый к работе код. С автоматической интерактивной документацией. - * **Стандартизированный**: Основан на открытых стандартах API (OpenAPI и JSON Schema) и полностью совместим с ними. - * **Множество других возможностей** включая автоматическую проверку и сериализацию данных, интерактивную документацию, аутентификацию с помощью OAuth2 JWT-токенов и т.д. -* **Безопасное хранение паролей**, которые хэшируются по умолчанию. -* Аутентификация посредством **JWT-токенов**. -* Модели **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: https://github.com/tiangolo/full-stack-fastapi-couchbase - -⚠️ **ПРЕДУПРЕЖДЕНИЕ** ⚠️ - -Если Вы начинаете новый проект, ознакомьтесь с представленными здесь альтернативами. - -Например, генератор проектов Full Stack FastAPI PostgreSQL может быть более подходящей альтернативой, так как он активно поддерживается и используется. И он включает в себя все новые возможности и улучшения. - -Но никто не запрещает Вам использовать генератор с СУБД Couchbase, возможно, он всё ещё работает нормально. Или у Вас уже есть проект, созданный с помощью этого генератора ранее, и Вы, вероятно, уже обновили его в соответствии со своими потребностями. - -Вы можете прочитать о нём больше в документации соответствующего репозитория. - -## Full Stack FastAPI MongoDB - -...может быть когда-нибудь появится, в зависимости от наличия у меня свободного времени и прочих факторов. 😅 🎉 - -## Модели машинного обучения на основе spaCy и FastAPI - -GitHub: https://github.com/microsoft/cookiecutter-spacy-fastapi - -### Модели машинного обучения на основе spaCy и FastAPI - Особенности - -* Интеграция с моделями **spaCy** NER. -* Встроенный формат запросов к **когнитивному поиску Azure**. -* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn. -* Встроенное развёртывание на основе **Azure DevOps** Kubernetes (AKS) CI/CD. -* **Многоязычность**. Лёгкий выбор одного из встроенных в spaCy языков во время настройки проекта. -* **Легко подключить** модели из других фреймворков (Pytorch, Tensorflow) не ограничиваясь spaCy. +# Full Stack FastAPI Шаблон + +Шаблоны, хотя обычно они поставляются с определенной конфигурацией, разработаны для гибкости и настройки. Это позволяет вам изменять и адаптировать их в соответствии с требованиями вашего проекта, что делает их отличной отправной точкой. 🏁 + +Вы можете использовать этот шаблон, чтобы начать работу, так как он включает множество начальных настроек, безопасности, базы данных и некоторые API-эндпоинты, которые уже выполнены за вас. + +Репозиторий GitHub: Full Stack FastAPI Template + +## 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. diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md index 9300aa1bd..e2d768886 100644 --- a/docs/ru/docs/tutorial/body-multiple-params.md +++ b/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** встраивать тело запроса в ключ, даже если объявлен только один параметр. diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md index e8bf04576..aa24ac530 100644 --- a/docs/ru/docs/tutorial/cors.md +++ b/docs/ru/docs/tutorial/cors.md @@ -1,85 +1,88 @@ # CORS (Cross-Origin Resource Sharing) -Понятие CORS или "Cross-Origin Resource Sharing" относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом "источнике" ("origin"). +CORS или "Cross-Origin Resource Sharing" относится к ситуациям, когда фронтенд, работающий в браузере, использует 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` всегда разрешены для простых CORS-запросов. -* `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` всегда разрешены для простых CORS-запросов. +* `allow_credentials` - Указывает, что куки должны поддерживаться для междоменных запросов. По умолчанию равно `False`. + + Нельзя установить значения `allow_origins`, `allow_methods` и `allow_headers` в `['*']`, если `allow_credentials` установлено в `True`. Все они должны быть явно определены. + * `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-заголовки к ответу. -## Больше информации +## Дополнительная информация -Для получения более подробной информации о CORS, обратитесь к Документации CORS от Mozilla. +Для получения более подробной информации о CORS, обратитесь к документации CORS от Mozilla. /// note | Технические детали Вы также можете использовать `from starlette.middleware.cors import CORSMiddleware`. -**FastAPI** предоставляет несколько middleware в `fastapi.middleware` только для вашего удобства как разработчика. Но большинство доступных middleware взяты напрямую из Starlette. +**FastAPI** предоставляет несколько middleware в `fastapi.middleware` исключительно для вашего удобства как разработчика. Но большинство доступных middleware непосредственно поступают из Starlette. /// diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md index 5b51aa402..b53ff6271 100644 --- a/docs/ru/docs/tutorial/extra-models.md +++ b/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 `typing.Union`: +Для этого используйте стандартный аннотацию типа Python `typing.Union`: /// note | Примечание -При объявлении `Union`, сначала указывайте наиболее детальные типы, затем менее детальные. В примере ниже более детальный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`. +При определении `Union`, сначала указывайте самый специфичный тип, затем менее специфичные. В примере ниже более специфичный `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` и без пароля. diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md index cb3d19a71..5b37c2b7c 100644 --- a/docs/ru/docs/tutorial/first-steps.md +++ b/docs/ru/docs/tutorial/first-steps.md @@ -1,50 +1,66 @@ # Первые шаги -Самый простой FastAPI файл может выглядеть так: +Самый простой файл FastAPI может выглядеть следующим образом: {* ../../docs_src/first_steps/tutorial001.py *} -Скопируйте в файл `main.py`. +Скопируйте этот код в файл `main.py`. -Запустите сервер в режиме реального времени: +Запустите live сервер:
```console -$ uvicorn main:app --reload +$ fastapi dev main.py -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 Запуск сервера для разработки 🚀 -
+ Ищем структуру файлов пакета в директориях + с файлами __init__.py + Импортирование из /home/user/code/awesomeapp -/// note | Технические детали + module 🐍 main.py -Команда `uvicorn main:app` обращается к: + code Импортируем объект приложения FastAPI из модуля с + помощью следующего кода: -* `main`: файл `main.py` (модуль Python). -* `app`: объект, созданный внутри файла `main.py` в строке `app = FastAPI()`. -* `--reload`: перезапускает сервер после изменения кода. Используйте только для разработки. + from main import app -/// + app Используем строку импорта: main:app + + server Сервер запущен по адресу http://127.0.0.1:8000 + server Документация по адресу http://127.0.0.1:8000/docs + + tip Запуск в режиме разработки, для использования в продакшене: + fastapi run + + Логи: + + INFO Будем отслеживать изменения в этих директориях: + ['/home/user/code/awesomeapp'] + INFO Uvicorn запущен по адресу http://127.0.0.1:8000 (нажмите CTRL+C + для завершения) + INFO Процесс перезагрузки запущен [383138] с использованием WatchFiles + INFO Серверный процесс запущен [383153] + INFO Ожидание запуска приложения. + INFO Запуск приложения завершен. +``` + +
-В окне вывода появится следующая строка: +В выводе будет строка, похожая на: ```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, по которому ваше приложение доступно на локальной машине. -### Проверьте +### Проверьте это -Откройте браузер по адресу: http://127.0.0.1:8000. +Откройте браузер по адресу http://127.0.0.1:8000. -Вы увидите 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 -Перейдите по адресу: http://127.0.0.1:8000/docs. +Теперь перейдите по адресу http://127.0.0.1:8000/docs. -Вы увидите автоматически сгенерированную, интерактивную документацию по API (предоставленную Swagger UI): +Вы увидите автоматическую интерактивную документацию API (предоставленную Swagger UI): ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) ### Альтернативная документация API -Теперь перейдите по адресу http://127.0.0.1:8000/redoc. +И теперь перейдите по адресу http://127.0.0.1:8000/redoc. -Вы увидите альтернативную автоматически сгенерированную документацию (предоставленную ReDoc): +Вы увидите альтернативную автоматическую документацию (предоставленную ReDoc): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) ### OpenAPI -**FastAPI** генерирует "схему" всего API, используя стандарт **OpenAPI**. +**FastAPI** генерирует "схему" всего вашего API, используя стандарт **OpenAPI** для определения API. #### "Схема" -"Схема" - это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание. +"Схема" — это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание. -#### API "схема" +#### "Схема" API -OpenAPI - это спецификация, которая определяет, как описывать схему API. +В данном случае, OpenAPI — это спецификация, которая определяет, как описывать схему 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. -Можете посмотреть здесь: http://127.0.0.1:8000/openapi.json. +Вы можете увидеть её непосредственно по адресу: http://127.0.0.1:8000/openapi.json. -Вы увидите примерно такой 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`. -Вы можете использовать всю функциональность Starlette в `FastAPI`. +Вы можете использовать всю функциональность Starlette с `FastAPI`. /// -### Шаг 2: создайте экземпляр `FastAPI` +### Шаг 2: создайте "экземпляр" `FastAPI` {* ../../docs_src/first_steps/tutorial001.py hl[3] *} -Переменная `app` является экземпляром класса `FastAPI`. - -Это единая точка входа для создания и взаимодействия с API. - -Именно к этой переменной `app` обращается `uvicorn` в команде: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
- -Если создать такое приложение: - -{* ../../docs_src/first_steps/tutorial002.py hl[3] *} - -И поместить его в `main.py`, тогда вызов `uvicorn` будет таким: +Здесь переменная `app` будет "экземпляром" класса `FastAPI`. -
- -```console -$ uvicorn main:my_awesome_api --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
+Это будет главная точка взаимодействия для создания и работы с вашим 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**, что функция, расположенная прямо под ним, отвечает за обработку запросов, поступающих по адресу: * путь `/` -* использующих get операцию +* использующих операцию get -/// 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`. diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md index c596abe1f..4413efcf8 100644 --- a/docs/ru/docs/tutorial/handling-errors.md +++ b/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] *} -В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений. +В этом примере вы просто выводите в терминал ошибку с очень выразительным сообщением, но вы поняли основную идею. Вы можете использовать исключение и затем просто повторно использовать стандартные обработчики исключений. diff --git a/docs/ru/docs/tutorial/index.md b/docs/ru/docs/tutorial/index.md index ddca2fbb1..9282c0c9e 100644 --- a/docs/ru/docs/tutorial/index.md +++ b/docs/ru/docs/tutorial/index.md @@ -1,36 +1,60 @@ # Учебник - Руководство пользователя -В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций. +Этот учебник показывает, как использовать **FastAPI** со многими его функциями, шаг за шагом. -Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API. +Каждый раздел постепенно опирается на предыдущие, но структура разбита на отдельные темы, чтобы вы могли перейти прямо к любой конкретной теме для решения своих специфичных нужд API. -Он также создан для использования в качестве будущего справочника. +Он также создан для использования в качестве справочной информации в будущем, чтобы вы могли возвращаться и находить именно то, что вам нужно. -Так что вы можете вернуться и посмотреть именно то, что вам нужно. +## Запуск кода -## Запустите код +Все блоки кода можно копировать и использовать напрямую (это действительно проверенные файлы Python). -Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python). - -Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `uvicorn` с параметрами: +Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с помощью:
```console -$ uvicorn main:app --reload +$ fastapi dev main.py + + FastAPI Начало работы сервера разработки 🚀 + + Поиск структуры файлов пакета в каталогах + с файлами __init__.py + Импорт из /home/user/code/awesomeapp + + module 🐍 main.py + + code Импорт объекта приложения FastAPI из модуля со + следующим кодом: + + from main import app + + app Использование строки импорта: main:app + + server Сервер запущен на http://127.0.0.1:8000 + server Документация доступна по адресу http://127.0.0.1:8000/docs + + tip Запущен в режиме разработки, для продакшена используйте: + fastapi run -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. + Логи: + + INFO Будет отслеживать изменения в этих каталогах: + ['/home/user/code/awesomeapp'] + INFO Uvicorn запущен на http://127.0.0.1:8000 (нажмите CTRL+C + для выхода) + INFO Запущен процесс автоперезагрузки [383138] с использованием WatchFiles + INFO Запущен процесс сервера [383153] + INFO Ожидание запуска приложения. + INFO Запуск приложения завершен. ```
-**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально. +**Настоятельно рекомендуется** написать или скопировать код, отредактировать его и запустить локально. -Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д. +Использование кода в вашем редакторе действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д. --- @@ -38,46 +62,34 @@ $ uvicorn main:app --reload Первый шаг — установить FastAPI. -Для руководства вы, возможно, захотите установить его со всеми дополнительными зависимостями и функциями: +Убедитесь, что вы создали [виртуальную среду](../virtual-environments.md){.internal-link target=_blank}, активировали ее, а затем **установили FastAPI**:
```console -$ pip install "fastapi[all]" +$ pip install "fastapi[standard]" ---> 100% ```
-...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код. - -/// note | Технические детали - -Вы также можете установить его по частям. +/// note | Примечание -Это то, что вы, вероятно, сделаете, когда захотите развернуть свое приложение в рабочей среде: +При установке с помощью `pip install "fastapi[standard]"` поставляются некоторые стандартные дополнительные зависимости, включая `fastapi-cloud-cli`, который позволяет развертывать приложения на FastAPI Cloud. -``` -pip install fastapi -``` - -Также установите `uvicorn` для работы в качестве сервера: - -``` -pip install "uvicorn[standard]" -``` +Если вы не хотите иметь эти необязательные зависимости, вы можете установить `pip install fastapi`. -И то же самое для каждой из необязательных зависимостей, которые вы хотите использовать. +Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, вы можете установить с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. /// ## Продвинутое руководство пользователя -Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**. +Существует также **Продвинутое руководство пользователя**, которое вы можете прочитать после **Учебника - Руководства пользователя**. -**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям. +**Продвинутое руководство пользователя** основывается на этом, использует те же концепции и обучает вас некоторым дополнительным функциям. -Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). +Но сначала вам следует прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). -Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**. +Он разработан так, чтобы вы могли создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших нужд, с использованием некоторых дополнительных идей из **Продвинутого руководства пользователя**. diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md index 845e881e1..609dc19ca 100644 --- a/docs/ru/docs/tutorial/middleware.md +++ b/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 | Совет -Имейте в виду, что можно добавлять свои собственные заголовки при помощи префикса 'X-'. +Имейте в виду, что вы можете добавлять собственные закрытые заголовки с помощью префикса 'X-'. -Если же вы хотите добавить собственные заголовки, которые клиент сможет увидеть в браузере, то вам потребуется добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию Starlette's CORS docs. +Но если у вас есть собственные заголовки, которые вы хотите показать клиенту в браузере, вам необходимо добавить их в конфигурации CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) с использованием параметра `expose_headers`, документированного в документации по CORS Starlette. /// @@ -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 | Совет -Мы используем `time.perf_counter()` вместо `time.time()` для обеспечения большей точности наших примеров. 🤓 +Здесь мы используем `time.perf_counter()` вместо `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}. -В следующем разделе вы можете прочитать, как настроить CORS с помощью middleware. +В следующем разделе вы узнаете, как настроить CORS с помощью промежуточного ПО. diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md index 13b7015db..bfa043cee 100644 --- a/docs/ru/docs/tutorial/query-params-str-validations.md +++ b/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 (ниже 0.95.0) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню. +В предыдущих версиях FastAPI (до 0.95.0) требовалось использовать `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` может принимать более одной аннотации метаданных, то теперь вы можете использовать ту же функцию с другими инструментами, например Typer. 🚀 +Так как `Annotated` может иметь более одной аннотации метаданных, вы теперь даже можете использовать одну и ту же функцию с другими инструментами, такими как Typer. 🚀 -## Больше валидации +## Дополнительная валидация Вы также можете добавить параметр `min_length`: {* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *} -## Регулярные выражения +## Добавление регулярных выражений -Вы можете определить регулярное выражение, которому должен соответствовать параметр: +Вы можете определить регулярное выражение `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, раздел Обязательные Опциональные поля. +Когда вы явно определяете 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 обновится соответственно, чтобы разрешить множество значений: -### 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] *} ## Устаревшие параметры -Предположим, вы больше не хотите использовать какой-либо параметр. +Теперь предположим, вам больше не нравится этот параметр. -Вы решили оставить его, потому что клиенты всё ещё им пользуются. Но вы хотите отобразить это в документации как устаревший функционал. +Вы должны оставить его на некоторое время, потому что клиенты все еще его используют, но вы хотите, чтобы в документации он явно отображался как устаревший. -Тогда для `Query` укажите параметр `deprecated=True`: +Затем передайте параметр `deprecated=True` в `Query`: {* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *} -В документации это будет отображено следующим образом: +Документация будет отображать это так: -## Исключить из 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`). + +Вы можете это сделать, используя Pydantic's `AfterValidator` внутри `Annotated`. + +/// tip | Подсказка + +Pydantic также имеет `BeforeValidator` и другие. 🤓 + +/// + +Например, этот кастомный валидатор проверяет, что идентификатор предмета начинается с `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()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. + +Мы преобразуем этот итерируемый объект в полноценный `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`. -В следующих главах вы увидете, как объявлять правила валидации для других типов (например, чисел). +Смотрите следующие главы, чтобы узнать, как объявлять валидации для других типов, таких как числа. diff --git a/docs/ru/docs/tutorial/response-status-code.md b/docs/ru/docs/tutorial/response-status-code.md index b46f656f3..32190c81c 100644 --- a/docs/ru/docs/tutorial/response-status-code.md +++ b/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`, например, из библиотеки `http.HTTPStatus` в Python. +`status_code` может также принимать `IntEnum`, такой как `http.HTTPStatus` в Python. /// Это позволит: -* Возвращать указанный код статуса в ответе. -* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательском интерфейсе): +* Возвращать указанный код состояния в ответе. +* Документировать его в OpenAPI схеме (и, соответственно, в пользовательских интерфейсах): /// 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 кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с документацией MDN об HTTP кодах статуса ответа. +Чтобы узнать больше о каждом коде состояния и их значении, ознакомьтесь с документацией MDN о HTTP кодах состояния. /// -## Краткие обозначения для запоминания названий кодов +## Удобные сокращения для запоминания названий -Рассмотрим предыдущий пример еще раз: +Давайте еще раз рассмотрим предыдущий пример: {* ../../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] *} -Они содержат те же числовые значения, но позволяют использовать подсказки редактора для выбора кода статуса: +Они являются просто удобством, они содержат те же числа, но позволяют использовать автодополнение редактора для их выбора: /// 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}, вы узнаете, как возвращать другой код состояния, отличный от объявленного здесь по умолчанию. diff --git a/docs/ru/docs/tutorial/sql-databases.md b/docs/ru/docs/tutorial/sql-databases.md index b127e44d5..383059f2d 100644 --- a/docs/ru/docs/tutorial/sql-databases.md +++ b/docs/ru/docs/tutorial/sql-databases.md @@ -1,18 +1,18 @@ # SQL (реляционные) базы данных -**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которой хотите. +**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которую хотите. -В этом разделе мы продемонстрируем, как работать с SQLModel. +В этом разделе мы рассмотрим пример использования SQLModel. -Библиотека **SQLModel** построена на основе SQLAlchemy и Pydantic. Она была разработана автором **FastAPI** специально для приложений на основе FastAPI, которые используют **реляционные базы данных**. +**SQLModel** построен на основе SQLAlchemy и Pydantic. Он был создан тем же автором, что и **FastAPI**, для обеспечения идеальной совместимости приложений на FastAPI, использующих **реляционные базы данных**. -/// tip | Подсказка +/// tip | Совет -Вы можете воспользоваться любой библиотекой для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных. (Их ещё называют **ORM** библиотеками). 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 и дополнительные инструменты https://github.com/fastapi/full-stack-fastapi-template +Существует официальный генератор проектов с **FastAPI** и **PostgreSQL**, включающий frontend и другие инструменты: https://github.com/fastapi/full-stack-fastapi-template /// -Это очень простое и короткое руководство, поэтому, если вы хотите узнать о базах данных в целом, об SQL, разобраться с более продвинутым функционалом, то воспользуйтесь документацией SQLModel. +Это очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, о SQL или более продвинутых функциях, обратитесь к документации SQLModel. ## Установка `SQLModel` -Создайте виртуальное окружение [virtual environment](../virtual-environments.md){.internal-link target=_blank}, активируйте его и установите `sqlmodel`: +Сначала убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его и затем установили `sqlmodel`:
@@ -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, но на данный момент вы просто можете использовать -Alembic напрямую. +SQLModel будет иметь утилиты миграции, оборачивающие Alembic, но сейчас вы можете использовать Alembic напрямую. /// -### Создание героя (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] *} ### Запуск приложения -Вы можете запустить приложение следующим образом: +Вы можете запустить приложение:
@@ -160,49 +159,49 @@ $ fastapi dev main.py
-Далее перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует модели для создания документации API. Эти же модели используются для сериализации и проверки данных. +Затем перейдите в пользовательский интерфейс `/docs`, вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также использует их для **сериализации** и **проверки** данных.
-## Добавление в приложение дополнительных (вспомогательных) моделей +## Обновление приложения с несколькими моделями -Теперь давайте проведём **рефакторинг** нашего приложения, чтобы сделать его более безопасным и более универсальным. +Теперь давайте немного **отрефакторим** приложение для повышения **безопасности** и **универсальности**. -Обратите внимание, что на данном этапе наше приложение позволяет на уровне клиента определять `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
-Если вы перейдете в пользовательский интерфейс API `/docs`, то вы увидите, что он был обновлен, и больше не принимает параметра `id` от клиента при создании нового героя, и т.д. +Если вы зайдете в пользовательский интерфейс `/docs`, вы увидите, что он теперь обновлен, и не будет ожидать получить `id` от клиента при создании героя и т.д.
@@ -353,6 +352,6 @@ $ fastapi dev main.py ## Резюме -Вы можете использовать **SQLModel** для взаимодействия с реляционными базами данных, а также для упрощения работы с **моделями данных** и **моделями таблиц**. +Вы можете использовать **SQLModel** для взаимодействия с реляционными базами данных и упрощения работы с *моделями данных* и *моделями таблиц*. -Вы можете узнать гораздо больше информации в документации по **SQLModel**. Там вы найдете более подробное мини-руководство по использованию SQLModel с **FastAPI**. 🚀 +Вы можете узнать намного больше в документации **SQLModel**, там есть более длительное мини-руководство по использованию SQLModel с **FastAPI**. 🚀 diff --git a/docs/ru/docs/virtual-environments.md b/docs/ru/docs/virtual-environments.md index 777adaf22..7bdf7d8d7 100644 --- a/docs/ru/docs/virtual-environments.md +++ b/docs/ru/docs/virtual-environments.md @@ -1,71 +1,69 @@ -# Виртуальная среда +# Виртуальные среды -При работе с проектами в Python рекомендуется использовать **виртуальную среду разработки** (или какой-нибудь другой подобный механизм). Это нужно для того, чтобы изолировать устанавливаемые пакеты для каждого отдельного проекта. +Когда вы работаете над проектами на Python, рекомендуется использовать **виртуальную среду** (или аналогичный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта. -/// info | Дополнительная информация +/// info | Информация -Если вы уже знакомы с виртуальными средами разработки, знаете как их создавать и использовать, то вы можете свободно пропустить данный раздел. 🤓 +Если вы уже знаете о виртуальных средах, как их создавать и использовать, вы можете пропустить этот раздел. 🤓 /// -/// tip | Подсказка +/// tip | Совет -**Виртуальная среда** и **переменная окружения** это две разные вещи. +**Виртуальная среда** отличается от **переменной окружения**. -**Переменная окружения** это системная переменная, которую могут использовать программы. +**Переменная окружения** — это системная переменная, которую могут использовать программы. -**Виртуальная среда** это папка, содержащая файлы. +**Виртуальная среда** — это директория, содержащая некоторые файлы. /// -/// info | Дополнительная информация +/// info | Информация -В этом разделе мы научим вас пользоваться виртуальными средами разработки и расскажем, как они работают. +На этой странице вы узнаете, как использовать **виртуальные среды** и как они работают. -Если же вы готовы воспользоваться инструментом, **который умеет управлять всем, что касается Python-проектов**, -(включая установку Python), то попробуйте uv. +Если вы готовы использовать **инструмент, который управляет всем** для вас (включая установку Python), попробуйте uv. /// ## Создание проекта -В первую очередь, создайте директорию для вашего проекта. +Сначала создайте директорию для вашего проекта. -Я обычно создаю папку под названием `code` внутри моего домашнего каталога `/home/user`. +Обычно я создаю директорию с названием `code` внутри своего домашнего каталога. -Затем внутри данной папки я создаю отдельную директорию под каждый свой проект. +И внутри этой директории я создаю по одной директории на каждый проект.
```console -// Перейдите в домашний каталог +// Перейти в домашний каталог $ cd -// Создайте отдельную папку под все будущие программные проекты (code) +// Создать директорию для всех проектов $ mkdir code -// Войдите в директорию code +// Войти в эту директорию $ cd code -// Создайте директрорию под данный проект (awesome-project) +// Создать директорию для этого проекта $ mkdir awesome-project -// Перейдите в созданную директорию проекта +// Войти в директорию проекта $ cd awesome-project ```
-## Создание виртуальной среды разработки +## Создание виртуальной среды -Начиная работу с Python-проектом, сразу же создавайте виртуальную среду разработки -**внутри вашего проекта**. +Когда вы впервые начинаете работу над проектом на Python, создайте виртуальную среду **внутри вашего проекта**. -/// tip | Подсказка +/// tip | Совет -Виртуальная среда разработки создается один раз, и в дальнейшем, работая с проектом, этого больше делать не придется. +Это нужно сделать только **один раз для проекта**, а не каждый раз, когда вы работаете. /// //// tab | `venv` -Для создания виртуальной среды вы можете воспользоваться модулем `venv`, который является частью встроенной библиотеки Python. +Для создания виртуальной среды вы можете использовать модуль `venv`, который поставляется с Python.
@@ -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` -Если вы установили `uv`, то вы можете им воспользоваться для создания виртуальной среды разработки. +Если у вас установлен `uv`, вы можете использовать его для создания виртуальной среды.
@@ -98,31 +96,31 @@ $ uv venv
-/// 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 (напр. Git Bash): +Или, если вы используете Bash для Windows (например, Git Bash):
@@ -164,13 +162,21 @@ $ source .venv/Scripts/activate //// +/// tip | Совет + +Каждый раз при установке **нового пакета** в эту среду **активируйте** её снова. + +Это гарантирует, что если вы используете **программу терминала (CLI)**, установленную этим пакетом, вы будете использовать её из вашей виртуальной среды, а не любую другую, установленную глобально, вероятно, с другой версией, чем вам нужно. + +/// + ## Проверка активации виртуальной среды -Проверьте, активна ли виртуальная среда (удостоверимся, что предыдущая команда сработала). +Проверьте, активна ли виртуальная среда (предыдущая команда сработала). -/// tip | Подсказка +/// tip | Совет -Убедитесь в том, что все работает так, как нужно и вы используете именно ту виртуальную среду разработки, которую нужно. Делать это необязательно, но желательно. +Это **не обязательно**, но это хороший способ **убедиться**, что всё работает как ожидалось, и вы используете именно ту виртуальную среду, которую планировали. /// @@ -186,7 +192,7 @@ $ which python
-Если данная команда показывает, что исполняемый файл `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
-Если данная команда показывает, что исполняемый файл `python` (`.venv\Scripts\python`), находится внутри виртуальной среды вашего проекта (у нас это `awesome-project`), значит все отработало как нужно. 🎉 +Если показывает, что `python` находится в `.venv\Scripts\python` внутри вашего проекта (в данном случае `awesome-project`), значит, всё сработало. 🎉 //// ## Обновление `pip` -/// tip | Подсказка +/// tip | Совет -Если вы используете `uv`, то вы должны будете его использовать для установки пакетов вместо `pip`, поэтому обновлять `pip` вам ненужно. 😎 +Если вы используете `uv`, то будете использовать его для установки пакетов вместо `pip`, поэтому обновлять `pip` не нужно. 😎 /// -Если для установки пакетов вы используете `pip` (он устанавливается по умолчанию вместе с Python), то обновите `pip` до последней версии. +Если вы используете `pip` для установки пакетов (он по умолчанию поставляется с Python), стоит **обновить** его до последней версии. -Большинство экзотических ошибок, возникающих при установке пакетов, устраняется предварительным обновлением `pip`. +Многие экзотические ошибки при установке пакетов решаются просто обновлением `pip`. -/// tip | Подсказка +/// tip | Совет -Обычно это делается только один раз, сразу после создания виртуальной среды разработки. +Обычно это делается **один раз**, сразу после создания виртуальной среды. /// -Убедитесь в том, что виртуальная среда активирована (с помощью вышеуказанной команды) и запустите следующую команду: +Убедитесь, что виртуальная среда активирована (используя команду выше), и затем выполните:
@@ -238,17 +244,17 @@ $ python -m pip install --upgrade pip ## Добавление `.gitignore` -Если вы используете **Git** (а вы должны его использовать), то добавьте файл `.gitignore` и исключите из Git всё, что находится в папке `.venv`. +Если вы используете **Git** (а вы должны), добавьте файл `.gitignore`, чтобы исключить всё содержимое вашей папки `.venv` из Git. -/// tip | Подсказка +/// tip | Совет -Если для создания виртуальной среды вы используете `uv`, то для вас все уже сделано и вы можете пропустить этот шаг. 😎 +Если вы использовали `uv` для создания виртуальной среды, это уже сделано за вас, можете пропустить этот шаг. 😎 /// -/// 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` -Если вы используете `uv`: +Если у вас установлен `uv`:
@@ -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` -Если вы используете `uv`: +Если у вас установлен `uv`:
@@ -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 внутри вашей виртуальной среды с установленными там пакетами.
@@ -386,22 +392,22 @@ Hello World ## Настройка редактора -Вероятно, вы захотите воспользоваться редактором. Убедитесь, что вы настроили его на использование той самой виртуальной среды, которую вы создали. (Скорее всего, она автоматически будет обнаружена). Это позволит вам использовать авто-завершение и выделение ошибок в редакторе. +Вы, вероятно, будете использовать редактор, убедитесь, что настроили его на использование той же виртуальной среды, которую вы создали (скорее всего, он её автоматически распознает), чтобы вы могли использовать автозавершение и видеть ошибки в коде. Например: * VS Code * PyCharm -/// tip | Подсказка +/// tip | Совет -Обычно это делается один раз, при создании виртуальной среды разработки. +Обычно это делается **один раз**, когда вы создаете виртуальную среду. /// -## Деактивация виртуальной среды разработки +## Деактивация виртуальной среды -По окончании работы над проектом вы можете деактивировать виртуальную среду. +После завершения работы над проектом вы можете **деактивировать** виртуальную среду.
@@ -411,55 +417,55 @@ $ deactivate
-Таким образом, при запуске `python`, будет использована версия `python` установленная глобально, а не из этой виртуальной среды вместе с установленными в ней пакетами. +Таким образом, при запуске `python`, он не будет использовать версию из этой виртуальной среды с установленными там пакетами. -## Все готово к работе +## Готовность к работе -Теперь вы готовы к тому, чтобы начать работу над своим проектом. +Теперь вы готовы приступить к работе над своим проектом. -/// tip | Подсказка +/// tip | Совет -Хотите разобраться со всем, что написано выше? +Хотите понять всё, что написано выше? -Продолжайте читать. 👇🤓 +Продолжайте чтение. 👇🤓 /// -## Зачем использовать виртуальную среду? +## Зачем виртуальные среды -Для работы с FastAPI вам потребуется установить Python. +Для работы с FastAPI вам нужно установить Python. -После этого вам нужно будет **установить** 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`, например, с помощью:
@@ -469,7 +475,7 @@ $ pip install "harry==1"
-И тогда в вашем глобальном окружении 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`).
@@ -491,9 +497,9 @@ $ pip install "harry==3"
-И тогда, в вашей глобальной среде окружения 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, это создаёт на вашем компьютере некоторые каталоги с некоторыми файлами. -Среди них есть каталоги, отвечающие за хранение всех устанавливаемых вами пакетов. +Некоторые из этих каталогов являются теми, которые хранят все установленные вами пакеты. -Когда вы запустите команду: +Когда вы запускаете:
```console -// Не запускайте эту команду, это просто пример 🤓 +// Не запускайте это сейчас, это лишь пример 🤓 $ pip install "fastapi[standard]" ---> 100% ```
-То будет скачан сжатый файл, содержащий код FastAPI, обычно скачивание происходит с PyPI. +Это загрузит сжатый файл с кодом FastAPI, обычно с PyPI. -Также будут скачаны файлы, содержащие пакеты, которые использует 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 (напр. Git Bash): +Или, если вы используете Bash для Windows (например, Git Bash):
@@ -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
-Если вы не деактивировали виртуальное окружение проекта `philosophers-stone`, то при запуске `python` через консоль будет вызван Python из `philosophers-stone` +Если вы не деактивируете виртуальную среду для `philosophers-stone`, то когда вы запускаете `python` в терминале, он попытается использовать Python из `philosophers-stone`.
@@ -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 import sirius @@ -794,46 +799,46 @@ Traceback (most recent call last):
-Но если вы деактивируете виртуальную среду разработки и активируете новую среду для `prisoner-of-askaban`, то вы тогда запустите Python из виртуального окружения `prisoner-of-azkaban`. +Но если вы деактивируете виртуальную среду и активируете новую для `prisoner-of-askaban`, то когда вы запускаете `python`, он будет использоваться Python из виртуальной среды в проекте `prisoner-of-azkaban`.
```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 -Я торжественно клянусь в этом! 🐺 +Я торжественно клянусь 🐺 ```
## Альтернативы -Это простое руководство поможет вам начать работу и научит тому, как всё работает **изнутри**. +Это простое руководство поможет вам начать работу и научит тому, как всё работает **внутри**. -Существует много альтернативных решений для работы с виртуальными средами разработки, с программными зависимостями, а также с проектами. +Существуют также **альтернативные** решения для управления виртуальными средами разработки, зависимостями пакетов (требования), проектами. -Когда вы будете готовы использовать единый инструмент для управления проектом, программными зависимостями, виртуальными средами разработки и т.д., то я рекомендую вам попробовать uv. +Когда вы будете готовы и захотите использовать инструмент для **управления всем проектом**, зависимостями пакетов, виртуальными средами и т.д., я бы рекомендовал вам попробовать uv. -`uv` может очень многое. Он умеет: +`uv` может делать много всего, он может: -* **Устанавливать Python**, включая установку различных версий -* Управлять средой виртуального окружения вашего проекта +* **Установить Python** для вас, включая разные версии +* Управлять **виртуальной средой** для ваших проектов * Устанавливать **пакеты** -* Управлять пакетами и их версиями внутри вашего проекта -* Удостовериться, что вы используете **точный** набор пакетов и версий при установке, включая зависимости. Таким образом, вы можете быть уверенны, что проект, запускается в production, точно также, как и при разработке, этот механизм называется *locking* -* Многие другие вещи +* Управлять зависимостями пакетов **и версиями** для вашего проекта +* Обеспечить наличие **точного** набора пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что ваш проект будет работать в production точно так же, как и на вашем компьютере во время разработки, это называется *locking* +* И многое другое ## Заключение -Если вы прочитали и поняли всё это, то теперь вы знаете **гораздо больше** о виртуальных средах разработки, чем многие другие разработчики. 🤓 +Если вы прочитали и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных средах, чем многие другие разработчики. 🤓 -Скорее всего, знание этих деталей будет полезно вам в будущем. Когда вы будете отлаживать что-то, кажущееся сложным, вы будете знать, **как это работает под капотом**. 😎 +Знание этих деталей, скорее всего, будет полезно вам в будущем, когда вы будете отлаживать что-то, что кажется сложным, но вы будете знать, **как всё работает внутри**. 😎 From 60e272d7aa6706db3f3f04a182e5242f1ce7ca1b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 27 Jul 2025 10:31:12 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20for?= =?UTF-8?q?mat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ru/docs/tutorial/first-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md index 5b37c2b7c..9cba3e02f 100644 --- a/docs/ru/docs/tutorial/first-steps.md +++ b/docs/ru/docs/tutorial/first-steps.md @@ -21,7 +21,7 @@ $ fastapi dev module 🐍 main.py - code Импортируем объект приложения FastAPI из модуля с + code Импортируем объект приложения FastAPI из модуля с помощью следующего кода: from main import app From e5aedbdb77b2dc171d6559b5659df8c1c023698e Mon Sep 17 00:00:00 2001 From: Yurii Motov Date: Thu, 31 Jul 2025 16:19:56 +0200 Subject: [PATCH 3/5] Update translations with new prompts --- docs/ru/docs/async.md | 206 +++++++------ docs/ru/docs/benchmarks.md | 44 ++- docs/ru/docs/deployment/manually.md | 102 +++---- docs/ru/docs/help-fastapi.md | 150 +++++----- docs/ru/docs/index.md | 79 ++--- docs/ru/docs/project-generation.md | 32 +- docs/ru/docs/tutorial/body-multiple-params.md | 46 +-- docs/ru/docs/tutorial/cors.md | 21 +- docs/ru/docs/tutorial/extra-models.md | 23 +- docs/ru/docs/tutorial/first-steps.md | 52 ++-- docs/ru/docs/tutorial/handling-errors.md | 20 +- docs/ru/docs/tutorial/index.md | 66 ++--- docs/ru/docs/tutorial/middleware.md | 28 +- .../tutorial/query-params-str-validations.md | 128 ++++---- docs/ru/docs/tutorial/response-status-code.md | 60 ++-- docs/ru/docs/tutorial/sql-databases.md | 174 +++++------ docs/ru/docs/virtual-environments.md | 280 +++++++++--------- 17 files changed, 767 insertions(+), 744 deletions(-) diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md index 1f467f646..5973e0df7 100644 --- a/docs/ru/docs/async.md +++ b/docs/ru/docs/async.md @@ -1,18 +1,18 @@ # Конкурентность и async / await -Подробности о синтаксисе `async def` для *функций обработки пути* и некоторые сведения об асинхронном коде, конкурентности и параллелизме. +Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций-обработчиков пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма. ## В спешке? -TL;DR: +TL;DR: -Если вы используете сторонние библиотеки, которые требуют вызова с ключевым словом `await`, как: +Если вы используете сторонние библиотеки, которые требуют вызова с ключевым словом `await`, как, например: ```Python results = await some_library() ``` -Тогда объявляйте свои *функции обработки пути* с использованием `async def`, как: +В этом случае *функции-обработчики пути* необходимо объявлять с использованием синтаксиса `async def`: ```Python hl_lines="2" @app.get('/') @@ -29,7 +29,7 @@ async def read_results(): --- -Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т. д.) и не поддерживает использование `await`, (это в настоящее время относится к большинству библиотек для работы с базами данных), то объявляйте свои *функции обработки пути* как обычно, просто с `def`, как: +Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует (с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await` (что относится сейчас к большинству библиотек для работы с базами данных), то объявляйте *функции-обработчики пути* обычным образом с помощью `def`, например: ```Python hl_lines="2" @app.get('/') @@ -40,7 +40,7 @@ def results(): --- -Если вашему приложению (каким-то образом) не нужно взаимодействовать ни с чем и ждать ответа, используйте `async def`, даже если вам не нужно использовать `await` внутри. +Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно, ожидать ответа, используйте `async def`, даже если внутри нет необходимости в `await`. --- @@ -48,7 +48,7 @@ def results(): --- -**Примечание**: Вы можете смешивать `def` и `async def` в своих *функциях обработки пути* столько, сколько вам нужно, и определять каждую с использованием наилучшего для вас варианта. FastAPI сделает с ними всё как надо. +**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях-обработчиках пути* и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно. В любом случае, в любой из упомянутых выше ситуаций, FastAPI всё равно будет работать асинхронно и с высокой скоростью. @@ -66,7 +66,7 @@ def results(): ## Асинхронный код -Асинхронный код просто значит, что язык 💬 имеет способ сообщить компьютеру / программе 🤖, что в какой-то момент в коде, ему 🤖 нужно будет дождаться, пока *что-то ещё* завершится где-то ещё. Пусть это *что-то ещё* называется "медленный файл" 📝. +Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖, что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝. Так что, в это время, компьютер может выполнять какую-то другую работу, пока "медленный файл" 📝 заканчивается. @@ -85,13 +85,13 @@ def results(): * ожидание, когда запрос к базе данных вернёт результаты * и т. д. -Поскольку основное время выполнения тратится на ожидание операций I/O, их называют операциями, "связанными с вводом-выводом" (I/O bound). +Поскольку в основном время тратится на ожидание выполнения операций I/O, их обычно называют операциями, ограниченными скоростью ввода-вывода. -Это называется "асинхронным", потому что компьютер / программе не нужно "синхронизироваться" с медленной задачей и ожидать момент, когда задача завершится, ничего не делая, чтобы затем взять результат задачи и продолжить работу. +Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и, будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу. -Вместо этого, в "асинхронной" системе завершённая задача может чуть-чуть подождать (несколько микросекунд), пока компьютер / программа завершит выполнение того, что она занималась, а потом вернуться, чтобы взять результаты и продолжить их обработку. +Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд), пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться, забрать результаты выполнения и начать их обрабатывать. -Для "синхронного" (в отличие от "асинхронного") часто используют термин "последовательный", потому что компьютер / программа проходит все шаги последовательно перед переключением на другую задачу, даже если они включают в себя ожидание. +"Синхронное" исполнение (в противовес "асинхронному") также называют "последовательным", потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче, даже если в процессе приходится ждать. ### Конкурентность и бургеры @@ -105,63 +105,65 @@ def results(): ### Конкурентные бургеры -Вы идёте с вашей возлюбленной в фастфуд, становитесь в очередь, пока кассир принимает заказы у людей перед вами. 😍 +Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами. -Затем наступает ваша очередь, вы заказываете 2 очень вкусных бургеров для вашей возлюбленной и для вас. 🍔🍔 +Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе. -Кассир что-то говорит повару на кухне, чтобы они знали, что надо приготовить ваши бургеры (даже если они в данный момент готовят бургеры для предыдущих клиентов). +Отдаёте деньги 💸. - +Кассир 💁 что-то говорит поварам на кухне 👨‍🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔 (но пока они заняты бургерами предыдущих клиентов). -Вы платите. 💸 + Кассир даёт вам номер вашего заказа. -В ожидании еды, вы идёте с вашей возлюбленной выбрать столик, садитесь и долго разговариваете с вашей возлюбленной (поскольку ваши бургеры очень вкусные и их приготовление занимает некоторое время). + + +В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍 (поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨). -Сидя за столиком с вашей возлюбленной, пока вы ждёте бургеры, вы тратите это время, чтобы восхищаться тем, насколько ваша возлюбленная замечательная, милая и умная ✨😍✨. +Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время, восхищаясь её великолепием, красотой и умом ✨😍✨. -Во время ожидания и разговора с вашей возлюбленной время от времени вы проверяете номер, отображаемый на стойке, чтобы увидеть, не наступило ли ваше ожидание. +Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете, какой номер горит над прилавком, и не подошла ли уже ваша очередь. -Затем в какой-то момент это наконец ваша очередь. Вы идёте к стойке, забираете свои бургеры и возвращаетесь к столу. +И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик. -Вы и ваша возлюбленная едите бургеры и наслаждаетесь временем вместе. ✨ +Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨. /// info | Информация -Прекрасные иллюстрации от Кетрины Томпсон. 🎨 +Прекрасные иллюстрации от Ketrina Thompson. 🎨 /// --- -Представьте, что в этой истории вы — компьютер / программа 🤖. +А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖. -В очереди вы бездействуете 😴, ожидая своей очереди, особо ничего "продуктивного" не делая. Но очередь быстро движется, так как кассир только берёт заказы (а не готовит их), так что это нормально. +В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете. Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного. Затем, когда наступает ваша очередь, вы делаете настоящую "продуктивную" работу, обрабатываете меню, решаете, что хотите, узнаёте выбор вашей возлюбленной, оплачиваете, проверяете, что даёте правильную сумму или карту, проверяете, правильно ли с вас взяли оплату, содержится ли в заказе всё, что нужно, и так далее. -Но потом, хотя вы всё еще не получили свои бургеры, ваша работа с кассиром "на паузе" ⏸, потому что вы должны ждать 🕙, пока приготовятся ваши бургеры. +И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸, поскольку теперь нужно ждать 🕙, когда заказ приготовят. -Но уходя от стойки и садясь за столик с номером вашего заказа, вы можете переключить 🔀 своё внимание на свою возлюбленную, и "работать" ⏯ 🤓 над этим. Таким образом, вы снова делаете что-то очень "продуктивное", как флирт с вашей возлюбленной 😍. +Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень "продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍. Кассир 💁 говорит "я закончил делать бургеры" через показ номера вашего заказа на табло, но вы не вскакиваете, как сумасшедший, когда отображаемый номер меняется на номер вашей очереди. Вы знаете, что никто не украдёт у вас бургеры, потому что у вас есть номер вашего заказа, а у других — свои. -Поэтому вы ждёте, пока ваша возлюбленная закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓), мило улыбаетесь и говорите, что идёте забирать бургеры ⏸. +Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓) и мило улыбнувшись, скажете, что идёте забирать заказ ⏸. -Затем вы идёте к стойке 🔀, к первоначальной задаче, которая завершена ⏯, берете бургеры, говорите спасибо и возвращаетесь за столик. Это завершает эту часть / задание взаимодействия с кассиром ⏹. Это, в свою очередь, создаёт новую задачу — "есть бургеры" 🔀 ⏯, но предыдущая — "получить бургеры" завершена ⏹. +И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹. В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹. ### Параллельные бургеры @@ -169,15 +171,19 @@ def results(): Вы идёте с вашей возлюбленной попробовать параллельный фастфуд. -Вы стоите в очереди, пока несколько (скажем, 8) кассиров, которые одновременно являются поварами, принимают заказы у людей перед вами. +Вы становитесь в очередь, пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами. + + -Все перед вами ожидают, когда их бургеры будут готовы до того, как они покинут кассу, поскольку каждый из 8 кассиров сразу идет и готовит бургер, прежде чем получить следующий заказ. +При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ. Затем, наконец, наступает ваша очередь, вы заказываете 2 очень вкусных бургера для вашей возлюбленной и вас. -Вы оплачиваете 💸. +Ни о чём не жалея, расплачиваетесь 💸. + + @@ -187,35 +193,37 @@ def results(): -Поскольку вы и ваша возлюбленная заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они прибудут, вы не можете уделить внимания вашей возлюбленной. 😞 + + +Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь, у вас не получается уделять должного внимание своей даме сердца 😞. -Это "синхронная" работа: вы "синхронизированы" с кассиром/поваром 👨‍🍳. Вам приходится ждать 🕙 и быть там в точный момент, когда кассир/повар 👨‍🍳 завершает приготовление бургеров и отдаёт их вам, иначе кто-то может их взять. +Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки, когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой. -Затем ваш кассир/повар 👨‍🍳 наконец возвращается с вашими бургерами, после долгого ожидания 🕙 перед стойкой. +Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой. -Вы берёте ваши бургеры и идёте за столик с вашей возлюбленной. +Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик. -Вы их просто кушаете, и всё. ⏹ +Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹. -Обменяться словами или пофлиртовать не очень получилось, так как больше времени было потрачено на ожидание 🕙 перед стойкой. 😞 +Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞. /// info | Информация -Прекрасные иллюстрации от Кетрины Томпсон. 🎨 +Прекрасные иллюстрации от Ketrina Thompson. 🎨 /// --- -В этом сценарии с параллельными бургерами вы — это компьютер / программа 🤖 с двумя процессорами (вы и ваша возлюбленная), оба долгое время ожидающие 🕙 и посвящающие своё внимание ⏯ быть "ожидающими у кассы" 🕙. +В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍), на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе". -В этом фастфуд-магазине 8 процессоров (кассиров/поваров). Хотя в магазине конкурентных бургеров могло быть только 2 (один кассир и один повар). +В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳. Но всё же, окончательный опыт не самый лучший. 😞 @@ -235,7 +243,7 @@ def results(): ### Заключение о бургерах -В этом сценарии "быстрого питания с бургерами с вашей возлюбленной", так как там много ожидания 🕙, имеет много больше смысла иметь конкурентную систему ⏸🔀⏯. +В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙, поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯. И это и есть случай для большинства веб-приложений. @@ -243,21 +251,25 @@ def results(): И потом снова ждёт 🕙, чтобы ответы вернулись. -Это "ожидание" 🕙 измеряется в микросекундах, но в итоге, если всё сложить, это много времени ожидания. +Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени. + +Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API. + +Большинство популярных фреймворков (включая Flask и Django) создавались до появления в Python новых возможностей асинхронного программирования. Поэтому их можно разворачивать с поддержкой параллельного исполнения или асинхронного программирования старого типа, которое не настолько эффективно. -Вот почему имеет смысл использовать асинхронный код ⏸🔀⏯ для веб-API. +При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером (ASGI) была разработана командой Django для внедрения поддержки веб-сокетов. -Эта форма асинхронности является тем, что сделало NodeJS популярным (хотя NodeJS не параллелен) и это то, что делает Go мощным языком программирования. +Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный), и в этом преимущество Go как языка программирования. И это тот же уровень производительности, который вы получаете с **FastAPI**. -И так как у вас может быть параллелизм и асинхронность одновременно, вы получаете более высокую производительность, чем большинство протестированных NodeJS фреймворков, и сопоставимо с Go, который является компилируемым языком, ближе к C (всё это благодаря Starlette). +Поскольку можно использовать преимущества параллелизма и асинхронности вместе, вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков и на уровне с Go, который является компилируемым языком близким к C (всё благодаря Starlette). ### Конкуренция лучше параллелизма? Нет! Это не мораль истории. -Конкурентность отличается от параллелизма. И она лучше в **конкретных** сценариях, которые включают много ожидания. Из-за этого, обычно она намного лучше, чем параллелизм для разработки веб-приложений. Но не всегда и не для всего. +Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание. Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях. Так что, чтобы уравновесить это, представьте себе следующий короткий рассказ: @@ -269,15 +281,15 @@ def results(): Тут нет ожидания 🕙 нигде, просто много работы по разным местам дома. -Вы могли бы иметь очереди как в примере с бургерами, сначала гостиная, затем кухня, но так как вы не ждете 🕙 чего-либо, а просто убираете и убираете, очереди никак не повлияют на это. +Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня, но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете. -Добавление или отсутствие очередей (конкурентности) не увеличит или уменьшит время завершения работы, и вы выполните то же количество работы. +И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё, и работы будет сделано тоже одинаковое количество. -Но в этом случае, если бы вы могли пригласить 8 бывших кассиров/поваров/теперь-уборщиков, и каждый из них (вместе с вами) мог бы взяться за зону дома, чтобы ее убрать, вы могли бы сделать всю работу **параллельно**, с дополнительной помощью, и закончить намного быстрее. +Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, и каждый из них (вместе с вами) взялся бы за свой участок дома, с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**. В этой ситуации каждый из уборщиков (включая вас) будет процессором, выполняющим свою часть работы. -И поскольку основная часть времени выполнения уходит на реальную работу (вместо ожидания), и работа в компьютере выполняется ЦП, такие задачи называют "ограниченными производительностью процессора" (CPU bound). +И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание), а работу в компьютере делает ЦП, такие задачи называют ограниченными производительностью процессора. --- @@ -286,33 +298,33 @@ def results(): Например: * Обработка **звука** или **изображений**. -* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения / цвета, обработка этого обычно требует вычисления чего-то на этих пикселях, все одновременно. -* **Машинное обучение**: оно обычно требует множества умножений "матриц" и "векторов". Представьте огромную таблицу с числами в Экселе и умножение всех их вместе одновременно. -* **Глубокое обучение**: это подполе Машинного обучения, так что, то же самое применимо. Просто здесь не одна таблица чисел для умножения, а огромное их множество, и в многих случаях используется специальный процессор для создания и / или использования этих моделей. +* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета, обработка обычно требует проведения расчётов по всем пикселям сразу. +* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов". Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить. +* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание. Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется специальный процессор для создания и / или использования построенных таким образом моделей. ### Конкурентность + параллелизм: Веб + Машинное обучение -С **FastAPI** вы можете использовать преимуществ конкурентности, который очень распространён в веб-разработке (та же главная привлекательность NodeJS). +**FastAPI** предоставляет возможности конкуретного программирования, которое очень распространено в веб-разработке (именно этим славится NodeJS). -Но вы также можете использовать преимущества параллелизма и многопроцессорности (имеющих несколько процессов, работающих параллельно) для рабочих нагрузок, зависимых от **производительности процессора**, таких как в системах Машинного обучения. +Кроме того, вы сможете использовать все преимущества параллелизма и многопроцессорности (когда несколько процессов работают параллельно), если рабочая нагрузка предполагает **ограничение по процессору**, как, например, в системах машинного обучения. -Это, плюс простой факт, что Python является главным языком для **Дата-сайенс**, Машинного обучения и особенно глубокого обучения, делают 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`. Он сообщает Python, что нужно дождаться ⏸, пока `get_burgers(2)` завершит своё выполнение 🕙, прежде чем сохранить результаты в `burgers`. Основываясь на этом, Python сможет временно перейти к выполнению других задач 🔀 ⏯ (например, получение нового запроса). +Ключевое здесь — `await`. Оно сообщает Python, что необходимо дождаться ⏸ выполнения `get_burgers(2)` 🕙 прежде чем сохранять результат в `burgers`. Python понимает, что может переключиться на выполнение других задач 🔀 ⏯ (например, получение следующего запроса). -Чтобы `await` работал, он должен находиться внутри функции, поддерживающей асинхронность. Для этого просто объявите её с помощью `async def`: +Для работы `await`, оно должно находиться внутри функции, поддерживающей асинхронность. Это достигается объявлением с `async def`: ```Python hl_lines="1" async def get_burgers(number: int): @@ -329,9 +341,9 @@ def get_sequential_burgers(number: int): return burgers ``` -С `async def`, Python знает, что внутри этой функции ему нужно ожидать выражений `await`, и что выполнение такой функции можно будет "поставить на паузу" ⏸ и перейти к чему-то другому 🔀, прежде чем вернуться. +`async def` указывает интерпретатору на наличие ожидания `await` в функции, с возможностью "паузы" ⏸ и переключения на другие задачи 🔀 до возврата в исходное место. -Когда вы хотите вызвать функцию `async def`, вы должны "ожидать" её. Поэтому, это не сработает: +Если требуется вызвать `async def` функцию, нужно "ожидать" её. Поэтому такое не сработает: ```Python # Это не сработает, потому что get_burgers была определена с использованием: async def @@ -340,7 +352,7 @@ burgers = get_burgers(2) --- -Так, если вы используете библиотеку, которая сообщает вам, что можете вызвать её с помощью `await`, вам нужно создать *функции обработки пути*, которые её используют с `async def`, как в: +Так что, если вы используете библиотеку, которая требует вызова с `await`, создавайте *функции-обработчики пути* с использованием `async def`, например: ```Python hl_lines="2-3" @app.get('/burgers') @@ -351,94 +363,94 @@ async def read_burgers(): ### Более технические подробности -Как вы могли заметить, `await` можно использовать только внутри функций, определённых с помощью `async def`. +Вы могли заметить, что `await` может применяться только в функциях, объявленных с использованием `async def`. -Но в то же время функции, определённые с помощью `async def`, должны быть "ожиданы". Поэтому, функции с `async def` могут вызываться только внутри функций, определённых с `async def`. +Но выполнение такой функции необходимо "ожидать" через `await`. Это означает, что её можно вызвать только из другой функции, также объявленной с `async def`. -Так что как же насчёт яйца и курицы, как вызвать первую `async` функцию? +Итак, как же появилась первая *курица*? В смысле... как нам вызвать первую асинхронную функцию? -Если вы работаете с **FastAPI**, вы можете не заботиться об этом, потому что эта "первая" функция будет вашей *функцией обработки пути*, и FastAPI будет знать, как сделать всё правильно. +При работе с **FastAPI** не надо думать об этом, потому что "первой" функцией будет ваша *функция-обработчик пути*, и FastAPI будет знать, что делать. -Но если вы хотите использовать `async` / `await` без FastAPI, вы тоже можете это сделать. +Если хотите использовать `async` / `await` без FastAPI, у вас также есть такая возможность. ### Пишите свой асинхронный код -Starlette (и **FastAPI**) базируются на AnyIO, что делает их совместимыми как со стандартной библиотекой Python asyncio, так и с Trio. +Starlette (и **FastAPI**) основаны на AnyIO, что делает их совместимыми как со стандартной библиотекой asyncio в Python, так и с Trio. -В частности, вы можете напрямую использовать AnyIO для ваших продвинутых случаев использования конкурентности, которые требуют более сложных паттернов в вашем собственном коде. +В частности, вы можете напрямую использовать AnyIO для сложных случаев использования конкурентности, требующих более сложных паттернов в вашем коде. -И даже если вы не использовали FastAPI, вы всё равно могли бы написать свои собственные асинхронные приложения с помощью AnyIO, чтобы они были высоко совместимыми и получали все его преимущества (например, структурированная конкурентность). +Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью AnyIO, чтобы они были максимально совместимыми и получали его преимущества (например *структурная конкурентность*). -Я создал другую библиотеку поверх AnyIO, как тонкий слой поверх него, чтобы немного улучшить аннотации типов и получить лучшую **автодополнения**, **ошибки в строках кода** и т. д. Она также имеет дружный вводный материал и учебник, который поможет вам **понять** и писать **свой собственный асинхронный код**: Asyncer. Он будет особенно полезен, если вам нужно **сочетать асинхронный код с обычным** (блокирующим/синхронным) кодом. +Я создал другую библиотеку поверх AnyIO, как тонкий слой, чтобы немного улучшить аннотации типов и получить лучшее **автозавершение**, **встроенные ошибки** и т. д. У неё также есть дружелюбное введение и учебник, которые помогут вам **понять** и писать **свой асинхронный код**: Asyncer. Это будет особенно полезно, если вам нужно **комбинировать асинхронный код с обычным** (блокирующим/синхронным) кодом. ### Другие формы асинхронного кода Этот стиль использования `async` и `await` относительно новый в языке. -Но он сильно упрощает работу с асинхронным кодом. +Но он значительно облегчает работу с асинхронным кодом. -Этот же синтаксис (или почти идентичный) также был недавно включен в современные версии JavaScript (в браузерах и NodeJS). +Очень похожий синтаксис недавно был включён в современные версии JavaScript (в браузере и NodeJS). -Но раньше обработка асинхронного кода была намного более сложной и трудной. +До этого поддержка асинхронного кода была реализована намного сложнее и труднее воспринималась. -В предыдущих версиях Python, вы могли использовать потоки или Gevent. Но код в этом случае был намного сложнее для понимания, отладки и осмысления. +В предыдущих версиях Python для этого использовались потоки или Gevent. Но такой код сложнее для понимания, отладки и размышлений. -В предыдущих версиях NodeJS / Javascript для браузеров, для этого использовались "обратные вызовы". Что приводило к аду обратных вызовов. +В предыдущих версиях NodeJS/JavaScript использовали "обратные вызовы", что приводило к аду обратных вызовов. ## Сопрограммы -**Сопрограмма** — это просто очень крутое слово для обозначения того, что возвращается функцией `async def`. Python знает, что это что-то вроде функции, которую можно запустить, и которая закончится в какой-то момент, но которая может быть также поставлена на паузу ⏸, когда внутри встречается `await`. +**Корутина** — это крутое словечко для именования той сущности, которая возвращается функцией `async def`. Python знает, что это что-то наподобие функции, что её можно запустить и она закончится в какой-то момент, но что её выполнение может быть остановлено ⏸ внутренне с помощью `await`. -Но вся эта функциональность использования асинхронного кода с `async` и `await` часто суммируется как использование "сопрограмм". Это сопоставимо с основной ключевой особенностью Go, "Горутинами". +Вся функциональность асинхронного программирования с использованием `async` и `await` обобщается под термином "корутины". Они схожи с ключевой особенностью Go — "горутинами". ## Заключение Давайте увидим ту же фразу сверху: -> Современные версии Python поддерживают **"асинхронный код"** с использованием чего-то, называемого **"сопрограммами"**, с синтаксисом **`async` и `await`**. +> Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**. Теперь это должно звучать более понятно. ✨ -Всё это то, на чём работает FastAPI (через Starlette) и что делает его настолько невероятно производительным. +На этом основана работа FastAPI (посредством Starlette), и именно это обеспечивает его высокую производительность. ## Очень технические подробности /// warning | Предупреждение -Вы, вероятно, можете это пропустить. +Этот раздел можно пропустить. -Это очень технические подробности того, как **FastAPI** работает внутри. +Здесь приводятся очень технические подробности устройства **FastAPI** внутри. -Если у вас есть технические знания (сопрограммы, потоки, блокировки и т. д.) и вы интересуетесь тем, как FastAPI обрабатывает `async def` в отличие от обычного `def`, продолжайте. +Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.) и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`, читайте дальше. /// -### Функции обработки пути +### Функции-обработчики пути -Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def` вместо `async def`, она выполняется во внешнем пуле потоков, который затем ожидается, вместо того, чтобы быть вызванной напрямую (так как это заблокировало бы сервер). +Когда вы объявляете *функцию-обработчик пути* обычным образом с ключевым словом `def` вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем пуле потоков, а не напрямую (это бы заблокировало сервер). -Если вы приходите из другого асинхронного фреймворка, который работает не так, как описано выше, и вы привыкли определять тривиальные вычислительные *функции обработки пути* с простым `def` для маленького прироста производительности (около 100 наносекунд), обратите внимание, что в **FastAPI** эффект будет полностью противоположным. В этих случаях лучше использовать `async def`, если только ваши *функции обработки пути* не используют код, который выполняет блокирующий I/O. +Если ранее вы использовали другой асинхронный фреймворк, который работает иначе, и привыкли объявлять простые вычислительные *функции* через `def` ради незначительного прироста скорости (порядка 100 наносекунд), обратите внимание, что с **FastAPI** эффект будет обратный. В таких случаях лучше использовать `async def`, если только *функция-обработчик пути* не выполняет код, приводящий к блокировке I/O. -Тем не менее, в обеих ситуациях есть вероятность, что **FastAPI** [всё еще будет быстрее](index.md#performance){.internal-link target=_blank}, чем (или, по крайней мере, сравним с) ваш предыдущий фреймворк. +Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](index.md#performance){.internal-link target=_blank}, чем (или хотя бы на уровне с) ваш предыдущий фреймворк. ### Зависимости -Тоже самое относится к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость является стандартной функцией `def` вместо `async def`, она запускается во внешнем пуле потоков. +То же самое относится и к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость объявлена с использованием стандартной функции `def`, она будет запущена во внешнем пуле потоков. ### Подзависимости -Вы можете иметь множество зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}, требующих друг друга (как параметры определения функций), некоторые из них могут быть созданы с помощью `async def`, а некоторые с обычным `def`. Это всё равно будет работать, и те, которые созданы с обычным `def`, будут вызываться на внешнем потоке (из пула), а не "ожидаться". +Вы можете объявить множество ссылающихся друг на друга зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`, другие обычным образом через `def`, и такая схема вполне работоспособна. Функции, объявленные с помощью `def` будут запускаться на внешнем потоке (из пула), а не с помощью `await`. ### Другие служебные функции -Любая другая служебная функция, которую вы вызываете напрямую, может быть создана с обычным `def` или `async def`, и FastAPI не будет влиять на то, как вы её вызываете. +Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы их запускаете. -Это в отличие от функций, которые FastAPI вызывает для вас: *функции обработки пути* и зависимости. +Этим они отличаются от функций, которые FastAPI вызывает самостоятельно: *функции-обработчики пути* и зависимости. -Если ваша служебная функция — это обычная функция с `def`, она будет вызвана напрямую (как вы пишите это в коде), не в пуле потоков, если функция создана с `async def`, тогда вам нужно `await` для этой функции, когда вы вызываете её в вашем коде. +Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую (как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с помощью `async def`, её вызов должен осуществляться с ожиданием через `await`. --- -Еще раз повторим, что все эти технические подробности вероятно будут полезны, если вы специально искали их. +Теперь, когда у вас есть представление о больших технических подробностях, это может быть полезно, если вы специально их искали. -В противном случае вы должны обратиться к руководящим принципам из раздела выше: В спешке?. +В противном случае просто ознакомьтесь с основными принципами в разделе выше: Нет времени?. diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md index 4846e9bd6..8ab1d1d3b 100644 --- a/docs/ru/docs/benchmarks.md +++ b/docs/ru/docs/benchmarks.md @@ -1,36 +1,34 @@ -# Результаты производительности +# Бенчмарки -Независимые тесты производительности TechEmpower показывают, что приложения на **FastAPI**, работающие под управлением Uvicorn, это один из самых быстрых Python-фреймворков, уступающий лишь Starlette и самому Uvicorn (которые используются внутри FastAPI). +Независимые тесты производительности от TechEmpower показывают, что приложения **FastAPI**, работающие под управлением Uvicorn, являются одними из самых быстрых Python-фреймворков, уступая только самим Starlette и Uvicorn (которые используются внутри FastAPI). -Однако просматривая результаты тестов и сравнения, следует учитывать следующее. +Однако при просмотре бенчмарков и сравнений следует учитывать следующее. -## Результаты тестов и скорость +## Бенчмарки и скорость -Когда вы изучаете тесты производительности, часто можно увидеть, что сравниваются несколько инструментов разных типов как эквивалентные. +Когда вы изучаете бенчмарки, часто можно увидеть сравнение нескольких инструментов разного типа, как если бы они были эквивалентны. -В частности, можно увидеть, что сравниваются Uvicorn, Starlette и FastAPI (среди многих других инструментов). +В частности, можно увидеть, как сравниваются Uvicorn, Starlette и FastAPI (среди многих других инструментов). -Чем проще задача, решаемая инструментом, тем лучше будут показатели производительности. И большинство тестов не проверяют дополнительные функции, предоставляемые инструментом. +Чем проще задача, которую решает инструмент, тем лучше у него производительность. И большинство бенчмарков не проверяют дополнительные функции, предоставляемые инструментом. -Иерархия выглядит следующим образом: +Иерархия инструментов выглядит следующим образом: -* **Uvicorn**: сервер ASGI +* **Uvicorn**: ASGI-сервер * **Starlette**: (использует Uvicorn) веб-микрофреймворк - * **FastAPI**: (использует Starlette) API-микрофреймворк с несколькими дополнительными функциями для создания API, включая валидацию данных и т.д. + * **FastAPI**: (использует Starlette) API-микрофреймворк с множеством дополнительных функций для создания API, таких как валидация данных и т.д. * **Uvicorn**: - * Будет показывать наилучшую производительность, так как не содержит много дополнительного кода, кроме самого сервера. - * Вы бы не писали приложение напрямую на Uvicorn. Это означало бы, что ваш код должен содержать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если бы вы это сделали, ваше итоговое приложение имело бы такую же нагрузку, как если бы вы использовали фреймворк, минимизируя количество кода и ошибок. - * Если вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и другими серверами приложений. - + * Имеет наилучшую производительность, так как не содержит многого дополнительного кода, кроме самого сервера. + * Вы не будете писать приложение на Uvicorn напрямую. Это означало бы, что в вашем коде пришлось бы включать, по крайней мере, весь код, предоставляемый Starlette (или **FastAPI**). И если бы вы так сделали, то конечное приложение имело бы те же накладные расходы, что и при использовании фреймворка, минимизирующего код вашего приложения и ваши ошибки. + * Если сравнивать Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и другими серверами приложений. * **Starlette**: - * Будет иметь производительность после Uvicorn. Фактически Starlette использует Uvicorn для работы. Поэтому он, вероятно, может только "замедлиться" по сравнению с Uvicorn, выполняя больше кода. - * Но он предоставляет вам инструменты для создания простых веб-приложений с маршрутизацией на основе путей и т.д. - * Если вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками). - + * Будет иметь следующую по производительности после Uvicorn. Фактически, Starlette использует Uvicorn для выполнения. Поэтому, вероятно, он может стать "медленнее" Uvicorn, так как выполняет больше кода. + * Однако он предоставляет вам инструменты для создания простых веб-приложений с маршрутизацией, основанной на путях и т.д. + * Если сравнивать Starlette, сравнивайте его с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками). * **FastAPI**: - * Так же, как Starlette использует Uvicorn и не может быть быстрее его, **FastAPI** использует Starlette, поэтому не может быть быстрее него. - * FastAPI предоставляет больше возможностей поверх Starlette. Возможности, которые почти всегда необходимы при создании API, такие как проверка и сериализация данных. И, используя его, вы получаете автоматическую документацию бесплатно (автоматическая документация не добавляет нагрузки к работающим приложениям, она создается при запуске). - * Если бы вы не использовали FastAPI и использовали Starlette напрямую (или другой инструмент, такой как Sanic, Flask, Responder и т.д.), вам пришлось бы самостоятельно реализовать всю проверку и сериализацию данных. Так что ваше конечное приложение все равно имело бы такую же нагрузку, как если бы оно было создано с использованием FastAPI. И во многих случаях, проверка и сериализация данных - это самая большая часть кода, написанного в приложениях. - * Таким образом, используя FastAPI, вы экономите время на разработку, снижаете количество ошибок, уменьшаете количество строк кода и, вероятно, получите такую же производительность (или лучше), как если бы вы не использовали его (так как вам пришлось бы реализовать все это в своем коде). - * Если вы сравниваете FastAPI, сравнивайте его с фреймворками веб-приложений (или набором инструментов), которые обеспечивают проверку данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и т.п. Фреймворками с интегрированной автоматической проверкой данных, сериализацией и документацией. + * Так же как Starlette использует Uvicorn и не может быть быстрее его, **FastAPI** использует Starlette, поэтому не может быть быстрее его. + * FastAPI предоставляет больше возможностей поверх Starlette. Возможностей, которые почти всегда нужны при создании API, таких как валидация данных и сериализация. Используя его, вы получаете автоматическую документацию бесплатно (автоматическая документация даже не добавляет накладных расходов при выполнении приложений, она генерируется при запуске). + * Если бы вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент, такой как Sanic, Flask, Responder и т.д.), вам пришлось бы самостоятельно реализовывать всю валидацию и сериализацию данных. Таким образом, ваше конечное приложение все равно имело бы те же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. + * Таким образом, используя FastAPI, вы экономите время разработки, уменьшаете количество ошибок, количество строк кода и, вероятно, получаете ту же производительность (или лучше), как если бы не использовали его (поскольку вам пришлось бы реализовать все это в своем коде). + * Если вы сравниваете FastAPI, сравнивайте его с фреймворком веб-приложений (или набором инструментов), который предоставляет валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией. diff --git a/docs/ru/docs/deployment/manually.md b/docs/ru/docs/deployment/manually.md index 67460d54b..55d1fa329 100644 --- a/docs/ru/docs/deployment/manually.md +++ b/docs/ru/docs/deployment/manually.md @@ -1,80 +1,80 @@ -# Запуск сервера вручную +# Ручной запуск сервера -## Использование команды `fastapi run` +## Используйте команду `fastapi run` -Коротко говоря, используйте `fastapi run`, чтобы запустить ваше приложение FastAPI: +Вкратце, используйте `fastapi run` для запуска вашего приложения FastAPI:
```console $ fastapi run main.py - FastAPI Запуск серверной программы для продакшена 🚀 + FastAPI Starting production server 🚀 - Поиск структуры файлов пакета из директорий - с файлами __init__.py - Импорт из /home/user/code/awesomeapp + Searching for package file structure from directories + with __init__.py files + Importing from /home/user/code/awesomeapp module 🐍 main.py - code Импорт объект приложения FastAPI из модуля при помощи - следующего кода: + code Importing the FastAPI app object from the module with + the following code: from main import app - app Использование строки импорта: main:app + app Using import string: main:app - server Сервер запущен на http://0.0.0.0:8000 - server Документация доступна по адресу http://0.0.0.0:8000/docs + server Server started at http://0.0.0.0:8000 + server Documentation at http://0.0.0.0:8000/docs - Логи: + Logs: - INFO Запущен серверный процесс [2306215] - INFO Ожидание запуска приложения. - INFO Запуск приложения завершён. - INFO Uvicorn работает на http://0.0.0.0:8000 (нажмите CTRL+C - для завершения) + INFO Started server process [2306215] + INFO Waiting for application startup. + INFO Application startup complete. + INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C + to quit) ```
-Это подойдёт для большинства случаев. 😎 +Это подходящий вариант для большинства случаев. 😎 -Вы можете использовать эту команду, чтобы например запустить ваше **FastAPI**-приложение в контейнере, на сервере и т.д. +Вы можете использовать эту команду, чтобы, например, запустить ваше приложение **FastAPI** в контейнере, на сервере и т. д. -## ASGI-сервера +## ASGI-серверы Давайте углубимся в детали. -FastAPI использует стандарт для создания Python веб-фреймворков и серверов, называемый ASGI. FastAPI — это ASGI веб-фреймворк. +FastAPI использует стандарт для создания веб-фреймворков и серверов в Python, называемый ASGI. FastAPI — это ASGI веб-фреймворк. -Основное, что вам нужно для запуска **FastAPI** приложения (или любого другого ASGI приложения) на удалённой серверной машине — это программа ASGI сервера, такая как **Uvicorn**, именно она используется по умолчанию в команде `fastapi`. +Основное, что вам нужно для запуска приложения **FastAPI** (или любого другого ASGI приложения) на удалённой серверной машине — это программа сервера ASGI, такая как **Uvicorn**, которая поставляется по умолчанию с командой `fastapi`. -Среди альтернатив: +Существует ряд альтернатив, включая: -* Uvicorn: высокопроизводительный ASGI сервер. -* Hypercorn: ASGI сервер, поддерживающий HTTP/2 и Trio среди прочего. -* Daphne: ASGI сервер, созданный для Django Channels. -* Granian: HTTP сервер на Rust для Python приложений. -* NGINX Unit: лёгкая и многофункциональная среда выполнения веб-приложений от NGINX. +* Uvicorn: высокопроизводительный ASGI-сервер. +* Hypercorn: ASGI-сервер, совместимый с HTTP/2 и Trio, среди прочих функций. +* Daphne: ASGI-сервер, созданный для Django Channels. +* Granian: сервер HTTP на Rust для Python приложений. +* NGINX Unit: лёгкая и универсальная среда выполнения веб-приложений. ## Сервер как машина и сервер как программа -Есть небольшая деталь о названиях, которую нужно иметь в виду. 💡 +Есть небольшой нюанс в терминологии, который стоит помнить. 💡 -Слово "**сервер**" обычно используется для обозначения как удалённого/облачного компьютера (физическая или виртуальная машина), так и программы, запущенной на этой машине (например, Uvicorn). +Слово "**сервер**" часто используется для обозначения как удалённого/облачного компьютера (физической или виртуальной машины), так и программы, работающей на этой машине (например, Uvicorn). -Просто помните, что когда вы видите "сервер" в общем случае, это может обозначать что-то из этих двух вещей. +Просто держите в уме, что, когда вы видите слово "сервер", это может относиться к одному из этих двух понятий. -Когда речь идёт о удалённой машине, её часто называют **сервер**, но также **машина**, **ВМ** (виртуальная машина), **нода**. Все они относятся к каким-то удалённым машинам, обычно под управлением Linux, на которых вы запускаете программы. +Когда говорят о удалённой машине, часто упоминают просто **сервер**, но также могут называть его **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают какой-то тип удалённого компьютера, обычно с операционной системой Linux, на котором вы запускаете программы. ## Установка программы сервера -Когда вы устанавливаете FastAPI, он поставляется с сервером для продакшена, Uvicorn, и вы можете запустить его с помощью команды `fastapi run`. +При установке FastAPI, он поставляется с продакшн-сервером, Uvicorn, и вы можете запустить его с командой `fastapi run`. Но вы также можете установить ASGI-сервер вручную. -Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и тогда можете установить серверное приложение. +Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и затем вы можете установить серверное приложение. Например, чтобы установить Uvicorn: @@ -88,21 +88,21 @@ $ pip install "uvicorn[standard]"
-Аналогичный процесс будет применен для любой другой программы ASGI сервера. +Аналогичный процесс применим и к любой другой программе ASGI-сервера. /// tip | Подсказка -Добавив `standard`, Uvicorn установит и будет использовать некоторые рекомендованные дополнительные зависимости. +Добавив `standard`, Uvicorn установит и будет использовать некоторые рекомендуемые дополнительные зависимости. -Среди них `uvloop`, высокопроизводительная замена для `asyncio`, которая предоставляет значительное увеличение производительности при использовании асинхронности. +В их числе `uvloop`, высокопроизводительная замена `asyncio`, которая обеспечивает ощутимый прирост скорости обработки запросов с большими объемами данных. -Когда вы устанавливаете FastAPI чем-то вроде `pip install "fastapi[standard]"`, вы также получаете `uvicorn[standard]`. +Когда вы устанавливаете FastAPI с чем-то вроде `pip install "fastapi[standard]"`, вы уже получаете `uvicorn[standard]`. /// ## Запуск программы сервера -Если вы установили ASGI-сервер вручную, вам обычно нужно будет передать строку импорта в специальном формате, чтобы он импортировал ваше FastAPI-приложение: +Если вы установили ASGI-сервер вручную, вам обычно потребуется указать строку для импорта в специальном формате, чтобы он мог импортировать ваше FastAPI-приложение:
@@ -116,9 +116,9 @@ $ uvicorn main:app --host 0.0.0.0 --port 80 /// note | Примечание -Команда `uvicorn main:app` относится к: +Команда `uvicorn main:app` обозначает: -* `main`: файл `main.py` (Python "модуль"). +* `main`: файл `main.py` (модуль Python). * `app`: объект, созданный внутри `main.py` строкой `app = FastAPI()`. Это эквивалентно: @@ -129,29 +129,29 @@ from main import app /// -Каждая альтернативная программа ASGI сервера будет иметь аналогичную команду, вы можете узнать больше в их соответствующей документации. +Каждая из альтернатив программ ASGI-сервера будет иметь схожую команду, вы можете узнать больше в их документации. /// warning | Предупреждение -Uvicorn и другие серверы поддерживают опцию `--reload`, которая полезна во время разработки. +Uvicorn и другие серверы поддерживают опцию `--reload`, которая полезна в процессе разработки. -Опция `--reload` потребляет значительно больше ресурсов, более нестабильна и т.д. +Опция `--reload` потребляет намного больше ресурсов, она менее стабильна и так далее. -Она очень полезна во время **разработки**, но **не следует** использовать её в **продакшене**. +Она очень помогает во время **разработки**, но **не рекомендуется** использовать её в **продакшн**. /// ## Концепции развёртывания -В этих примерах выполняется запуск серверной программы (например, Uvicorn), создавая **один процесс**, который слушает на всех IP (`0.0.0.0`) на предустановленном порту (например, `80`). +Эти примеры запускают серверные программы (например, Uvicorn), начиная с **одного процесса**, слушающего все IP-адреса (`0.0.0.0`) на определенном порту (например, `80`). -Это базовая идея. Но, вероятно, вам захочется позаботиться о некоторых дополнительных вещах, таких как: +Это основная идея. Но вы, вероятно, захотите позаботиться о некоторых дополнительных вещах, таких как: * Безопасность - HTTPS * Запуск при старте системы * Перезапуски -* Репликация (число запущенных процессов) +* Репликация (количество запущенных процессов) * Память -* Предыдущие шаги перед стартом +* Предыдущие шаги перед запуском -Я расскажу вам больше о каждой из этих концепций, как их рассматривать и приведу конкретные примеры стратегий для их решения в следующих главах. 🚀 +Я расскажу вам больше о каждой из этих концепций, о том, как их воспринимать, и дам конкретные примеры стратегий для работы с ними в следующих главах. 🚀 diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md index ef290a4df..4971d9fe6 100644 --- a/docs/ru/docs/help-fastapi.md +++ b/docs/ru/docs/help-fastapi.md @@ -14,11 +14,11 @@ Вы можете подписаться на (редкую) [рассылку **FastAPI и друзья**](newsletter.md){.internal-link target=_blank}, чтобы быть в курсе следующих событий: -* Новости о FastAPI и его друзьях 🚀 -* Руководства 📝 -* Возможности ✨ -* Изменения 🚨 -* Советы и хитрости ✅ +* Новостях о FastAPI и его друзьях 🚀 +* Руководствах 📝 +* Возможностях ✨ +* Изменениях, нарушающих совместимость 🚨 +* Подсказках и хитростях ✅ ## Подписаться на FastAPI в Twitter @@ -40,22 +40,22 @@ ## Связаться с автором -Вы можете связаться со мной (Себастьян Рамирес / `tiangolo`), автором. +Можно связаться со мной (Себаcтиян Рамирез / `tiangolo`), автором FastAPI. Вы можете: * Подписаться на меня на **GitHub**. - * Ознакомиться с другими проектами с открытым исходным кодом, которые я создал и которые могут быть полезны вам. - * Подписывайтесь на меня, чтобы узнавать о моих новых проектах с открытым исходным кодом. + * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам. + * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом. * Подписаться на меня в **Twitter** или в Mastodon. - * Расскажите мне, как вы используете FastAPI (мне нравится об этом слышать). - * Узнавать о моих объявлениях или новых инструментах. - * Вы также можете подписаться на @fastapi в Twitter (отдельный аккаунт). -* Следите за мной на **LinkedIn**. - * Узнавайте о моих объявлениях или новых инструментах (хотя я чаще использую Twitter 🤷‍♂). -* Читайте, что я пишу (или подписывайтесь на меня) на **Dev.to** или на **Medium**. - * Читайте другие идеи, статьи и узнавайте о созданных мной инструментах. - * Подпишитесь на меня, чтобы знать, когда я публикую что-то новое. + * Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это). + * Получать уведомления, когда я делаю объявления и представляю новые инструменты. + * Вы также можете подписаться на @fastapi в Twitter (это отдельный аккаунт). +* Подписаться на меня в **LinkedIn**. + * Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷‍♂). +* Читать, что я пишу (или подписаться на меня) в **Dev.to** или в **Medium**. + * Читать другие идеи, статьи и читать об инструментах созданных мной. + * Подпишитесь на меня, чтобы читать, когда я публикую что-нибудь новое. ## Написать твит о **FastAPI** @@ -65,28 +65,28 @@ ## Оставить голос за FastAPI -* Голосуйте за **FastAPI** на Slant. -* Голосуйте за **FastAPI** на AlternativeTo. -* Создайте отзыв о **FastAPI** на StackShare. +* Голосуйте за **FastAPI** в Slant. +* Голосуйте за **FastAPI** в AlternativeTo. +* Расскажите, как Вы используете **FastAPI** на StackShare. -## Помогите другим с вопросами на GitHub +## Помочь другим с их вопросами на GitHub -Вы можете попытаться помочь другим с их вопросами в: +Вы можете помочь другим с их вопросами: -* Обсуждения GitHub -* Проблемы GitHub +* GitHub Discussions +* GitHub Issues -Во многих случаях вы уже можете знать ответы на эти вопросы. 🤓 +Во многих случаях, весьма вероятно, Вы уже знаете ответ на эти вопросы. 🤓 -Если вы будете помогать многим людям с их вопросами, вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 +Если Вы будете много помогать людям с решением их вопросов, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 Просто помните, самое важное: старайтесь быть добрыми. Люди приходят со своими разочарованиями и часто не задают вопросы так, как следовало бы, но старайтесь быть как можно добрее. 🤗 -Идея сообщества **FastAPI** заключается в том, чтобы быть добрыми и гостеприимными. В то же время, не терпите издевательства или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге. +Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимным. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге. --- -Вот как помочь другим с вопросами (в обсуждениях или проблемах): +Как помочь другим с их вопросами (в обсуждениях или issues): ### Понять вопрос @@ -102,7 +102,7 @@ В большинстве случаев и вопросов что-то связано с **исходным кодом** пользователя. -Во многих случаях они скопируют только фрагмент кода, но этого недостаточно для того, чтобы **воспроизвести проблему**. +В большинстве случаев и по большинству вопросов есть что-то связанное с **исходным кодом** вопрошающего. * Вы можете попросить их предоставить минимальный, воспроизводимый пример, который вы можете **копировать и вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, которое они наблюдают, или чтобы лучше понять их контекст. @@ -116,49 +116,51 @@ ### Попросить закрыть -Если они ответят, с большой вероятностью вы решили их проблему, поздравляю, **вы герой**! 🦸 +### Попросить закрыть вопрос -* Теперь, если это решило их проблему, вы можете попросить их: +Если Вам ответили, высоки шансы, что Вам удалось решить их проблему, поздравляю, **Вы - герой**! 🦸 - * В обсуждениях на GitHub: отметить комментарий как **ответ**. - * В проблемах на GitHub: **закрыть** проблему. +* В таком случае, если вопрос решён, попросите их: + + * В GitHub Discussions: отметить ваш комментарий как **ответ**. + * В GitHub Issues: **закрыть** тикет. ## Отслеживать репозиторий на GitHub Вы можете "отслеживать" FastAPI на GitHub (нажав на кнопку "watch" вверху справа): https://github.com/fastapi/fastapi. 👀 -Если вы выберете "Watching" вместо "Releases only", вы получите уведомления, когда кто-то создаёт новую проблему или задаёт вопрос. Вы также можете уточнить, что хотите получать уведомления только о новых проблемах, обсуждениях или PR и т.д. +Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления, когда кто-либо создаст новый тикет или вопрос. Вы также можете указать, что хотите получать уведомления только о новых тикетах, обсуждениях или пулл-реквестах и т.д. -Затем вы можете попытаться помочь решить эти вопросы. +Тогда Вы можете попробовать решить эти вопросы. -## Задавать вопросы +## Задать вопросы -Вы можете создать новый вопрос в репозитории GitHub, чтобы: +Вы можете создать новый вопрос в репозитории на GitHub, например: -* Задать **вопрос** или попросить о **проблеме**. -* Предложить новую **функцию**. +* Задать **вопрос** или попросить помощи в решении **проблемы**. +* Предложить новую **возможность**. -**Примечание**: если вы это сделаете, я попрошу вас также помочь другим. 😉 +**Заметка**: если Вы создаёте подобные вопросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉 -## Проверка пул-реквестов +## Проверять пулл-реквесты -Вы можете помочь мне с проверкой пул-реквестов от других участников. +Вы можете помочь мне проверять пулл-реквесты других участников. Снова повторяю, пожалуйста, старайтесь быть добрыми. 🤗 --- -Вот что нужно иметь в виду и как проверять пул-реквесты: +О том, что нужно иметь в виду при проверке пулл-реквестов: ### Понять проблему -* Во-первых, убедитесь, что вы **поняли проблему**, которую пытается решить пул-реквест. Возможно, это обсуждается в обсуждениях GitHub или проблеме. +* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение в GitHub Discussion или ticket. -* Также существует вероятность, что пул-реквест не требуется, поскольку проблему можно решить **по-другому**. Затем вы можете предложить или спросить об этом. +* Также есть вероятность, что пулл-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт. ### Не беспокойтесь о стиле -* Не слишком беспокойтесь о таких вещах, как стиль сообщений о коммитах, я буду принимать и сливать с учетом мануальной настройки. +* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах. При слиянии пулл-реквеста с основной веткой, я буду сжимать и настраивать всё вручную. * Также не беспокойтесь о правилах стиля, уже есть автоматизированные инструменты, которые это проверяют. @@ -168,47 +170,47 @@ * Проверьте и прочтите код, посмотрев, имеет ли он смысл, **запустите его локально** и посмотрите, действительно ли он решает задачу. -* Затем **комментируйте**, что вы это сделали, так я узнаю, что вы действительно проверили код. +* Затем **прокомментируйте**, что Вы сделали эту проверку, тогда я буду знать, что Вы действительно проверили код. /// info | Информация -К сожалению, я не могу просто доверять PR, у которых имеется несколько положительных отзывов. +К сожалению, я не могу так просто доверять пулл-реквестам, у которых уже есть несколько одобрений. -Бывали случаи, когда PR имели 3, 5 или больше положительных отзывов, вероятно из-за привлекательного описания, но когда я проверял такие PR, они оказывались некорректными, имели ошибку или не решали заявленную проблему. 😅 +Бывали случаи, что пулл-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пулл-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅 Поэтому действительно важно, чтобы вы прочли и исполнили код, и сообщили мне в комментариях, что вы это сделали. 🤓 /// -* Если PR можно упростить каким-то образом, вы можете попросить об этом, но не стоит быть слишком придирчивыми, может быть множество субъективных точек зрения (и у меня также будет своя 🙈), поэтому лучше сосредоточиться на фундаментальных вещах. +* Если Вы считаете, что пулл-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах. ### Тестирование -* Помогите мне проверить, что у PR есть **тесты**. +* Помогите мне проверить, что у пулл-реквеста есть **тесты**. -* Проверьте, что тесты **падали** до PR. 🚨 +* Проверьте, что тесты **падали** до пулл-реквеста. 🚨 -* Затем проверьте, что тесты **не валятся** после PR. ✅ +* Затем проверьте, что тесты **не падают** после пулл-реквеста. ✅ -* Многие PR не имеют тестов, вы можете **напомнить** им об их добавлении или даже **предложить** свои тесты. Это одна из тех вещей, которые отнимают больше всего времени, и вы можете существенно помочь с ними. +* Многие пулл-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим. -* Затем также укажите в комментариях, что вы проверили, так я узнаю, что вы это сделали. 🤓 +* Затем также прокомментируйте, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓 -## Создайте пул-реквест +## Создать пулл-реквест -Вы можете [внести вклад](contributing.md){.internal-link target=_blank} в исходный код с помощью Pull Requests, например: +Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в кодовую базу, предложив пулл-реквесты, например: -* Чтобы исправить ошибку в документации. -* Чтобы поделиться статьей, видео или подкастом, который вы создали или нашли, о FastAPI, редактируя этот файл. - * Убедитесь, что добавили ссылку в начало соответствующего раздела. -* Чтобы помочь [перевести документацию](contributing.md#translations){.internal-link target=_blank} на ваш язык. - * Вы также можете помочь рецензировать переводы, созданные другими. -* Чтобы предложить новые разделы документации. -* Чтобы исправить существующую проблему или баг. +* Исправить опечатку в документации, которую Вы нашли. +* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли, изменив этот файл. + * Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела. +* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык. + * Вы также можете проверять переводы, сделанные другими. +* Предложить новые разделы документации. +* Исправить существующую проблему/баг. * Убедитесь, что добавили тесты. * Чтобы добавить новую возможность. * Убедитесь, что добавили тесты. - * Убедитесь, что добавили документацию, если это актуально. + * Убедитесь, что добавили документацию, если это необходимо. ## Помогите поддерживать FastAPI @@ -218,20 +220,20 @@ Основные задачи, которые вы можете сделать прямо сейчас: -* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (см. раздел выше). -* [Проверка пул-реквестов](#review-pull-requests){.internal-link target=_blank} (см. раздел выше). +* [Помочь другим с их вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (смотрите вышестоящую секцию). +* [Проверить пул-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите вышестоящую секцию). Эти две задачи **занимают больше всего времени**. Это основная работа по поддержке FastAPI. -Если вы можете помочь мне с этим, **вы помогаете поддерживать FastAPI**, обеспечивая его дальнейшее **развитие быстрее и лучше**. 🚀 +Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 ## Присоединяйтесь к чату -Присоединяйтесь к 👥 чат-серверу Discord 👥 и общайтесь с другими в сообществе FastAPI. +Подключайтесь к 👥 чат-серверу в Discord 👥 и общайтесь с другими участниками сообщества FastAPI. /// tip | Подсказка -Задавайте вопросы в Обсуждениях GitHub, так у вас будет намного больше шансов получить помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. +Для вопросов, задавайте их в GitHub Discussions, там больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. Используйте чат только для других общих разговоров. @@ -241,16 +243,16 @@ Помните, что в чатах легче задаются вопросы, которые носят слишком общий характер и на них труднее найти ответы, поэтому вы можете не получить ответы. -На GitHub шаблон поможет вам задать правильный вопрос, чтобы вы могли легче получить хороший ответ, или даже решить проблему самостоятельно до того, как вы зададите его. На GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это занимает некоторое время. Я лично не могу сделать то же самое с системами чатов. 😅 +В разделе обсуждений на GitHub, шаблон поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу гарантировать те же ответы в чатах. 😅 -Разговоры в чатах также не так легко доступны для поиска, как в GitHub, поэтому вопросы и ответы могут затеряться. И только те, что на GitHub, учитываются в получении статуса [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что вы, скорее всего, получите больше внимания на GitHub. +Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только вопросы решаемые на GitHub учитываются в получении титула [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub. -С другой стороны, в чаты подключены тысячи пользователей, поэтому есть большая вероятность, что вы найдёте там кого-то, с кем могли бы поговорить почти в любое время. 😄 +С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время trouver кого-то, с кем можно поговорить. 😄 ## Спонсировать автора -Если ваш **продукт/компания** зависит от **FastAPI** или связана с ним и вы хотите достичь его пользователей, вы можете спонсировать автора (меня) через спонсоров GitHub. В зависимости от уровня, вы можете получить некоторые дополнительные преимущества, такие как награда в документации. 🎁 +Если ваш **продукт/компания** зависит от или связан с **FastAPI** и вы хотите донести до его пользователей, вы можете спонсировать автора (меня) через GitHub sponsors. В зависимости от уровня, вы можете получать некоторые дополнительные преимущества, такие как значок в документации. 🎁 --- -Спасибо! 🚀 +Благодарствую! 🚀 diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 2e0f6b684..281f8cf19 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -37,16 +37,16 @@ FastAPI — это современный, быстрый (высокопрои Ключевые особенности: -* **Быстрый**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков на Python](#performance). -* **Быстрая разработка**: Повышает скорость разработки примерно на 200–300%. * -* **Меньше ошибок**: Уменьшает количество ошибок, вносимых разработчиком, на 40%. * -* **Интуитивно понятный**: Отличная поддержка редактора. Автозаполнение везде. Меньше времени на отладку. -* **Простой**: Разработан для простоты использования и изучения. Меньше времени на чтение документации. -* **Краткий**: Сведите к минимуму дублирование кода. Множество функций из каждого объявления параметра. Меньше ошибок. -* **Надежный**: Получите готовый к производству код. С автоматической интерактивной документацией. -* **На основе стандартов**: Основан на (и полностью совместим с) открытых стандартах API: OpenAPI (ранее известный как Swagger) и JSON Schema. +* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых фреймворков Python](#performance). +* **Быстрота разработки**: Увеличьте скорость разработки примерно на 200–300%. * +* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). * +* **Интуитивно понятный**: Отличная поддержка редактора. Автозавершение везде. Меньше времени на отладку. +* **Лёгкость**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации. +* **Краткость**: Сведите к минимуму дублирование кода. Каждый объявленный параметр - определяет несколько функций. Меньше ошибок. +* **Надежность**: Получите готовый к работе код. С автоматической интерактивной документацией. +* **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: OpenAPI (ранее известном как Swagger) и JSON Schema. -* оценка, основанная на тестах внутренней команды разработчиков, создающих производственные приложения. +* оценка на основе тестов внутренней команды разработчиков, создающих продакшн приложения. ## Спонсоры @@ -101,7 +101,13 @@ FastAPI — это современный, быстрый (высокопрои "_Мы перешли на **FastAPI** для наших **API** [...] Думаю, он вам понравится [...]_" -
Ines Montani - Matthew Honnibal - Explosion AI основатели - spaCy создатели (ref) - (ref)
+
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +"_Если кто-то хочет создать продакшн Python API, я бы настоятельно рекомендовал **FastAPI**. Он **прекрасно разработан**, **прост в использовании** и **высокомасштабируем**, он стал **ключевым компонентом** нашей стратегии разработки API-first и управляет множеством автоматизаций и сервисов, таких как наш виртуальный инженер TAC._" + +
Deon Pillsbury - Cisco (ref)
--- @@ -140,7 +146,7 @@ $ pip install "fastapi[standard]"
-**Примечание**: Убедитесь, что вы обернули `"fastapi[standard]"` в кавычки, чтобы это работало во всех терминалах. +**Примечание**: Убедитесь, что вы используете кавычки для `"fastapi[standard]"`, чтобы обеспечить его работу во всех терминалах. ## Пример @@ -191,7 +197,7 @@ async def read_item(item_id: int, q: Union[str, None] = None): **Примечание**: -Если вы не уверены, ознакомьтесь с разделом _"Торопитесь?"_ о `async` и `await` в документации. +Если вы не знаете, проверьте раздел _"Нет времени?"_ в документации об `async` и `await`. @@ -204,25 +210,24 @@ async def read_item(item_id: int, q: Union[str, None] = None): ```console $ fastapi dev main.py - ╭────────── FastAPI CLI - Режим разработки ───────────╮ + ╭────────── FastAPI CLI - Development mode ───────────╮ │ │ - │ Сервер работает на: http://127.0.0.1:8000 │ + │ Serving at: http://127.0.0.1:8000 │ │ │ - │ Документация API: http://127.0.0.1:8000/docs │ + │ API docs: http://127.0.0.1:8000/docs │ │ │ - │ Запущено в режиме разработки, для использования в │ - │ продакшн используйте: │ + │ Running in development mode, for production use: │ │ │ │ fastapi run │ │ │ ╰─────────────────────────────────────────────────────╯ -INFO: Будет следить за изменениями в этих директориях: ['/home/user/code/awesomeapp'] -INFO: Uvicorn работает на http://127.0.0.1:8000 (Нажмите CTRL+C чтобы остановить) -INFO: Запущен процесс перезагрузки [2248755] с использованием WatchFiles -INFO: Запущен серверный процесс [2248757] -INFO: Ожидание запуска приложения. -INFO: Запуск приложения завершён. +INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [2248755] using WatchFiles +INFO: Started server process [2248757] +INFO: Waiting for application startup. +INFO: Application startup complete. ```
@@ -230,9 +235,9 @@ INFO: Запуск приложения завершён.
О команде fastapi dev main.py... -Команда `fastapi dev` читает ваш файл `main.py`, определяет **FastAPI** приложение в нем и запускает сервер, используя Uvicorn. +Команда `fastapi dev` считывает файл `main.py`, определяет в нем приложение **FastAPI** и запускает сервер с использованием Uvicorn. -По умолчанию, `fastapi dev` запускается с активированной функцией автообновления для локальной разработки. +По умолчанию `fastapi dev` запускает приложение с включенной авто-перезагрузкой для локальной разработки. Вы можете узнать больше об этом в документации FastAPI CLI. @@ -404,7 +409,7 @@ item: Item --- -Мы только начали изучать, как все это работает, но вы уже поняли основную идею. +Мы только немного поверхностно ознакомились, но вы уже поняли, как все это работает. Попробуйте изменить строку: @@ -442,14 +447,14 @@ item: Item * **WebSockets** * невероятно простые тесты, основанные на HTTPX и `pytest` * **CORS** - * **Сеансы Cookies** + * **Сессии с использованием Cookie** * ...и многое другое. ## Производительность Независимые бенчмарки TechEmpower демонстрируют приложения **FastAPI**, работающие под Uvicorn, как один из самых быстрых доступных фреймворков на Python, уступающий только самим Starlette и Uvicorn (используемых внутри FastAPI). (*) -Чтобы узнать больше об этом, см. раздел Бенчмарки. +Чтобы узнать больше об этом, см. раздел Тесты производительности. ## Зависимости @@ -457,7 +462,7 @@ FastAPI зависит от Pydantic и Starlette. ### Зависимости `standard` -Когда вы устанавливаете FastAPI с использованием `pip install "fastapi[standard]"`, он поставляется с `standard` группой необязательных зависимостей: +Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он включает группу зависимостей `standard`: Используется Pydantic: @@ -467,30 +472,30 @@ FastAPI зависит от Pydantic и Starlette. * httpx - Обязательно, если вы хотите использовать `TestClient`. * jinja2 - Обязательно, если вы хотите использовать конфигурацию шаблона по умолчанию. -* python-multipart - Обязательно, если вы хотите поддерживать "парсинг" форм, с `request.form()`. +* python-multipart - Обязательно, если вы хотите поддерживать форму "парсинга" с помощью `request.form()`. Используется FastAPI: -* uvicorn - сервер, который загружает и обслуживает ваше приложение. Это включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), нужные для высокопроизводительного сервиса. +* uvicorn - для сервера, который загружает и обслуживает ваше приложение. Это включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), необходимые для высокопроизводительного обслуживания. * `fastapi-cli[standard]` - для предоставления команды `fastapi`. - * Это включает `fastapi-cloud-cli`, который позволяет развернуть ваше FastAPI приложение на FastAPI Cloud. + * Это включает `fastapi-cloud-cli`, который позволяет разворачивать ваше приложение FastAPI в FastAPI Cloud. -### Без `standard` зависимостей +### Без зависимостей `standard` -Если вы не хотите включать `standard` необязательные зависимости, вы можете установить FastAPI с `pip install fastapi` вместо `pip install "fastapi[standard]"`. +Если вы не хотите включать необязательные зависимости `standard`, вы можете установить FastAPI с помощью `pip install fastapi` вместо `pip install "fastapi[standard]"`. ### Без `fastapi-cloud-cli` -Если вы хотите установить FastAPI с стандартными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. +Если вы хотите установить FastAPI с стандартными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. ### Дополнительные необязательные зависимости -Существуют некоторые дополнительные зависимости, которые вы можете добавить. +Существуют некоторые дополнительные зависимости, которые вы можете захотеть установить. Дополнительные необязательные зависимости Pydantic: * pydantic-settings - для управления настройками. -* pydantic-extra-types - для добавления типов, которые могут быть использованы с Pydantic. +* pydantic-extra-types - для дополнительных типов, которые могут быть использованы с Pydantic. Дополнительные необязательные зависимости FastAPI: diff --git a/docs/ru/docs/project-generation.md b/docs/ru/docs/project-generation.md index a9c50f78c..ae7218f03 100644 --- a/docs/ru/docs/project-generation.md +++ b/docs/ru/docs/project-generation.md @@ -1,28 +1,28 @@ # Full Stack FastAPI Шаблон -Шаблоны, хотя обычно они поставляются с определенной конфигурацией, разработаны для гибкости и настройки. Это позволяет вам изменять и адаптировать их в соответствии с требованиями вашего проекта, что делает их отличной отправной точкой. 🏁 +Шаблоны обычно идут с определенной настройкой, но они разработаны гибкими и настраиваемыми. Это позволяет вам модифицировать и адаптировать их в соответствии с требованиями вашего проекта, превращая их в отличную отправную точку. 🏁 -Вы можете использовать этот шаблон, чтобы начать работу, так как он включает множество начальных настроек, безопасности, базы данных и некоторые API-эндпоинты, которые уже выполнены за вас. +Вы можете использовать этот шаблон, чтобы начать, так как он включает множество начальных настроек, безопасности, базу данных и некоторые API эндпоинты уже готовы. -Репозиторий GitHub: Full Stack FastAPI Template +Репозиторий на GitHub: Full Stack FastAPI Template -## Full Stack FastAPI Шаблон - Технологический стек и функции +## Full Stack FastAPI Шаблон - Технологии и Особенности -- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python бэкенд API. - - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия с SQL базой данных Python (ORM). +- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python бэкенда API. + - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия Python с SQL базой данных (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) для фронтенд-компонентов. - - 🤖 Автоматически сгенерированный фронтенд-клиент. + - 💃 Использование TypeScript, hooks, [Vite](https://vitejs.dev), и других компонентов современного стека фронтенда. + - 🎨 [Chakra UI](https://chakra-ui.com) для компонентов фронтенда. + - 🤖 Автоматически сгенерированный фронтенд клиент. - 🧪 [Playwright](https://playwright.dev) для End-to-End тестирования. - 🦇 Поддержка темного режима. -- 🐋 [Docker Compose](https://www.docker.com) для разработки и производства. +- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна. - 🔒 Безопасное хеширование паролей по умолчанию. -- 🔑 JWT токены аутентификации. -- 📫 Восстановление пароля по электронной почте. -- ✅ Тесты с [Pytest](https://pytest.org). -- 📞 [Traefik](https://traefik.io) в качестве обратного прокси / балансировщика нагрузки. -- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд-прокси Traefik для автоматической обработки HTTPS-сертификатов. -- 🏭 CI (непрерывная интеграция) и CD (непрерывное развертывание), основанные на GitHub Actions. +- 🔑 Аутентификация с помощью JWT токенов. +- 📫 Восстановление пароля через email. +- ✅ Тесты с использованием [Pytest](https://pytest.org). +- 📞 [Traefik](https://traefik.io) в качестве реверс-прокси / балансировщика нагрузки. +- 🚢 Инструкции по развёртыванию с Docker Compose, включая настройку фронтенд прокси Traefik для автоматического управления HTTPS сертификатами. +- 🏭 CI (непрерывная интеграция) и CD (непрерывное развёртывание) на базе GitHub Actions. diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md index e2d768886..3224e8265 100644 --- a/docs/ru/docs/tutorial/body-multiple-params.md +++ b/docs/ru/docs/tutorial/body-multiple-params.md @@ -1,10 +1,10 @@ -# Body - Множественные параметры +# Тело запроса - Множество параметров -Теперь, когда мы увидели, как использовать `Path` и `Query`, давайте рассмотрим более продвинутые способы объявления тела запроса. +Теперь, когда мы увидели, как использовать `Path` и `Query`, давайте рассмотрим более продвинутые примеры объявления тела запроса. -## Объединение `Path`, `Query` и параметров тела +## Объединение `Path`, `Query` и параметров тела запроса -Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления параметров тела, и **FastAPI** поймет, что с ними делать. +Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления параметров тела запроса, и **FastAPI** автоматически поймёт, что с ними делать. Вы также можете объявлять параметры тела как необязательные, установив значение по умолчанию `None`: @@ -12,13 +12,13 @@ /// 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,13 +52,13 @@ } ``` -/// note | Примечание +/// note | Заметка -Обратите внимание, что хотя `item` был объявлен так же, как и раньше, теперь он ожидается внутри тела с ключом `item`. +Обратите внимание, что хотя параметр `item` был объявлен таким же образом, как и раньше, теперь предполагается, что он находится внутри тела запроса с ключом `item`. /// -**FastAPI** выполнит автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с `user`. +**FastAPI** сделает автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с параметром `user`. Он выполнит проверку составных данных и задокументирует это в схеме OpenAPI и автоматической документации. @@ -66,11 +66,11 @@ Так же, как существуют `Query` и `Path` для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет эквивалент для тела - `Body`. -Например, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле, кроме параметров `item` и `user`. +Например, расширяя предыдущую модель, вы можете решить, что вам нужен ещё один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`. -Если вы объявите это без указания объекта (Path, Query, Body и т.д.), то, поскольку это является простым типом данных, **FastAPI** рассмотрит это как query-параметр. +Если вы объявите его как есть, поскольку это простой тип данных, **FastAPI** будет считать, что это query-параметр. -Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела, используя `Body`: +Но вы можете указать **FastAPI** обрабатывать его как ещё один ключ тела запроса, используя `Body`: {* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *} @@ -94,9 +94,9 @@ И снова, он преобразует типы данных, проверит, задокументирует и т.д. -## Множественные параметры тела и query +## Множество body-параметров и query -Конечно, вы также можете объявить дополнительные query-параметры, когда это необходимо, дополнительно к любым параметрам тела. +Конечно, вы также можете объявлять дополнительные query-параметры в любое время, дополнительно к любым body-параметрам. Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так: @@ -116,7 +116,7 @@ q: str | None = None /// info | Информация -`Body` также имеет все те же дополнительные параметры валидации и метаданные, как `Query`, `Path` и другие, которые вы увидите позже. +`Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`, `Path` и других, которые вы увидите позже. /// @@ -126,13 +126,13 @@ q: str | None = None По умолчанию **FastAPI** ожидает получить тело запроса напрямую. -Но если вы хотите, чтобы он ожидал JSON с ключом `item`, внутри которого будет содержимое модели, как это происходит при объявлении дополнительных параметров тела, вы можете использовать специальный параметр `embed` типа `Body`: +Но если вы хотите, чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`: ```Python item: Item = Body(embed=True) ``` -пример: +как в этом примере: {* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *} @@ -162,10 +162,10 @@ item: Item = Body(embed=True) ## Резюме -Вы можете добавлять несколько параметров тела для вашей *функции операции пути*, даже если запрос может содержать только одно тело. +Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря на то, что запрос может содержать только одно тело. -**FastAPI** справится с этим, предоставит вам правильные данные в вашей функции, проведет валидацию и документирование правильной схемы в *операции пути*. +Но **FastAPI** справится с этим, предоставит вам правильные данные в вашей функции, а также выполнит валидацию и документирование правильной схемы *операции пути*. Вы также можете объявлять отдельные значения для получения в рамках тела запроса. -И вы можете указать **FastAPI** встраивать тело запроса в ключ, даже если объявлен только один параметр. +И вы можете настроить **FastAPI** так, чтобы включить тело запроса в ключ, даже если объявлен только один параметр. diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md index aa24ac530..4cfcf703c 100644 --- a/docs/ru/docs/tutorial/cors.md +++ b/docs/ru/docs/tutorial/cors.md @@ -26,9 +26,9 @@ ## Подстановочные символы -Можно также задать список как `"*"` (подстановочный символ), чтобы разрешить все источники. +Можно указать список, используя подстановочный символ `"*"`, чтобы разрешить любые источники. -Но тогда разрешатся только определённые виды взаимодействия, исключая всё, что связано с учётными данными: куки, заголовки Authorization такие, как те, что используются с токенами Bearer и т.д. +Но тогда не будут разрешены некоторые виды взаимодействия, включая всё, что связано с учётными данными: куки, заголовки Authorization с токенами Bearer и т.п. Поэтому, чтобы всё функционировало правильно, лучше явно указывать разрешённые источники. @@ -46,20 +46,17 @@ * Специфические HTTP-методы (`POST`, `PUT`) или все из них с помощью подстановочного символа `"*"`. * Специфические HTTP-заголовки или все из них с помощью подстановочного символа `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001.py hl[2,6:12,14:20] *} -По умолчанию параметры, используемые реализацией `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` всегда разрешены для простых CORS-запросов. -* `allow_credentials` - Указывает, что куки должны поддерживаться для междоменных запросов. По умолчанию равно `False`. - - Нельзя установить значения `allow_origins`, `allow_methods` и `allow_headers` в `['*']`, если `allow_credentials` установлено в `True`. Все они должны быть явно определены. - +* `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` всегда разрешены для простых CORS-запросов. +* `allow_credentials` - Указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. Ни один из параметров `allow_origins`, `allow_methods` и `allow_headers` не может быть установлен в `['*']`, если `allow_credentials` установлен в `True`. Все они должны быть явно указаны. * `expose_headers` - Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию равно `[]`. * `max_age` - Устанавливает максимальное время в секундах, в течение которого браузеры могут кэшировать CORS-ответы. По умолчанию равно `600`. diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md index b53ff6271..fe7276db6 100644 --- a/docs/ru/docs/tutorial/extra-models.md +++ b/docs/ru/docs/tutorial/extra-models.md @@ -2,7 +2,7 @@ Продолжая с предыдущим примером, будет обычным явлением иметь более одной связанной модели. -Это особенно актуально для моделей пользователей, потому что: +Это особенно применимо в случае пользовательских моделей, потому что: * **Модель для ввода** должна иметь возможность включать пароль. * **Модель для вывода** не должна содержать пароль. @@ -22,11 +22,12 @@ {* ../../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()`. +В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был устаревшим (но всё ещё поддерживается) и переименован в `.model_dump()`. -Примеры здесь используют `.dict()` для совместимости с Pydantic версии 1, но вы должны использовать `.model_dump()`, если можете применять Pydantic версии 2. +В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, следует использовать `.model_dump()`. /// @@ -90,7 +91,7 @@ UserInDB( ) ``` -Или, более точно, используя напрямую `user_dict`, с любым будущим содержимым: +Или более точно, используя `user_dict` напрямую, с любым потенциальным содержимым: ```Python UserInDB( @@ -122,7 +123,7 @@ UserInDB(**user_in.dict()) #### Распаковка `dict` и дополнительные именованные аргументы -И затем, добавляя дополнительный именованный аргумент `hashed_password=hashed_password`, как в: +И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password`, как здесь: ```Python UserInDB(**user_in.dict(), hashed_password=hashed_password) @@ -142,7 +143,7 @@ UserInDB( /// warning | Предупреждение -Поддерживающие дополнительные функции `fake_password_hasher` и `fake_save_user` существуют исключительно для демонстрации возможного потока данных, но, конечно, не обеспечивают реальной безопасности. +Используемые в примере вспомогательные функции `fake_password_hasher` и `fake_save_user` служат лишь для демонстрации возможного потока данных, но, конечно, они не обеспечивают настоящую безопасность. /// @@ -150,15 +151,15 @@ UserInDB( Сокращение дублирования кода — одна из основных идей **FastAPI**. -Поскольку дублирование кода увеличивает вероятность появления ошибок, проблем с безопасностью, проблем с десинхронизацией кода (когда вы обновляете что-то в одном месте, но не в других), и т.д. +Поскольку дублирование кода увеличивает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д. И все эти модели разделяют много данных и дублируют названия и типы атрибутов. Мы могли бы сделать лучше. -Мы можем определить модель `UserBase`, которая будет базовой для наших других моделей. А затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию и т.д.). +Мы можем объявить модель `UserBase`, которая будет базовой для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию и т.п.). -Все преобразования данных, валидация, документация и т.д. будут работать как обычно. +Все операции конвертации, валидации, документации и т.п. будут по-прежнему работать нормально. Таким образом, мы можем определить только отличия между моделями (с открытым `password`, с `hashed_password` и без пароля): @@ -166,7 +167,7 @@ UserInDB( ## `Union` или `anyOf` -Вы можете объявить ответ как `Union` из двух или более типов, что значит, что ответ может быть любым из них. +Вы можете объявить ответ как `Union` из двух или более типов, это значит, что ответ должен соответствовать одному из них. Он будет определён в OpenAPI как `anyOf`. @@ -192,7 +193,7 @@ UserInDB( some_variable: PlaneItem | CarItem ``` -Но если мы поместим это в присвоение `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается выполнить **недопустимую операцию** между `PlaneItem` и `CarItem` вместо интерпретации это как аннотацию типа. +Но если мы поместим это в `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа. ## Список моделей diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md index 9cba3e02f..19b0465af 100644 --- a/docs/ru/docs/tutorial/first-steps.md +++ b/docs/ru/docs/tutorial/first-steps.md @@ -4,7 +4,7 @@ {* ../../docs_src/first_steps/tutorial001.py *} -Скопируйте этот код в файл `main.py`. +Скопируйте это в файл `main.py`. Запустите live сервер: @@ -13,42 +13,42 @@ ```console $ fastapi dev main.py - FastAPI Запуск сервера для разработки 🚀 + FastAPI Starting development server 🚀 - Ищем структуру файлов пакета в директориях - с файлами __init__.py - Импортирование из /home/user/code/awesomeapp + Searching for package file structure from directories + with __init__.py files + Importing from /home/user/code/awesomeapp module 🐍 main.py - code Импортируем объект приложения FastAPI из модуля с - помощью следующего кода: + code Importing the FastAPI app object from the module with + the following code: from main import app - app Используем строку импорта: main:app + app Using import string: main:app - server Сервер запущен по адресу http://127.0.0.1:8000 - server Документация по адресу http://127.0.0.1:8000/docs + server Server started at http://127.0.0.1:8000 + server Documentation at http://127.0.0.1:8000/docs - tip Запуск в режиме разработки, для использования в продакшене: + tip Running in development mode, for production use: fastapi run - Логи: + Logs: - INFO Будем отслеживать изменения в этих директориях: + INFO Will watch for changes in these directories: ['/home/user/code/awesomeapp'] - INFO Uvicorn запущен по адресу http://127.0.0.1:8000 (нажмите CTRL+C - для завершения) - INFO Процесс перезагрузки запущен [383138] с использованием WatchFiles - INFO Серверный процесс запущен [383153] - INFO Ожидание запуска приложения. - INFO Запуск приложения завершен. + INFO Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C + to quit) + INFO Started reloader process [383138] using WatchFiles + INFO Started server process [383153] + INFO Waiting for application startup. + INFO Application startup complete. ```
-В выводе будет строка, похожая на: +В окне вывода появится следующая строка: ```hl_lines="4" INFO: Uvicorn запущен по адресу http://127.0.0.1:8000 (нажмите CTRL+C для завершения) @@ -165,7 +165,7 @@ OpenAPI определяет схему API для вашего API. А эта Здесь переменная `app` будет "экземпляром" класса `FastAPI`. -Это будет главная точка взаимодействия для создания и работы с вашим API. +Это единая точка входа для создания и взаимодействия с API. ### Шаг 3: создайте *операцию пути* @@ -316,8 +316,8 @@ https://example.com/items/foo ## Резюме -* Импортируйте `FastAPI`. -* Создайте экземпляр `app`. -* Напишите **декоратор операции пути** с помощью декораторов вроде `@app.get("/")`. -* Определите **функцию операции пути**; например, `def root(): ...`. -* Запустите сервер разработки с помощью команды `fastapi dev`. +* Импортируем `FastAPI`. +* Создаём экземпляр `app`. +* Пишем **декоратор операции пути** (такой как `@app.get("/")`). +* Пишем **функцию операции пути** (`def root(): ...`). +* Запускаем сервер в режиме разработки (`fastapi dev`). diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md index 4413efcf8..8b7fa5366 100644 --- a/docs/ru/docs/tutorial/handling-errors.md +++ b/docs/ru/docs/tutorial/handling-errors.md @@ -11,23 +11,23 @@ * Элемент, к которому клиент пытался получить доступ, не существует. * и т.д. -В таких случаях обычно возвращается **HTTP-код статуса ответа** в диапазоне **400** (от 400 до 499). +В таких случаях обычно возвращается **HTTP статус-код** в диапазоне **400** (от 400 до 499). Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно. Четырёхсотые статус-коды означают, что ошибка произошла по вине клиента. -Помните ли ошибки **"404 Not Found "** (и шутки)? +Помните ли ошибки **"404 Not Found"** (и шутки)? ## Использование `HTTPException` -Для возврата клиенту HTTP-ответов с ошибками используется `HTTPException`. +Для возврата HTTP-ответов с ошибками клиенту используется `HTTPException`. ### Импортируйте `HTTPException` {* ../../docs_src/handling_errors/tutorial001.py hl[1] *} -### Вызовите `HTTPException` в своем коде +### Вызовите `HTTPException` в своём коде `HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API. @@ -35,9 +35,9 @@ Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы вызываете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту. -О том, насколько выгоднее `вызывать` исключение, чем `возвращать` значение, будет рассказано в разделе, посвященном зависимости и безопасности. +Польза от `вызова` исключения, а не `возврата` значения, станет очевидной в разделе, посвящённом зависимостям и безопасности. -В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`: +В этом примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`: {* ../../docs_src/handling_errors/tutorial001.py hl[11] *} @@ -91,7 +91,7 @@ {* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *} -Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`. +Здесь, если вы запросите `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`. Но оно будет обработано `unicorn_exception_handler`. @@ -232,9 +232,11 @@ path -> item_id И класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`. -Единственное отличие состоит в том, что `HTTPException` от **FastAPI** позволяет добавлять заголовки, которые будут включены в ответ, в то время как `HTTPException` от Starlette принимает только строки. +Единственное отличие заключается в том, что `HTTPException` от **FastAPI** позволяет добавлять заголовки, которые будут включены в ответ. -Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своем коде. +Он необходим/используется внутри системы для OAuth 2.0 и некоторых утилит безопасности. + +Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своём коде. Но когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette. diff --git a/docs/ru/docs/tutorial/index.md b/docs/ru/docs/tutorial/index.md index 9282c0c9e..aadcf75e7 100644 --- a/docs/ru/docs/tutorial/index.md +++ b/docs/ru/docs/tutorial/index.md @@ -1,60 +1,60 @@ # Учебник - Руководство пользователя -Этот учебник показывает, как использовать **FastAPI** со многими его функциями, шаг за шагом. +Этот учебник показывает вам, как использовать **FastAPI** с большинством его функций, шаг за шагом. -Каждый раздел постепенно опирается на предыдущие, но структура разбита на отдельные темы, чтобы вы могли перейти прямо к любой конкретной теме для решения своих специфичных нужд API. +Каждый раздел постепенно основан на предыдущих, но он структурирован по отдельным темам, чтобы вы могли перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API. -Он также создан для использования в качестве справочной информации в будущем, чтобы вы могли возвращаться и находить именно то, что вам нужно. - -## Запуск кода +Этот учебник также предназначен для использования в качестве справочника в будущем, так что вы можете вернуться и посмотреть именно то, что вам нужно. Все блоки кода можно копировать и использовать напрямую (это действительно проверенные файлы Python). -Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с помощью: +Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python). + +Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с:
```console $ fastapi dev main.py - FastAPI Начало работы сервера разработки 🚀 + FastAPI Starting development server 🚀 - Поиск структуры файлов пакета в каталогах - с файлами __init__.py - Импорт из /home/user/code/awesomeapp + Searching for package file structure from directories + with __init__.py files + Importing from /home/user/code/awesomeapp module 🐍 main.py - code Импорт объекта приложения FastAPI из модуля со - следующим кодом: + code Importing the FastAPI app object from the module with + the following code: from main import app - app Использование строки импорта: main:app + app Using import string: main:app - server Сервер запущен на http://127.0.0.1:8000 - server Документация доступна по адресу http://127.0.0.1:8000/docs + server Server started at http://127.0.0.1:8000 + server Documentation at http://127.0.0.1:8000/docs - tip Запущен в режиме разработки, для продакшена используйте: + tip Running in development mode, for production use: fastapi run - Логи: + Logs: - INFO Будет отслеживать изменения в этих каталогах: + INFO Will watch for changes in these directories: ['/home/user/code/awesomeapp'] - INFO Uvicorn запущен на http://127.0.0.1:8000 (нажмите CTRL+C - для выхода) - INFO Запущен процесс автоперезагрузки [383138] с использованием WatchFiles - INFO Запущен процесс сервера [383153] - INFO Ожидание запуска приложения. - INFO Запуск приложения завершен. + INFO Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C + to quit) + INFO Started reloader process [383138] using WatchFiles + INFO Started server process [383153] + INFO Waiting for application startup. + INFO Application startup complete. ```
**Настоятельно рекомендуется** написать или скопировать код, отредактировать его и запустить локально. -Использование кода в вашем редакторе действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д. +Использование его в вашем редакторе показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автозавершение и т.д. --- @@ -62,7 +62,7 @@ $ fastapi dev @@ -76,20 +76,20 @@ $ pip install "fastapi[standard]" /// note | Примечание -При установке с помощью `pip install "fastapi[standard]"` поставляются некоторые стандартные дополнительные зависимости, включая `fastapi-cloud-cli`, который позволяет развертывать приложения на FastAPI Cloud. +Если вы устанавливаете с помощью `pip install "fastapi[standard]"`, это включает в себя некоторые стандартные необязательные зависимости, включая `fastapi-cloud-cli`, который позволяет развернуть на FastAPI Cloud. -Если вы не хотите иметь эти необязательные зависимости, вы можете установить `pip install fastapi`. +Если вы не хотите иметь эти необязательные зависимости, можно установить `pip install fastapi`. -Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, вы можете установить с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. +Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, установите с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. /// ## Продвинутое руководство пользователя -Существует также **Продвинутое руководство пользователя**, которое вы можете прочитать после **Учебника - Руководства пользователя**. +Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после **Учебника - Руководства пользователя**. -**Продвинутое руководство пользователя** основывается на этом, использует те же концепции и обучает вас некоторым дополнительным функциям. +**Продвинутое руководство пользователя** основывается на этом, использует те же концепции и учит вас некоторым дополнительным функциям. -Но сначала вам следует прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). +Но сначала вы должны прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). -Он разработан так, чтобы вы могли создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших нужд, с использованием некоторых дополнительных идей из **Продвинутого руководства пользователя**. +Он разработан таким образом, чтобы вы могли создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**. diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md index 609dc19ca..5b1af44da 100644 --- a/docs/ru/docs/tutorial/middleware.md +++ b/docs/ru/docs/tutorial/middleware.md @@ -1,8 +1,8 @@ # Middleware (Промежуточное ПО) -Вы можете добавить промежуточное ПО (middleware) в приложения на **FastAPI**. +Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение. -"Промежуточное ПО" - это функция, которая работает с каждым **запросом** до того, как он обработается какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвратом. +"Middleware" это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением. * Оно обрабатывает каждый **запрос**, поступающий в ваше приложение. * Может что-то сделать с этим **запросом** или выполнить любой необходимый код. @@ -19,9 +19,9 @@ /// -## Создание промежуточного ПО +## Создание middleware -Чтобы создать промежуточное ПО, используйте декоратор `@app.middleware("http")` над функцией. +Для создания middleware используйте декоратор `@app.middleware("http")` над функцией. Функция промежуточного ПО получает: @@ -59,19 +59,19 @@ {* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *} -/// tip | Совет +/// tip | Примечание -Здесь мы используем `time.perf_counter()` вместо `time.time()`, так как он может быть более точным для этих случаев использования. 🤓 +Мы используем `time.perf_counter()` вместо `time.time()` для обеспечения большей точности наших примеров. 🤓 /// -## Порядок выполнения нескольких промежуточных ПО +## Порядок выполнения нескольких middleware -Когда вы добавляете несколько промежуточных ПО с использованием либо декоратора `@app.middleware()`, либо метода `app.add_middleware()`, каждое новое промежуточное ПО оборачивает приложение, формируя стек. Последнее добавленное промежуточное ПО является *самым внешним*, а первое - *самым внутренним*. +Когда вы добавляете несколько middleware с помощью декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, образуя стек. Последнее добавленное middleware будет *внешним*, а первое — *внутренним*. -На пути запроса сначала выполняется *самое внешнее* промежуточное ПО. +На этапе запроса сначала выполняется *внешнее* middleware. -На пути ответа оно выполняется последним. +На этапе ответа оно выполняется последним. Например: @@ -80,16 +80,16 @@ app.add_middleware(MiddlewareA) app.add_middleware(MiddlewareB) ``` -Это приводит к следующему порядку выполнения: +Это приведет к следующему порядку выполнения: * **Запрос**: MiddlewareB → MiddlewareA → маршрут * **Ответ**: маршрут → MiddlewareA → MiddlewareB -Это поведение стека гарантирует, что промежуточные ПО выполняются в предсказуемом и контролируемом порядке. +Такое поведение стека обеспечивает выполнение middleware в предсказуемом и контролируемом порядке. -## Другие промежуточные ПО +## Другие middleware -Вы можете позже прочитать больше о других промежуточных ПО в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}. +О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}. В следующем разделе вы узнаете, как настроить CORS с помощью промежуточного ПО. diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md index bfa043cee..718739b5c 100644 --- a/docs/ru/docs/tutorial/query-params-str-validations.md +++ b/docs/ru/docs/tutorial/query-params-str-validations.md @@ -6,36 +6,36 @@ {* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *} -Query-параметр `q` имеет тип `str | None`, это значит, что он имеет тип `str`, но также может быть `None`. Более того, значение по умолчанию равно `None`, поэтому FastAPI определит, что он не является обязательным. +Query-параметр `q` имеет тип `str | None`. Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный. /// note | Технические детали FastAPI определит, что значение `q` не является обязательным благодаря значению по умолчанию `= None`. -Использование `str | None` позволит вашему редактору кода обеспечить лучшую поддержку и обнаружение ошибок. +`str | None` позволит редактору кода оказать вам лучшую поддержку и найти ошибки. /// ## Дополнительная валидация -Мы хотим убедиться, что даже если `q` является опциональным, когда он предоставлен, **его длина не превышает 50 символов**. +Добавим дополнительное условие валидации параметра `q` — **длина строки не более 50 символов**. ### Импорт `Query` и `Annotated` Для этого сначала импортируйте: -* `Query` из `fastapi` -* `Annotated` из `typing` +* `Query` из пакета `fastapi` +* `Annotated` из пакета `typing` {* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *} /// info | Дополнительная информация -FastAPI добавил поддержку `Annotated` (и стал рекомендовать его) в версии 0.95.0. +FastAPI добавил поддержку `Annotated` (и начал рекомендовать его) в версии 0.95.0. Если у вас более старая версия, вы получите ошибки при попытке использовать `Annotated`. -Убедитесь, что вы [обновите версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`. +Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`. /// @@ -81,7 +81,7 @@ q: Annotated[Union[str, None]] = None //// -Обе версии означают одно и то же: `q` - это параметр, который может быть `str` или `None`, и по умолчанию он равен `None`. +Обе эти версии означают одно и то же. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`. Теперь перейдем к самому интересному. 🎉 @@ -93,23 +93,23 @@ q: Annotated[Union[str, None]] = None Обратите внимание, что значение по умолчанию все еще `None`, так что параметр остается необязательным. -Но теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что хотим иметь **дополнительную валидацию** для этого значения, мы хотим, чтобы оно содержало максимум 50 символов. 😎 +Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим иметь **дополнительные условия валидации** для этого значения, чтобы его длина не превышала 50 символов. 😎 /// tip | Подсказка -Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают те же аргументы, что и `Query()`. +Здесь мы используем `Query()`, так как это **query-параметр**. Позже мы увидим другие параметры, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают те же аргументы, что и `Query()`. /// Теперь FastAPI: -* **Проверит** данные, убедившись, что максимальная длина составляет 50 символов -* Покажет **четкую ошибку** клиента, когда данные невалидны -* **Документирует** параметр в схеме OpenAPI *операции пути* (что будет отображаться в **автоматической документации**) +* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов +* Показывает **понятную ошибку** для клиента в случаях, когда данные не валидны +* **Документирует** параметр в схему OpenAPI *операции пути* (что отображается в **UI автоматической документации**) -## Альтернативный (старый): `Query` как значение по умолчанию +## Альтернативный (устаревший) способ: `Query` как значение по умолчанию -В предыдущих версиях FastAPI (до 0.95.0) требовалось использовать `Query` как значение по умолчанию для вашего параметра, вместо размещения его в `Annotated`. Есть высокая вероятность, что вы увидите код, использующий его, поэтому я объясню его вам. +В предыдущих версиях FastAPI (до 0.95.0) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню. /// tip | Подсказка @@ -123,7 +123,7 @@ q: Annotated[Union[str, None]] = None В этом случае (без использования `Annotated`) мы заменяем значение по умолчанию `None` функции на `Query()`, теперь нам необходимо установить значение по умолчанию с параметром `Query(default=None)`, это служит той же цели определения значения по умолчанию (по крайней мере для FastAPI). -Так: +Таким образом: ```Python q: str | None = Query(default=None) @@ -136,21 +136,21 @@ q: str | None = Query(default=None) q: str | None = None ``` -Но версия с `Query` определяет его явно как query-параметр. +Но версия с `Query` объявляет его как query-параметр. -Затем мы можем передать больше параметров в `Query`. В данном случае, параметр `max_length`, который применяется к строкам: +Теперь, мы можем указать больше параметров для `Query`. В данном случае, параметр `max_length` применяется к строкам: ```Python q: str | None = Query(default=None, max_length=50) ``` -Это проверит данные, покажет четкую ошибку, когда данные невалидны, и задокументирует параметр в OpenAPI схеме *операции пути*. +Входные данные будут проверены. Если данные недействительны, тогда будет указано на ошибку в запросе. Параметр также будет задокументирован в схеме OpenAPI данной *операции пути*. ### `Query` как значение по умолчанию или в `Annotated` Имейте в виду, что при использовании `Query` внутри `Annotated` вы не можете использовать параметр `default` у `Query`. -Вместо этого используйте фактическое значение по умолчанию параметра функции. В противном случае это будет не совместимо. +Вместо этого, используйте обычное указание значения по умолчанию для параметра функции. Иначе это будет несовместимо. Например, это не разрешено: @@ -166,7 +166,7 @@ q: Annotated[str, Query(default="rick")] = "morty" q: Annotated[str, Query()] = "rick" ``` -...или в старых кодовых базах вы найдете: +...или в кодовой базе, которую вам может встретиться: ```Python q: str = Query(default="rick") @@ -174,13 +174,13 @@ 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` может иметь более одной аннотации метаданных, вы теперь даже можете использовать одну и ту же функцию с другими инструментами, такими как Typer. 🚀 @@ -198,19 +198,19 @@ q: str = Query(default="rick") Это регулярное выражение проверяет, что полученное значение параметра: -* `^`: начинается с следующих символов, перед которыми ничего нет. -* `fixedquery`: имеет точное значение `fixedquery`. -* `$`: заканчивается здесь, после `fixedquery` нет символов. +* `^`: начинается с следующих символов, не имеет символов перед. +* `fixedquery`: в точности содержит строку `fixedquery`. +* `$`: заканчивается там, где `fixedquery`, не имеет символов после. Если вам сложно дается концепция **"регулярные выражения"**, не беспокойтесь. Для многих людей это трудная тема. Вы можете делать множество вещей, не прибегая к регулярным выражениям. -Теперь вы знаете, что когда они вам понадобятся, вы сможете использовать их в **FastAPI**. +Теперь вы знаете, что, когда вам понадобятся регулярные выражения, вы сможете использовать их в **FastAPI**. -### Pydantic v1 `regex` вместо `pattern` +### `regex` в Pydantic v1 вместо `pattern` -До версии Pydantic 2 и до FastAPI 0.100.0 параметр назывался `regex` вместо `pattern`, но теперь он устарел. +До версии Pydantic 2 и FastAPI 0.100.0, параметр назывался `regex` вместо `pattern`, но сейчас он считается устаревшим. -Вы все еще можете увидеть код, использующий его: +Вы всё ещё можете встретить код, использующий его: //// tab | Pydantic v1 @@ -218,13 +218,13 @@ q: str = Query(default="rick") //// -Но знайте, что это устаревшая версия и ее следует обновить для использования нового параметра `pattern`. 🤓 +Однако знайте, что это устарело и стоит обновить используемый параметр на `pattern`. 🤓 ## Значения по умолчанию -Разумеется, вы можете использовать значения по умолчанию, отличные от `None`. +Вы можете также указать любое значение `по умолчанию`, отличное от `None`. -Предположим, вы хотите объявить query-параметр `q` с `min_length` равным `3` и со значением по умолчанию `"fixedquery"`: +Например, если вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`: {* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *} @@ -236,7 +236,7 @@ q: str = Query(default="rick") ## Обязательный параметр -Когда нам не нужно объявлять больше валидации или метаданных, мы можем сделать query-параметр `q` обязательным, просто не объявляя значение по умолчанию, например: +Когда вам не требуется дополнительная валидация или другие метаданные для параметра запроса, вы можете сделать параметр `q` обязательным просто не указывая значения по умолчанию. Например: ```Python q: str @@ -248,7 +248,7 @@ q: str q: str | None = None ``` -Но мы теперь определяем его с `Query`, например так: +Но в настоящее время мы определяем его через `Query`. Например: //// tab | Annotated @@ -258,7 +258,7 @@ q: Annotated[str | None, Query(min_length=3)] = None //// -Так что, когда вам нужно объявить значение обязательным при использовании `Query`, вы можете просто не указывать значение по умолчанию: +Так что, если вы хотите сделать query-параметр `Query` обязательным, вы можете просто не указывать значение по умолчанию: {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} @@ -266,13 +266,13 @@ q: Annotated[str | None, Query(min_length=3)] = None Вы можете объявить, что параметр может принимать значение `None`, но при этом является обязательным. Это заставит клиентов отправлять значение, даже если оно равно `None`. -Для этого вы можете объявить, что `None` допустимый тип, но просто не указывать значение по умолчанию: +Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но не указывать значение по умолчанию: {* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *} -## Список значений для query-параметра / несколько значений +## Множество значений для query-параметра -Когда вы явно определяете query-параметр с помощью `Query`, вы также можете указать его как принимающий список значений или, иначе говоря, принимающий несколько значений. +Для query-параметра `Query` можно указать, что он принимает список значений (множество значений). Например, чтобы объявить query-параметр `q`, который может появляться несколько раз в URL, вы можете написать: @@ -340,7 +340,7 @@ http://localhost:8000/items/ Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка. -Например, `list[int]` бы проверяла (и документировала), что содержимое списка является целыми числами. Но простой `list` не будет этого делать. +Например, для List[int] список будет валидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет. /// @@ -354,11 +354,11 @@ http://localhost:8000/items/ Имейте в виду, что разные инструменты могут иметь разный уровень поддержки OpenAPI. -Некоторые из них могут не показывать всю дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке. +Некоторые из них могут не отображать всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке. /// -Вы можете добавить `title`: +Вы можете добавить название query-параметра, используя параметр `title`: {* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *} @@ -408,11 +408,11 @@ http://127.0.0.1:8000/items/?item-query=foobaritems ## Кастомная валидация -Могут быть случаи, когда вам потребуется выполнить **кастомную валидацию**, которая не может быть выполнена с показанными выше параметрами. +Могут быть случаи, когда вам нужно исполнить **кастомную валидацию**, которую нельзя выполнить с использованием только параметров, описанных выше. -В таких случаях вы можете использовать **кастомную функцию валидации**, которая применяется после обычной валидации (например, после проверки что значение является `str`). +В таких сценариях, вы можете использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки значения на совпадение с `str`). -Вы можете это сделать, используя Pydantic's `AfterValidator` внутри `Annotated`. +Это можно сделать, используя `AfterValidator` из Pydantic внутри `Annotated`. /// tip | Подсказка @@ -420,57 +420,57 @@ Pydantic также имеет итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. +С `data.items()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. -Мы преобразуем этот итерируемый объект в полноценный `list` с `list(data.items())`. +Мы преобразуем этот итерируемый объект в обычный `list` с помощью `list(data.items())`. -Затем с помощью `random.choice()` мы можем получить **случайное значение** из списка, так что мы получаем кортеж с `(id, name)`. Это будет что-то вроде `("imdb-tt0371724", "Автостопом по галактике")`. +Затем через `random.choice()` мы можем получить **случайное значение** из списка, это будет кортеж `(id, name)`. Пример: `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`. -Затем мы **присваиваем эти два значения** кортежа переменным `id` и `name`. +Потом мы **присваиваем эти два значения** из кортежа переменным `id` и `name`. -Таким образом, если пользователь не предоставил ID предмета, он все равно получит случайное предложение. +Так, если пользователь не передал ID элемента, они всё равно получат случайное предложение. -...все это мы делаем в **одной простой строке**. 🤯 Разве вы не любите Python? 🐍 +...всё это выполняется в одной **простой строке**. 🤯 Разве вы не любите Python? 🐍 {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *} ## Резюме -Вы можете объявлять дополнительные валидации и метаданные для ваших параметров. +Вы можете объявлять дополнительные правила валидации и метаданные для ваших параметров. Общие валидации и метаданные: @@ -489,4 +489,4 @@ Pydantic также имеет `http.HTTPStatus` в Python. +В качестве значения параметра `status_code` может также использоваться `IntEnum`, например, из библиотеки Python `http.HTTPStatus`. /// Это позволит: -* Возвращать указанный код состояния в ответе. -* Документировать его в OpenAPI схеме (и, соответственно, в пользовательских интерфейсах): +* Возвращать указанный код статуса в ответе. +* Документировать его как таковой в OpenAPI схеме (а значит, и в пользовательском интерфейсе): /// note | Примечание -Некоторые коды состояния ответа (см. следующий раздел) указывают на то, что тело ответа отсутствует. +Некоторые коды ответа (см. следующий раздел) указывают, что ответа с телом не будет. -FastAPI об этом знает и создаст документацию OpenAPI, в которой будет указано, что тела ответа нет. +FastAPI знает об этом и создаст документацию OpenAPI, которая укажет, что тело ответа отсутствует. /// -## О HTTP кодах состояния +## Об HTTP статус-кодах /// note | Примечание -Если вы уже знаете, что такое HTTP коды состояния, пропустите этот раздел. +Если вы уже знаете, что такое HTTP статус-коды, можете пропустить этот раздел. /// В HTTP вы отправляете числовой код состояния из 3 цифр как часть ответа. -У этих кодов состояния есть название для их распознавания, но важной частью является число. +У этих кодов статуса есть связанные с ними названия для их распознавания, но важна именно числовая часть. -Вкратце: +Кратко о значениях: -* `100 - 199` предназначены для "Информации". Вы редко используете их напрямую. Ответы с этими кодами состояния не могут иметь тело. -* **`200 - 299`** предназначены для "Успешных" ответов. Это те, которые вы будете использовать чаще всего. - * `200` — код состояния по умолчанию, означающий, что все прошло "ОК". - * Другой пример — `201`, "Создано". Он обычно используется после создания новой записи в базе данных. - * Особый случай — `204`, "Нет содержимого". Этот ответ используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела. -* **`300 - 399`** предназначены для "Перенаправления". Ответы с этими кодами состояния могут иметь или не иметь тело, за исключением `304`, "Не изменено", который не должен иметь тела. -* **`400 - 499`** предназначены для "Ошибки клиента". Это второй по распространенности тип использования. - * Пример — `404`, для ответа "Не найдено". - * Для общих ошибок клиента можно использовать `400`. -* `500 - 599` предназначены для ошибок сервера. Вы почти никогда не используете их напрямую. Когда что-то идет не так в вашем приложении или на сервере, автоматически возвращается один из этих кодов состояния. +* `100 - 199` — это информационные коды. Вы редко используете их напрямую. Ответы с этими кодами не должны содержать тело. +* **`200 - 299`** — это успешные ответы. Эти вы будете использовать чаще всего. + * `200` — это код по умолчанию, который означает, что все прошло "OK". + * Другой пример — `201`, "Created". Он часто используется после создания новой записи в базе данных. + * Особый случай — `204`, "No Content". Этот ответ используется, когда нет содержимого для возврата клиенту, и поэтому тело отсутствует. +* **`300 - 399`** — это коды перенаправлений. Ответы с этими кодами статуса могут, а могут и не иметь тело, за исключением `304`, "Not Modified", у которого его не должно быть. +* **`400 - 499`** — это ошибки клиента. Это вторая группа, которую вы, вероятно, будете использовать чаще всего. + * Пример — `404`, для ответа "Not Found". + * Для общих ошибок клиента можно использовать просто `400`. +* `500 - 599` — это ошибки сервера. Вы почти никогда не используете их напрямую. Когда что-то идет не так в коде вашего приложения или на сервере, он автоматически возвращает один из этих кодов. -/// tip | Подсказка +/// tip | Совет -Чтобы узнать больше о каждом коде состояния и их значении, ознакомьтесь с документацией MDN о HTTP кодах состояния. +Чтобы узнать больше о каждом статус-коде и для чего он предназначен, ознакомьтесь с документацией MDN об HTTP кодах статуса. /// @@ -76,7 +76,7 @@ FastAPI об этом знает и создаст документацию Open {* ../../docs_src/response_status_code/tutorial001.py hl[6] *} -`201` — это код состояния для "Создано". +`201` — это код статуса "Создано". Но вам не обязательно запоминать значение каждого из этих кодов. @@ -84,7 +84,7 @@ FastAPI об этом знает и создаст документацию Open {* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *} -Они являются просто удобством, они содержат те же числа, но позволяют использовать автодополнение редактора для их выбора: +Они содержат те же числовые значения, но позволяют использовать авто-завершение редактора для выбора кода статуса: @@ -92,10 +92,10 @@ FastAPI об этом знает и создаст документацию Open Вы также можете использовать `from starlette import status`. -**FastAPI** предоставляет `starlette.status` так же, как `fastapi.status` исключительно для удобства разработчиков. Но `fastapi.status` поставляется непосредственно из Starlette. +**FastAPI** предоставляет `starlette.status` как `fastapi.status` исключительно для удобства разработчиков. Однако он поставляется непосредственно из Starlette. /// -## Изменение значения по умолчанию +## Изменение кода по умолчанию -Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать другой код состояния, отличный от объявленного здесь по умолчанию. +Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP код статуса, отличный от используемого здесь кода по умолчанию. diff --git a/docs/ru/docs/tutorial/sql-databases.md b/docs/ru/docs/tutorial/sql-databases.md index 383059f2d..149281347 100644 --- a/docs/ru/docs/tutorial/sql-databases.md +++ b/docs/ru/docs/tutorial/sql-databases.md @@ -1,40 +1,40 @@ # SQL (реляционные) базы данных -**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которую хотите. +**FastAPI** не требует от вас использования реляционной базы данных. Но вы можете использовать **любую базу данных**, которую захотите. -В этом разделе мы рассмотрим пример использования SQLModel. +Здесь мы увидим пример, использующий SQLModel. -**SQLModel** построен на основе SQLAlchemy и Pydantic. Он был создан тем же автором, что и **FastAPI**, для обеспечения идеальной совместимости приложений на FastAPI, использующих **реляционные базы данных**. +**SQLModel** построен на основе SQLAlchemy и Pydantic. Он был создан автором **FastAPI** и является идеальным выбором для приложений FastAPI, которые нуждаются в реляционных базах данных. /// tip | Совет -Вы можете воспользоваться любой другой библиотекой для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных, нельзя сказать, что FastAPI вас вынуждает использовать что-то конкретное. 😎 +Вы можете использовать любую другую библиотеку для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных, в некоторых случаях называемую "ORMs". FastAPI не заставляет вас использовать что-то конкретное. 😎 /// -Поскольку SQLModel основан на SQLAlchemy, можно легко использовать **любую базу данных**, поддерживаемую SQLAlchemy (что делает их также поддерживаемыми SQLModel), такие как: +Поскольку SQLModel основан на SQLAlchemy, вы можете легко использовать **любую базу данных, поддерживаемую** SQLAlchemy (соответственно поддерживаемую SQLModel), например: * PostgreSQL * MySQL * SQLite * Oracle -* Microsoft SQL Server, и т.д. +* Microsoft SQL Server и т. д. -В этом примере мы будем использовать **SQLite**, так как она состоит из единственного файла, и Python имеет интегрированную поддержку. Таким образом, вы сможете скопировать этот пример и запустить его как есть. +В этом примере мы будем использовать базу данных **SQLite**, потому что она использует один файл, и поддержка Python встроена. Таким образом, вы можете скопировать этот пример и запустить его как есть. -Позже, для вашей продукции, вы, возможно, захотите использовать сервер базы данных, например **PostgreSQL**. +В дальнейшем, для продакшн-версии вашего приложения, возможно, вам стоит использовать серверную базу данных, такую как **PostgreSQL**. /// tip | Совет -Существует официальный генератор проектов с **FastAPI** и **PostgreSQL**, включающий frontend и другие инструменты: https://github.com/fastapi/full-stack-fastapi-template +Существует официальный генератор проектов с **FastAPI** и **PostgreSQL**, включая frontend и другие инструменты: https://github.com/fastapi/full-stack-fastapi-template /// -Это очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, о SQL или более продвинутых функциях, обратитесь к документации SQLModel. +Это очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, об SQL или более продвинутых возможностях, обратитесь к документации SQLModel. ## Установка `SQLModel` -Сначала убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его и затем установили `sqlmodel`: +Сначала убедитесь, что вы создали свое [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили `sqlmodel`:
@@ -45,11 +45,11 @@ $ pip install sqlmodel
-## Создание приложения с единственной моделью +## Создание приложения с одной моделью -Мы начнем с создания самой простой, первой версии приложения с одной моделью **SQLModel**. +Мы сначала создадим самую простую версию приложения с одной моделью **SQLModel**. -Позднее мы улучшим его, повышая безопасность и универсальность, добавив **несколько моделей** ниже. 🤓 +Позже мы улучшим его, повысив безопасность и универсальность за счет **нескольких моделей** ниже. 🤓 ### Создание моделей @@ -57,91 +57,91 @@ $ pip install sqlmodel {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *} -Класс `Hero` очень похож на модель Pydantic (фактически, под капотом, он на самом деле *является моделью Pydantic*). +Класс `Hero` очень похож на модель Pydantic (по сути, под капотом, это действительно *модель Pydantic*). -Есть несколько отличий: +Но есть несколько различий: -* `table=True` указывает SQLModel, что это модель-таблица, она должна представлять **таблицу** в реляционной базе данных, а не просто модель данных (как любой другой обычный класс Pydantic). +* `table=True` говорит SQLModel, что это *модель таблицы*, она должна представлять **таблицу** в реляционной базе данных, это не просто *модель данных* (в отличие от обычного класса Pydantic). -* `Field(primary_key=True)` указывает SQLModel, что `id` является **первичным ключом** в базе данных SQL (вы можете узнать больше о первичных ключах баз данных в документации SQLModel). +* `Field(primary_key=True)` говорит SQLModel, что `id` является **первичным ключом** в базе данных SQL (более подробно о первичных ключах SQL можно узнать в документации SQLModel). - Тип `int | None` говорит SQLModel, что этот столбец должен иметь тип `INTEGER` в базе данных SQL и быть `NULLABLE`. + Тип `int | None` сообщает SQLModel, что этот столбец должен быть `INTEGER` в базе данных SQL и что он должен быть `NULLABLE`. -* `Field(index=True)` указывает SQLModel, что для этого столбца должен быть создан SQL-индекс, который позволит ускорить поиск в базе данных при чтении данных, отфильтрованных по этому столбцу. +* `Field(index=True)` говорит SQLModel, что он должен создать **SQL индекс** для этого столбца, что позволит ускорить поиск в базе данных при чтении данных, отфильтрованных по этому столбцу. - SQLModel будет считать, что данные, объявленные как `str`, будут храниться в базе данных как столбец типа `TEXT` (или `VARCHAR`, в зависимости от базы данных). + SQLModel будет знать, что нечто объявленное как `str` будет SQL-столбцом типа `TEXT` (или `VARCHAR`, в зависимости от базы данных). -### Создание `Engine` +### Создание подключения -Объект `engine` в SQLModel (под капотом это на самом деле `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 в разных потоках. Это необходимо, так как один единственный запрос может использовать более одного потока (например, в зависимостях). +Использование `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`, чтобы упростить остальной код, который будет использовать эту зависимость. +Затем мы создадим объявленную зависимость `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 | Совет -SQLModel будет иметь утилиты миграции, оборачивающие Alembic, но сейчас вы можете использовать Alembic напрямую. +В SQLModel будут включены утилиты для миграции на основе Alembic, но пока вы можете использовать Alembic напрямую. /// ### Создание героя -Так как каждая модель SQLModel также является моделью Pydantic, вы можете использовать ее в тех же **аннотациях типов**, что и модели Pydantic. +Поскольку каждая модель в SQLModel также является моделью Pydantic, вы можете использовать её в тех же **аннотациях типов**, что и модели Pydantic. -Например, если вы объявляете параметр типа `Hero`, он будет считан из **тела JSON**. +Например, если вы объявите параметр типа `Hero`, он будет прочитан из **тела JSON**. -Таким же образом вы можете объявить его как **возвращаемый тип** функции, и тогда структура данных будет отображаться в автоматически созданной документации API. +Точно так же, вы можете объявить его как **возвращаемый тип функции**, и тогда форма данных будет отображаться в интерфейсе автоматической документации API. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} -Здесь мы используем зависимость `SessionDep` (объект `Session`), чтобы добавить нового `Hero` в экземпляр `Session`, зафиксировать изменения в базе данных, обновить данные в `hero`, а затем вернуть их. +Здесь мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их. ### Чтение данных героев -Мы можем **читать** героев `Hero` из базы данных, используя `select()`. Мы можем включить `limit` и `offset` для постраничного доступа к результатам. +Мы можем **читать** данных героев из базы данных, используя `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *} ### Чтение данных одного героя -Мы можем **читать** данные одного героя: +Мы можем **читать** данные одного героя. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *} ### Удаление героя -Мы также можем **удалить** героя `Hero`. +Мы можем также **удалить** героя. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *} @@ -159,7 +159,7 @@ $ fastapi dev main.py
-Затем перейдите в пользовательский интерфейс `/docs`, вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также использует их для **сериализации** и **проверки** данных. +Затем перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также для **сериализации** и **проверки** данных.
@@ -167,27 +167,27 @@ $ fastapi dev main.py ## Обновление приложения с несколькими моделями -Теперь давайте немного **отрефакторим** приложение для повышения **безопасности** и **универсальности**. +Теперь давайте немного **отрефакторим** это приложение, чтобы повысить его **безопасность** и **универсальность**. -Если вы посмотрите на предыдущее приложение, в пользовательском интерфейсе вы можете увидеть, что до сих пор оно позволяет клиенту определять `id` для создаваемого `Hero`. 😱 +Если вы посмотрите на предыдущее приложение, в UI вы увидите, что до сих пор оно позволяет клиенту задавать `id` создаваемого героя (`Hero`). 😱 -Мы не должны этого допускать, это может привести к перезаписи `id`, который был уже присвоен в базе данных. Определение `id` должно выполняться на уровне **backend** или **базы данных**, а не **клиентом**. +Нам нельзя допускать этого, так как они могут перезаписать `id`, который у нас уже есть в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда** или **на уровне базы данных**, **не на уровне клиента**. -Кроме того, мы создаем `secret_name` для героя, но везде его возвращаем, это совсем не **секретно**... 😅 +Кроме того, мы создаём `secret_name` для героя, но на данный момент мы возвращаем его везде, и это не очень **секретно**... 😅 -Мы исправим эти вещи, добавив несколько **дополнительных моделей**. Здесь SQLModel будет по-настоящему полезен. ✨ +Мы исправим это, добавив несколько **дополнительных моделей**. Вот где SQLModel действительно засияет. ✨ ### Создание нескольких моделей -В **SQLModel** любая модель с `table=True` является **моделью таблицы**. +В **SQLModel** любая модель класса, содержащая `table=True`, является **моделью таблицы**. -А любые моделия без `table=True` являются **моделями данных**, которые на самом деле просто модели Pydantic (с парой небольших расширений). 🤓 +А любая модель класса без `table=True` является **моделью данных**, они на самом деле представляют собой модели Pydantic (с несколькими небольшими дополнительными возможностями). 🤓 С помощью SQLModel мы можем использовать **наследование**, чтобы **избежать дублирования** всех полей во всех случаях. #### `HeroBase` - базовый класс -Начнем с модели `HeroBase`, содержащей все **общие поля** для всех моделей: +Начнем с модели `HeroBase`, которая имеет все **общие поля** для всех моделей: * `name` * `age` @@ -196,12 +196,12 @@ $ fastapi dev main.py #### `Hero` - *модель таблицы* -Затем создадим `Hero`, текущую модель таблицы с **дополнительными полями**, которые не всегда будут в других моделях: +Затем создадим `Hero`, это фактическая *модель таблицы*, с **дополнительными полями**, которых может не быть в других моделях: * `id` * `secret_name` -Поскольку `Hero` наследуется от `HeroBase`, он также имеет **поля**, объявленные в `HeroBase`, так что все поля для `Hero`: +Так как `Hero` наследует от `HeroBase`, он **также** содержит **поля**, объявленные в `HeroBase`, так что все поля для `Hero` следующие: * `id` * `name` @@ -212,23 +212,23 @@ $ fastapi dev main.py #### `HeroPublic` - публичная *модель данных* -Далее создадим модель `HeroPublic`, которая будет **возвращаться** клиенту API. +Далее создаём модель `HeroPublic`, это модель, которая будет **возвращаться** клиентам API. -Она имеет те же поля, что и `HeroBase`, поэтому не будет содержать `secret_name`. +Она имеет те же поля, что и `HeroBase`, поэтому не будет включать `secret_name`. -Теперь личность наших героев защищена! 🥷 +Наконец-то личности наших героев защищены! 🥷 -Кроме того, она снова объявляет `id: int`. Делая это, мы заключаем **контракт** с клиентами API, чтобы они всегда могли ожидать, что `id` будет там и будет `int` (никогда не будет `None`). +Также она повторном объявляет `id: int`. Таким образом мы устанавливаем **договоренность** с клиентами API, что они всегда могут ожидать наличие `id` и то, что это будет `int` (оно никогда не будет `None`). /// tip | Совет -Имейте модель ответа, обеспечивающую доступность значения и всегда `int` (не `None`), это очень полезно для клиентов API. Они могут писать намного проще код, имея эту уверенность. +Наличие в модели возврата гарантии того, что значение всегда будет доступно и будет `int` (не `None`), очень полезно для API-клиентов, они могут писать более простой код с этой уверенностью. -Кроме того, **автоматически сгенерированные клиенты** будут иметь более простые интерфейсы, чтобы разработчикам, работающим с вашим API, было значительно легче. 😎 +Кроме того, автоматически сгенерированные клиенты будут иметь более простые интерфейсы, так что разработчикам, работающим с вашим API, будет значительно проще. 😎 /// -Все поля в `HeroPublic` такие же, как и в `HeroBase`, с `id`, объявленным как `int` (не `None`): +Все поля в `HeroPublic` такие же, как в `HeroBase`, с `id`, объявленным как `int` (не `None`): * `id` * `name` @@ -238,17 +238,17 @@ $ fastapi dev main.py #### `HeroCreate` - *модель данных* для создания героя -Теперь создадим модель `HeroCreate`, которая будет **проверять** данные клиентов. +Сейчас мы создаём модель `HeroCreate`. Это модель, которая будет **проверять** данные от клиентов. -Она имеет те же поля, что и `HeroBase`, а также включает `secret_name`. +Она содержит те же поля, что и `HeroBase`, а также `secret_name`. -Теперь, когда клиенты **создают нового героя**, они отправляют `secret_name`, который будет сохранен в базе данных, но эти секретные имена не будут возвращены в API клиентам. +Теперь, когда клиенты **создают нового героя**, они отправят `secret_name`, он будет сохранён в базе данных, но эти секретные имена не будут возвращаться в API клиентам. /// tip | Совет -Вот как вы должны работать с **паролями**: получайте их, но не возвращайте через API. +Это то, как вы должны обрабатывать **пароли**: получайте их, но не возвращайте их в API. -Вы также должны **хэшировать** значения паролей перед их сохранением, **никогда не храните их в открытом виде**. +Также **хешируйте** значения паролей перед их сохранением, **никогда не храните их в открытом виде**. /// @@ -260,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`: @@ -280,29 +280,29 @@ $ fastapi dev main.py ### Создание с помощью `HeroCreate` и возврат `HeroPublic` -Теперь, когда у нас есть **несколько моделей**, мы можем обновить те части приложения, которые их используют. +Теперь, когда у нас есть **несколько моделей**, мы можем обновить части приложения, которые их используют. -В запросе мы получаем *модель данных* `HeroCreate`, и из нее создаем `Hero` *модель таблицы*. +Мы получаем в запросе модель данных `HeroCreate`, и из нее создаём модель таблицы `Hero`. -Эта новая *модель таблицы* `Hero` будет иметь поля, отправленные клиентом, и также `id`, сгенерированный базой данных. +Эта новая модель таблицы `Hero` будет иметь поля, отправленные клиентом, а также `id`, сгенерированное базой данных. -Затем мы возвращаем ту же *модель таблицы* `Hero` из функции. Но так как мы объявили `response_model` с *моделью данных* `HeroPublic`, **FastAPI** будет использовать `HeroPublic` для проверки и сериализации данных. +Затем возвращаем ту же модель таблицы `Hero` как есть из функции. Но так как мы объявляем `response_model` с моделью данных `HeroPublic`, **FastAPI** будет использовать `HeroPublic` для проверки и сериализации данных. {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *} /// tip | Совет -Теперь мы используем `response_model=HeroPublic` вместо **аннотации возвращаемого типа** `-> HeroPublic`, потому что значение, которое мы возвращаем, на самом деле *не является* `HeroPublic`. +Теперь мы используем `response_model=HeroPublic` вместо аннотации **возвращаемого типа** `-> HeroPublic`, потому что значение, которое мы возвращаем, **на самом деле не** `HeroPublic`. -Если бы мы объявили `-> HeroPublic`, ваш редактор и linter начали бы жаловаться (и вполне справедливо), что вы возвращаете `Hero`, а не `HeroPublic`. +Если бы мы объявили `-> HeroPublic`, ваш редактор и линтер бы пожаловались (и справедливо), что вы возвращаете `Hero`, а не `HeroPublic`. -Объявляя это в `response_model`, мы говорим **FastAPI** делать свое дело, не мешая аннотациям типов и не полагаясь на помощь от вашего редактора и других инструментов. +Объявляя это в `response_model`, мы говорим **FastAPI** делать свое дело, не вмешиваясь в аннотации типов и не полагаясь на помощь редактора и других инструментов. /// ### Чтение героев с `HeroPublic` -Мы можем сделать то же самое при **чтении** героев, опять же используем `response_model=list[HeroPublic]`, чтобы убедиться, что данные правильно проверены и сериализованы. +Мы можем сделать то же самое, как и раньше для **чтения** данных героев, используя `response_model=list[HeroPublic]`, чтобы обеспечить правильную валидацию и сериализацию данных. {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *} @@ -312,25 +312,25 @@ $ fastapi dev main.py {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *} -### Обновление героя с `HeroUpdate` +### Обновление героя с помощью `HeroUpdate` -Мы можем **обновить героя**. Для этого используем HTTP-метод `PATCH`. +Мы можем **обновить героя**. Для этого мы используем HTTP-операцию `PATCH`. -В коде мы получаем словарь `dict` с данными, отправленными клиентом, **только данными, отправленными клиентом**, исключаем любые значения, которые были бы там только из-за значений по умолчанию. Чтобы сделать это, используем `exclude_unset=True`. Это главная хитрость. 🪄 +И в коде мы получаем объект `dict` со всеми данными, отправленными клиентом, содержанием **только данных, отправленных клиентом**, исключая любые значения, которые могут быть там только как значения по умолчанию. Для этого мы используем `exclude_unset=True`. Это главный трюк. 🪄 Затем используем `hero_db.sqlmodel_update(hero_data)`, чтобы обновить `hero_db` данными из `hero_data`. {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *} -### Удаление героя ещё раз +### Удаление героя снова -Удаление героя **остается практически без изменений**. +Операция **удаления** героя остаётся практически неизменной. -Желание всё *`отрефакторить`* здесь не будет удовлетворено. 😅 +В этом случае желание *`отрефакторить всё`* остаётся неудовлетворённым. 😅 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} -### Снова запустите приложение +### Снова запуск приложения Вы можете снова запустить приложение: @@ -344,7 +344,7 @@ $ fastapi dev main.py
-Если вы зайдете в пользовательский интерфейс `/docs`, вы увидите, что он теперь обновлен, и не будет ожидать получить `id` от клиента при создании героя и т.д. +Если вы пойдете в пользовательский интерфейс API `/docs`, вы увидите, что он обновлен и больше не ожидает получение параметра `id` от клиента при создании нового героя и т.д.
@@ -352,6 +352,6 @@ $ fastapi dev main.py ## Резюме -Вы можете использовать **SQLModel** для взаимодействия с реляционными базами данных и упрощения работы с *моделями данных* и *моделями таблиц*. +Вы можете использовать **SQLModel** для взаимодействия с реляционной базой данных и упрощения кода с *моделями данных* и *моделями таблиц*. -Вы можете узнать намного больше в документации **SQLModel**, там есть более длительное мини-руководство по использованию SQLModel с **FastAPI**. 🚀 +Вы можете узнать гораздо больше в документации **SQLModel**, там есть более длительное мини руководство по использованию SQLModel с **FastAPI**. 🚀 diff --git a/docs/ru/docs/virtual-environments.md b/docs/ru/docs/virtual-environments.md index 7bdf7d8d7..d5a1e271d 100644 --- a/docs/ru/docs/virtual-environments.md +++ b/docs/ru/docs/virtual-environments.md @@ -1,28 +1,28 @@ -# Виртуальные среды +# Виртуальное окружение -Когда вы работаете над проектами на Python, рекомендуется использовать **виртуальную среду** (или аналогичный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта. +Когда вы работаете с проектами на Python, вероятно, вам стоит использовать **виртуальное окружение** (или аналогичный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта. /// info | Информация -Если вы уже знаете о виртуальных средах, как их создавать и использовать, вы можете пропустить этот раздел. 🤓 +Если вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓 /// /// tip | Совет -**Виртуальная среда** отличается от **переменной окружения**. +**Виртуальное окружение** отличается от **переменной окружения**. **Переменная окружения** — это системная переменная, которую могут использовать программы. -**Виртуальная среда** — это директория, содержащая некоторые файлы. +**Виртуальное окружение** — это директория с файлами. /// /// info | Информация -На этой странице вы узнаете, как использовать **виртуальные среды** и как они работают. +Этот раздел научит вас использовать **виртуальные окружения** и как они работают. -Если вы готовы использовать **инструмент, который управляет всем** для вас (включая установку Python), попробуйте uv. +Если вы готовы начать использовать **инструмент, который управляет всем** за вас (включая установку Python), попробуйте uv. /// @@ -30,40 +30,40 @@ Сначала создайте директорию для вашего проекта. -Обычно я создаю директорию с названием `code` внутри своего домашнего каталога. +Обычно я создаю директорию с именем `code` внутри моего домашнего каталога. -И внутри этой директории я создаю по одной директории на каждый проект. +И внутри этой директории создаю одну папку для каждого проекта.
```console // Перейти в домашний каталог $ cd -// Создать директорию для всех проектов +// Создайте директорию для всех ваших проектов с кодом $ mkdir code -// Войти в эту директорию +// Войдите в указанную директорию $ cd code -// Создать директорию для этого проекта +// Создайте директорию для этого проекта $ mkdir awesome-project -// Войти в директорию проекта +// Перейдите в эту директорию проекта $ cd awesome-project ```
-## Создание виртуальной среды +## Создание виртуального окружения -Когда вы впервые начинаете работу над проектом на Python, создайте виртуальную среду **внутри вашего проекта**. +Когда вы начинаете работать над Python-проектом **в первый раз**, создайте виртуальное окружение **внутри вашего проекта**. /// tip | Совет -Это нужно сделать только **один раз для проекта**, а не каждый раз, когда вы работаете. +Вы должны сделать это **один раз на проект**, а не каждый раз, когда работаете. /// //// tab | `venv` -Для создания виртуальной среды вы можете использовать модуль `venv`, который поставляется с Python. +Чтобы создать виртуальное окружение, вы можете использовать модуль `venv`, который входит в комплект поставки Python.
@@ -73,12 +73,12 @@ $ python -m venv .venv
-/// details | Что делает эта команда? +/// details | Что делает эта команда -* `python`: используется программа под названием `python` -* `-m`: вызывает модуль как скрипт, далее укажем, какой модуль -* `venv`: используется модуль под названием `venv`, который обычно устанавливается вместе с Python -* `.venv`: создаёт виртуальную среду в новой директории `.venv` +* `python`: использовать программу `python` +* `-m`: вызвать модуль как сценарий, далее укажем, какой модуль использовать +* `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python +* `.venv`: создать виртуальное окружение в новой директории `.venv` /// @@ -86,7 +86,7 @@ $ python -m venv .venv //// tab | `uv` -Если у вас установлен `uv`, вы можете использовать его для создания виртуальной среды. +Если у вас установлен `uv`, вы можете использовать его для создания виртуального окружения.
@@ -98,29 +98,29 @@ $ uv venv /// tip | Совет -По умолчанию `uv` создаёт виртуальную среду в директории, называемой `.venv`. +По умолчанию `uv` создаст виртуальное окружение в директории под названием `.venv`. -Но вы можете изменить это, добавив дополнительный аргумент с именем директории. +Но вы можете изменить это, передав дополнительный аргумент с именем директории. /// //// -Эта команда создаёт новую виртуальную среду в директории, называемой `.venv`. +Эта команда создаст новое виртуальное окружение в директории `.venv`. -/// details | `.venv` или другое имя? +/// details | `.venv` или другое имя -Вы можете создать виртуальную среду в другой директории, но существует традиция называть её `.venv`. +Вы можете создать виртуальное окружение в другой директории, но принято называть его `.venv`. /// -## Активация виртуальной среды +## Активация виртуального окружения -Активируйте созданную виртуальную среду, чтобы любая выполняемая команда Python или устанавливаемый пакет использовали её. +Активируйте новое виртуальное окружение, чтобы любая команда Python, которую вы запускаете, или пакет, который вы устанавливаете, использовала его. /// tip | Совет -Делайте это **каждый раз**, когда начинаете **новую сессию терминала** для работы над проектом. +Делайте это **каждый раз**, начиная **новую сессию терминала** для работы над проектом. /// @@ -150,7 +150,7 @@ $ .venv\Scripts\Activate.ps1 //// tab | Windows Bash -Или, если вы используете Bash для Windows (например, Git Bash): +Или если вы используете Bash для Windows (например, Git Bash):
@@ -170,13 +170,21 @@ $ source .venv/Scripts/activate /// -## Проверка активации виртуальной среды +/// tip | Подсказка -Проверьте, активна ли виртуальная среда (предыдущая команда сработала). +Каждый раз, когда вы устанавливаете **новый пакет** в этой среде, **активируйте** ее снова. + +Это гарантирует, что если вы используете программу из **терминала (CLI)**, установленную этим пакетом, вы используете ту, что в вашем виртуальном окружении, а не ту, что может быть установлена глобально, с другой версией, чем вам нужно. + +/// + +## Проверка активации виртуального окружения + +Проверьте, что виртуальное окружение активно (предыдущая команда сработала). /// tip | Совет -Это **не обязательно**, но это хороший способ **убедиться**, что всё работает как ожидалось, и вы используете именно ту виртуальную среду, которую планировали. +Это **необязательно**, но хороший способ **убедиться**, что все работает как надо и вы используете то виртуальное окружение, которое хотели. /// @@ -192,7 +200,7 @@ $ which python
-Если показывает, что `python` находится в `.venv/bin/python` внутри вашего проекта (в данном случае `awesome-project`), значит, всё сработало. 🎉 +Если путь указывает на бинарный файл `python` в `.venv/bin/python`, внутри вашего проекта (в нашем случае это `awesome-project`), значит все сработало. 🎉 //// @@ -208,7 +216,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
-Если показывает, что `python` находится в `.venv\Scripts\python` внутри вашего проекта (в данном случае `awesome-project`), значит, всё сработало. 🎉 +Если путь указывает на бинарный файл `python` в `.venv\Scripts\python`, внутри вашего проекта (в нашем случае это `awesome-project`), значит все сработало. 🎉 //// @@ -216,21 +224,21 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python /// tip | Совет -Если вы используете `uv`, то будете использовать его для установки пакетов вместо `pip`, поэтому обновлять `pip` не нужно. 😎 +Если вы используете `uv` для установки пакетов, вам не нужно обновлять `pip`. 😎 /// -Если вы используете `pip` для установки пакетов (он по умолчанию поставляется с Python), стоит **обновить** его до последней версии. +Если вы используете `pip` для установки пакетов (он идет по умолчанию вместе с Python), для начала обновите его до последней версии. -Многие экзотические ошибки при установке пакетов решаются просто обновлением `pip`. +Многие экзотические ошибки при установке пакетов решаются простым обновлением `pip`. /// tip | Совет -Обычно это делается **один раз**, сразу после создания виртуальной среды. +Обычно это делается **один раз**, сразу после создания виртуального окружения. /// -Убедитесь, что виртуальная среда активирована (используя команду выше), и затем выполните: +Убедитесь, что виртуальное окружение активно (с помощью вышеуказанной команды), и затем запустите:
@@ -244,17 +252,17 @@ $ python -m pip install --upgrade pip ## Добавление `.gitignore` -Если вы используете **Git** (а вы должны), добавьте файл `.gitignore`, чтобы исключить всё содержимое вашей папки `.venv` из Git. +Если вы используете **Git** (и вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить всё из директории `.venv` из Git. /// tip | Совет -Если вы использовали `uv` для создания виртуальной среды, это уже сделано за вас, можете пропустить этот шаг. 😎 +Если вы использовали `uv` для создания виртуального окружения, оно уже это сделало за вас, вы можете пропустить этот шаг. 😎 /// /// tip | Совет -Это делается **один раз**, сразу после создания виртуальной среды. +Сделайте это **один раз**, сразу после создания виртуального окружения. /// @@ -266,13 +274,13 @@ $ echo "*" > .venv/.gitignore
-/// details | Что делает эта команда? +/// details | Что значит эта команда -* `echo "*"`: выведет текст `*` в терминал (следующий этап слегка изменит это) -* `>`: всё, что выводится в терминал командой слева от `>`, не выводится, а записывается в файл справа от `>` -* `.gitignore`: имя файла, в который следует записать текст +* `echo "*"`: "выведет" текст `*` в терминал (следующая часть немного это изменит) +* `>`: всё, что печатается командой слева от `>`, не должно быть выведено, а записано в файл справа от `>` +* `.gitignore`: имя файла, в который должен быть записан текст -И `*` для Git означает "всё". Таким образом, он будет игнорировать всё содержимое директории `.venv`. +А `*` для Git означает "всё". То есть будут проигнорированы все содержимое директории `.venv`. Эта команда создаст файл `.gitignore` с содержимым: @@ -284,23 +292,23 @@ $ echo "*" > .venv/.gitignore ## Установка пакетов -После активации виртуальной среды вы можете устанавливать в неё пакеты. +После активации окружения вы можете устанавливать в него пакеты. /// tip | Совет -Делайте это **один раз** во время установки или обновления пакетов, необходимых вашему проекту. +Сделайте это **один раз** при установке или обновлении пакетов, нужных вашему проекту. -Если вам нужно обновить версию или добавить новый пакет, вы должны будете **сделать это снова**. +Если вам нужно обновить версию пакета или добавить новый пакет, вам нужно будет **сделать это снова**. /// ### Установка пакетов напрямую -Если вы торопитесь и не хотите объявлять зависимости проекта в файле, вы можете установить их напрямую. +Если вам срочно нужно и вы не хотите использовать файл для объявления зависимостей пакета вашего проекта, вы можете установить их напрямую. /// tip | Совет -Очень желательно объявлять пакеты и их версии, которые ваш проект использует, в отдельном файле (например, `requirements.txt` или `pyproject.toml`). +Очень хорошей идеей будет заносить пакеты и версии, которые нужны вашей программе, в файл (например, `requirements.txt` или `pyproject.toml`). /// @@ -367,7 +375,7 @@ $ uv pip install -r requirements.txt /// details | `requirements.txt` -Файл `requirements.txt` с несколькими пакетами может выглядеть так: +`requirements.txt` со списком некоторых пакетов может выглядеть так: ```requirements.txt fastapi[standard]==0.113.0 @@ -378,7 +386,7 @@ pydantic==2.8.0 ## Запуск программы -После активации виртуальной среды вы можете запустить свою программу, и она будет использовать Python внутри вашей виртуальной среды с установленными там пакетами. +После активации виртуального окружения вы можете запустить свою программу, и она будет использовать Python из вашего виртуального окружения с установленными там пакетами.
@@ -392,7 +400,7 @@ Hello World ## Настройка редактора -Вы, вероятно, будете использовать редактор, убедитесь, что настроили его на использование той же виртуальной среды, которую вы создали (скорее всего, он её автоматически распознает), чтобы вы могли использовать автозавершение и видеть ошибки в коде. +Вероятно, вы будете использовать редактор кода; убедитесь, что вы настроили его для использования того же виртуального окружения, которое вы создали (вероятно, он его автоматически обнаружит), чтобы у вас были автозавершение и подсветка ошибок. Например: @@ -401,13 +409,13 @@ Hello World /// tip | Совет -Обычно это делается **один раз**, когда вы создаете виртуальную среду. +Обычно это делается **один раз**, при создании виртуального окружения. /// -## Деактивация виртуальной среды +## Деактивация виртуального окружения -После завершения работы над проектом вы можете **деактивировать** виртуальную среду. +Когда вы завершите работу над проектом, вы можете **деактивировать** виртуальное окружение.
@@ -417,55 +425,53 @@ $ deactivate
-Таким образом, при запуске `python`, он не будет использовать версию из этой виртуальной среды с установленными там пакетами. +Таким образом, когда вы запускаете `python`, он не будет пытаться запустить его из того виртуального окружения с установленными в нём пакетами. ## Готовность к работе -Теперь вы готовы приступить к работе над своим проектом. - - +Теперь вы готовы начать работу над своим проектом. /// tip | Совет -Хотите понять всё, что написано выше? +Хотите понять, что означает все вышеперечисленное? Продолжайте чтение. 👇🤓 /// -## Зачем виртуальные среды +## Зачем использовать виртуальные окружения Для работы с FastAPI вам нужно установить Python. -После этого вам потребуется установить 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`, например, с помощью:
@@ -475,7 +481,7 @@ $ pip install "harry==1"
-И в итоге у вас установлена `harry` версии `1` в глобальной среде Python. +И тогда у вас будет установлена версия `harry` `1` в вашем глобальном Python. ```mermaid flowchart LR @@ -487,7 +493,7 @@ flowchart LR end ``` -Но затем, если вы хотите запустить `prisoner-of-azkaban`, вы должны удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`). +Но если вы хотите запустить `prisoner-of-azkaban`, вам нужно будет удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`).
@@ -497,9 +503,9 @@ $ pip install "harry==3"
-И вы получили `harry` версии `3`, установленный в вашей глобальной среде Python. +И затем у вас будет установлена версия `harry` `3` в вашем глобальном Python. -И если вы попробуете снова запустить `philosophers-stone`, то есть вероятность, что он **не будет работать**, так как зависит от `harry` версии `1`. +И если вы снова попытаетесь запустить `philosophers-stone`, есть вероятность, что он **не будет работать**, потому что ему нужен `harry` версии `1`. ```mermaid flowchart LR @@ -518,47 +524,47 @@ flowchart LR /// tip | Совет -В Python-пакетах обычно стараются изо всех сил **избегать критических изменений** в **новых версиях**, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, работает ли всё правильно. +В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новых версиях, но лучше перестраховаться и намеренно устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно. /// -Теперь представьте, что это происходит с **многими** другим пакеты, от которых зависят все ваши **проекты**. С этим очень сложно справиться. И вы, вероятно, в конечном итоге запустите некоторые проекты с некоторыми **несовместимыми версиями** пакетов и не будете знать, почему что-то не работает. +Теперь представьте это с **множеством** других **пакетов**, от которых зависят все ваши **проекты**. Это очень сложно управляемо. И, вероятно, вы будете запускать некоторые проекты с некоторыми **несовместимыми версиями** пакетов и не будете знать, почему что-то не работает. -Кроме того, в зависимости от вашей операционной системы (например, Linux, Windows, macOS), она могла поставляться с уже установленным Python. И в этом случае она вероятно имела некоторые пакеты, предварительно установленные с определёнными версиями, **необходимыми вашей системой**. Если вы устанавливаете пакеты в глобальную среду Python, вы можете в итоге **сломать** некоторые программы, которые были полностью частью вашей операционной системы. +Кроме того, в зависимости от вашей операционной системы (например, Linux, Windows, macOS), она могла быть поставлена с уже установленным Python. И в этом случае, вероятно, были предустановлены некоторые пакеты с определёнными версиями, **нужными вашей системе**. Если вы устанавливаете пакеты в глобальной среде Python, вы можете **поломать** некоторые из программ, которые поставляются с вашей операционной системой. ## Где устанавливаются пакеты -Когда вы устанавливаете Python, это создаёт на вашем компьютере некоторые каталоги с некоторыми файлами. +Когда вы устанавливаете Python, это создаёт некоторые директории с файлами на вашем компьютере. -Некоторые из этих каталогов являются теми, которые хранят все установленные вами пакеты. +Некоторые из этих директорий предназначены для хранения всех устанавливаемых вами пакетов. Когда вы запускаете:
```console -// Не запускайте это сейчас, это лишь пример 🤓 +// Не запускайте это сейчас, это просто пример 🤓 $ pip install "fastapi[standard]" ---> 100% ```
-Это загрузит сжатый файл с кодом FastAPI, обычно с PyPI. +Это скачается как сжатый файл с кодом FastAPI, обычно из PyPI. -Он также **загрузит** файлы для других пакетов, от которых зависит FastAPI. +Он также **скачает** файлы для других пакетов, от которых зависит FastAPI. Затем он **извлечёт** все эти файлы и поместит их в директорию на вашем компьютере. -По умолчанию, он сохранит загруженные и извлечённые файлы в директории, которая идёт в комплекте с вашей установкой Python, то есть в **глобальной среде**. +По умолчанию, он разместит те загруженные и извлечённые файлы в директории, которая идёт с вашей установкой Python, это ваш **глобальный Python**. -## Что такое виртуальные среды +## Что такое виртуальные окружения? -Решением проблем использования всех пакетов в глобальной среде является использование **виртуальной среды для каждого проекта**, над которым вы работаете. +Решением проблем того, что все пакеты находятся в глобальной среде, является использование **виртуального окружения для каждого проекта**, над которым вы работаете. -Виртуальная среда — это **директория**, очень похожая на глобальную, в которой вы можете устанавливать пакеты для конкретного проекта. +Виртуальное окружение — это **директория**, очень похожая на глобальную, где вы можете устанавливать пакеты для проекта. -Таким образом, каждый проект будет иметь собственную виртуальную среду (`.venv` директории) со своими пакетами. +Таким образом, каждый проект будет иметь своё собственное виртуальное окружение (директорию `.venv`) со своими пакетами. ```mermaid flowchart TB @@ -577,9 +583,9 @@ flowchart TB stone-project ~~~ azkaban-project ``` -## Что означает активация виртуальной среды +## Что означает активация виртуального окружения? -Когда вы активируете виртуальную среду, например, используя: +Когда вы активируете виртуальное окружение, например, с помощью: //// tab | Linux, macOS @@ -607,7 +613,7 @@ $ .venv\Scripts\Activate.ps1 //// tab | Windows Bash -Или, если вы используете Bash для Windows (например, Git Bash): +Или если вы используете Bash для Windows (например, Git Bash):
@@ -619,19 +625,19 @@ $ source .venv/Scripts/activate //// -Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд. +Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для следующих команд. -Одна из этих переменных — это переменная `PATH`. +Одна из этих переменных — переменная `PATH`. /// tip | Совет -Вы можете узнать больше о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}. +Вы можете узнать больше о переменной `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}. /// -Активация виртуальной среды добавляет её путь `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) в переменную окружения `PATH`. +Активация виртуального окружения добавляет путь его директории `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) в переменную окружения `PATH`. -Предположим, что до активации среды переменная `PATH` выглядела так: +Скажем, до активации окружения переменная `PATH` выглядела так: //// tab | Linux, macOS @@ -660,7 +666,7 @@ C:\Windows\System32 //// -После активации виртуальной среды переменная `PATH` будет выглядеть примерно так: +После активации виртуального окружения переменная `PATH` будет выглядеть примерно так: //// tab | Linux, macOS @@ -668,15 +674,15 @@ 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 @@ -692,15 +698,15 @@ 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 @@ -710,13 +716,13 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python //// -Важной деталью является то, что путь к виртуальной среде будет помещён в **начало** переменной `PATH`. Система найдёт его **до** того, как найдёт какой-либо другой Python. Таким образом, при запуске команды `python` будет использоваться Python **из виртуальной среды**, а не любой другой `python` (например, `python` из глобальной среды). +Важная деталь заключается в том, что он помещает путь виртуального окружения в **начало** переменной `PATH`. Система обнаружит это **раньше**, чем любой другой Python. Таким образом, когда вы запускаете `python`, он будет использовать Python **из виртуального окружения**, а не любой другой `python` (например, `python` из глобального окружения). -Активация виртуальной среды также изменяет несколько других вещей, но это одна из самых важных функцией. +Активация виртуального окружения также меняет несколько других вещей, но это одна из самых важных функций. -## Проверка виртуальной среды +## Проверка виртуального окружения -Когда вы проверяете, активна ли виртуальная среда, например, используя: +Когда вы проверяете, активно ли виртуальное окружение, например, с помощью: //// tab | Linux, macOS, Windows Bash @@ -746,33 +752,33 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python //// -Это означает, что программа `python`, которая будет использоваться, это та, что находится **в виртуальной среде**. +Это означает, что программа `python`, которая будет использоваться, — это программа **из виртуального окружения**. Вы используете `which` на Linux и macOS и `Get-Command` на Windows PowerShell. -Команда работает следующим образом: она проходит через переменную окружения `PATH`, проходя **каждый путь в порядке** поиска программы под названием `python`. После того, как она найдёт её, она **отобразит путь** к этой программе. +Работа этой команды заключается в том, что она проверяет переменную окружения `PATH`, проходя по **каждому пути по порядку** в поисках программы под названием `python`. Как только она её находит, она **показывает вам путь** к этой программе. -Самая важная часть заключается в том, что когда вы вызываете `python`, это та самая программа "`python`", которая будет выполнена. +Наиболее важной частью является то, что когда вы вызываете `python`, это тот самый "`python`", который будет запущен. -Таким образом, вы можете убедиться, что находитесь в правильной виртуальной среде. +Таким образом, вы можете убедиться, что находитесь в правильном виртуальном окружении. /// tip | Совет -Легко активировать одну виртуальную среду, получить один Python, а затем **перейти к другому проекту**. +Легко активировать одно виртуальное окружение, а затем **перейти к другому проекту**. -И второй проект **не будет работать**, потому что вы используете **неправильный Python** из виртуальной среды для другого проекта. +И второй проект **не будет работать**, потому что вы используете **неправильный Python**, из виртуального окружения другого проекта. -Полезно иметь возможность проверять, какой `python` используется. 🤓 +Полезно уметь проверять, какой `python` используется. 🤓 /// -## Зачем деактивировать виртуальную среду +## Зачем деактивировать виртуальное окружение? -Например, вы можете работать над проектом `philosophers-stone`, **активируя эту виртуальную среду**, устанавливая пакеты и работая в этой среде. +Например, вы можете работать над проектом `philosophers-stone`, **активировать это виртуальное окружение**, устанавливать пакеты и работать в этой среде. -А затем вы хотите работать над **другим проектом** `prisoner-of-azkaban`. +А затем вы хотите поработать над **другим проектом** `prisoner-of-azkaban`. -Вы переходите к этому проекту: +Вы переходите в этот проект:
@@ -782,7 +788,7 @@ $ cd ~/code/prisoner-of-azkaban
-Если вы не деактивируете виртуальную среду для `philosophers-stone`, то когда вы запускаете `python` в терминале, он попытается использовать Python из `philosophers-stone`. +Если вы не деактивируете виртуальное окружение для `philosophers-stone`, когда вы запускаете `python` в терминале, он попытается использовать Python из `philosophers-stone`.
@@ -799,17 +805,17 @@ Traceback (most recent call last):
-Но если вы деактивируете виртуальную среду и активируете новую для `prisoner-of-askaban`, то когда вы запускаете `python`, он будет использоваться Python из виртуальной среды в проекте `prisoner-of-azkaban`. +Но если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, то, когда вы запускаете `python`, он будет использовать Python из виртуального окружения в `prisoner-of-azkaban`.
```console $ cd ~/code/prisoner-of-azkaban -// Вам не нужно находиться в старой директории для деактивации, вы можете сделать это из любого места, даже после перехода к другому проекту 😎 +// Вам не нужно находиться в старой директории для деактивации, вы можете сделать это, где угодно, даже после перехода к другому проекту 😎 $ deactivate -// Активируйте виртуальную среду в `prisoner-of-azkaban/.venv` 🚀 +// Активируйте виртуальное окружение в prisoner-of-azkaban/.venv 🚀 $ source .venv/bin/activate // Теперь, когда вы запускаете python, он найдёт пакет sirius, установленный в этой виртуальной среде ✨ @@ -822,23 +828,23 @@ $ python main.py ## Альтернативы -Это простое руководство поможет вам начать работу и научит тому, как всё работает **внутри**. +Это простое руководство, чтобы начать работу и показать, как всё **работает изнутри**. -Существуют также **альтернативные** решения для управления виртуальными средами разработки, зависимостями пакетов (требования), проектами. +Существует много **альтернатив** для управления виртуальными окружениями, зависимостями пакетов, проектами. -Когда вы будете готовы и захотите использовать инструмент для **управления всем проектом**, зависимостями пакетов, виртуальными средами и т.д., я бы рекомендовал вам попробовать uv. +Когда вы будете готовы и захотите использовать инструмент для **полного управления проектом**, зависимостями пакетов, виртуальными окружениями и т.д., я бы предложил вам попробовать uv. -`uv` может делать много всего, он может: +`uv` может сделать множество вещей, он может: * **Установить Python** для вас, включая разные версии -* Управлять **виртуальной средой** для ваших проектов +* Управлять **виртуальным окружением** для ваших проектов * Устанавливать **пакеты** -* Управлять зависимостями пакетов **и версиями** для вашего проекта -* Обеспечить наличие **точного** набора пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что ваш проект будет работать в production точно так же, как и на вашем компьютере во время разработки, это называется *locking* -* И многое другое +* Управлять зависимостями пакетов и версиями для вашего проекта +* Гарантировать, что у вас есть **точный** набор пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что вы можете запустить ваш проект в продакшн точно так же, как на вашем компьютере во время разработки, это называется **locking** +* И многие другие вещи ## Заключение -Если вы прочитали и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных средах, чем многие другие разработчики. 🤓 +Если вы прочли и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие разработчики. 🤓 -Знание этих деталей, скорее всего, будет полезно вам в будущем, когда вы будете отлаживать что-то, что кажется сложным, но вы будете знать, **как всё работает внутри**. 😎 +Понимание этих деталей, вероятно, будет полезно в будущем, когда вы будете отлаживать что-то, кажущееся сложным, но вы будете знать, **как всё работает под капотом**. 😎 From 52b8966c6e73d3302da80c3909186dd31d447270 Mon Sep 17 00:00:00 2001 From: Yurii Motov Date: Thu, 31 Jul 2025 17:30:51 +0200 Subject: [PATCH 4/5] Update translations with new prompts 2 --- docs/ru/docs/async.md | 310 +++++++++--------- docs/ru/docs/benchmarks.md | 36 +- docs/ru/docs/deployment/manually.md | 68 ++-- docs/ru/docs/help-fastapi.md | 232 +++++++------ docs/ru/docs/index.md | 178 +++++----- docs/ru/docs/project-generation.md | 28 +- docs/ru/docs/tutorial/body-multiple-params.md | 66 ++-- docs/ru/docs/tutorial/cors.md | 61 ++-- docs/ru/docs/tutorial/extra-models.md | 104 +++--- docs/ru/docs/tutorial/first-steps.md | 154 +++++---- docs/ru/docs/tutorial/handling-errors.md | 24 +- docs/ru/docs/tutorial/index.md | 34 +- docs/ru/docs/tutorial/middleware.md | 62 ++-- .../tutorial/query-params-str-validations.md | 248 +++++++------- docs/ru/docs/tutorial/response-status-code.md | 72 ++-- docs/ru/docs/tutorial/sql-databases.md | 225 ++++++------- docs/ru/docs/virtual-environments.md | 310 +++++++++--------- 17 files changed, 1090 insertions(+), 1122 deletions(-) diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md index 5973e0df7..4146b4dd3 100644 --- a/docs/ru/docs/async.md +++ b/docs/ru/docs/async.md @@ -1,18 +1,18 @@ # Конкурентность и async / await -Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций-обработчиков пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма. +Подробная информация о синтаксисе `async def` для *функций-обработчиков пути*, а также некоторые сведения об асинхронном программировании, конкурентности и параллелизме. -## В спешке? +## Нет времени? -TL;DR: +TL;DR: -Если вы используете сторонние библиотеки, которые требуют вызова с ключевым словом `await`, как, например: +Если вы используете сторонние библиотеки, которые требуют вызова с `await`, например: ```Python results = await some_library() ``` -В этом случае *функции-обработчики пути* необходимо объявлять с использованием синтаксиса `async def`: +Тогда объявите ваши *функции-обработчики пути* с `async def`, как: ```Python hl_lines="2" @app.get('/') @@ -23,13 +23,13 @@ async def read_results(): /// note | Примечание -Вы можете использовать `await` только внутри функций, созданных с помощью `async def`. +`await` можно использовать только внутри функций, созданных с использованием `async def`. /// --- -Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует (с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await` (что относится сейчас к большинству библиотек для работы с базами данных), то объявляйте *функции-обработчики пути* обычным образом с помощью `def`, например: +Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т. д.) и не поддерживает использование `await`, (это в настоящее время относится к большинству библиотек для работы с базами данных), тогда объявляйте ваши *функции-обработчики пути* обычным образом, с `def`, например: ```Python hl_lines="2" @app.get('/') @@ -40,25 +40,25 @@ def results(): --- -Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно, ожидать ответа, используйте `async def`, даже если внутри нет необходимости в `await`. +Если вашему приложению (каким-то образом) не нужно ни с чем взаимодействовать и ждать ответа, используйте `async def`, даже если внутри не нужно использовать `await`. --- -Если вы не знаете, используйте обычный `def`. +Если вы просто не знаете, используйте обычный `def`. --- -**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях-обработчиках пути* и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно. +**Примечание**: Вы можете смешивать `def` и `async def` в ваших *функциях-обработчиках пути* так, как вам нужно, и определять каждую с использованием наилучшего варианта для вас. FastAPI сделает с ними всё, что нужно. -В любом случае, в любой из упомянутых выше ситуаций, FastAPI всё равно будет работать асинхронно и с высокой скоростью. +В любом случае, в любой из описанных выше ситуаций, FastAPI всё равно будет работать асинхронно и будет чрезвычайно быстро. -Но, следуя указанным выше шагам, он сможет оптимизировать производительность. +Но, следуя указанным шагам, можно будет достичь некоторой оптимизации производительности. ## Технические подробности -Современные версии Python поддерживают **"асинхронный код"** с использованием чего-то, называемого **"сопрограммами"**, с синтаксисом **`async` и `await`**. +Современные версии Python поддерживают **"асинхронный код"**, используя что-то под названием **"сопрограммы"**, со **синтаксисом `async` и `await`**. -Давайте рассмотрим эту фразу по частям в следующих разделах: +Давайте разберём эту фразу по частям в следующих разделах: * **Асинхронный код** * **`async` и `await`** @@ -66,269 +66,257 @@ def results(): ## Асинхронный код -Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖, что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝. +Асинхронный код просто означает, что в языке 💬 есть способ указать компьютеру / программе 🤖, что в определённый момент кода, он 🤖 должен будет дождаться, пока *что-то ещё* завершится где-то ещё. Допустим, это *что-то ещё* называется "медленный файл" 📝. -Так что, в это время, компьютер может выполнять какую-то другую работу, пока "медленный файл" 📝 заканчивается. +Итак, в это время компьютер может заниматься чем-то другим, пока "медленный файл" 📝 завершает работу. -Потом компьютер / программа 🤖 будет возвращаться каждый раз, когда у него будет шанс, потому что он снова ждет, или когда он 🤖 закончит всю работу, которую у него была к тому моменту. И он 🤖 проверит, не завершилась ли какая-либо из задач, чтобы выполнить то, что нужно. +Затем компьютер / программа 🤖 возвращается каждый раз, когда у него появляется возможность, потому что он снова что-то ожидает, или вся выполняемая работа на данный момент завершена. Он 🤖 проверяет, не завершена ли какая-нибудь из ожидаемых задач, и выполняет необходимые действия. -Затем он 🤖 берёт первую задачу, которая завершилась (например, наш "медленный файл" 📝) и продолжает выполнение того, что ему надо было сделать. +Далее 🤖 берёт первую завершённую задачу (допустим наш "медленный файл" 📝) и продолжает действия, которые он должен был выполнить с ней. -Этот "ожидать чего-то ещё" обычно относится к операциям I/O, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например: +То "ожидание чего-то ещё", как правило, относится к операциям I/O, которые относительно "медленны" (по сравнению со скоростью процессора и оперативной памяти), например: -* ожидание данных от клиента, отправленных через сеть -* ожидание, когда данные, отправленные программой, будут получены клиентом через сеть -* ожидание, когда содержимое файла на диске будет прочитано системой и передано вашей программе -* ожидание, когда данные, которые ваша программа передала системе, будут записаны на диск +* данные от клиента по сети +* данные, отправленные вашей программой клиенту через сеть +* содержимое файла на диске передано системе и дано вашей программе +* содержимое вашей программы передано системе для записи на диск * удалённая операция API -* ожидание завершения операции с базой данных -* ожидание, когда запрос к базе данных вернёт результаты +* операция с базой данных завершается +* выполнение запроса к базе данных возвращает результаты * и т. д. -Поскольку в основном время тратится на ожидание выполнения операций I/O, их обычно называют операциями, ограниченными скоростью ввода-вывода. +Поскольку в основном время выполнения тратится на ожидание операций I/O, это называют "операциями, ограниченными скоростью ввода-вывода". -Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и, будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу. +Они называются "асинхронными", поскольку компьютеру / программе не нужно быть "синхронизированными" с медленной задачей и сидеть в ожидании момента её завершения, чтобы забрать результаты и продолжить работу. -Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд), пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться, забрать результаты выполнения и начать их обрабатывать. +Вместо этого, в "асинхронной" системе задача, оказавшись завершённой, может немного подождать в очереди (некоторые микросекунды), пока компьютер / программа завершит то, что выполнял, и затем вернуться, чтобы забрать результаты и продолжить работу с ними. -"Синхронное" исполнение (в противовес "асинхронному") также называют "последовательным", потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче, даже если в процессе приходится ждать. +Для "синхронного" (в противоположность "асинхронному") они часто также используют термин "последовательный", потому что компьютер / программа следует всем шагам в последовательности, прежде чем переключиться на другую задачу, даже если эти шаги включают ожидание. ### Конкурентность и бургеры -Эту идею **асинхронного** кода, описанную выше, иногда также называют **"конкурентностью"**. Это отличается от **"параллелизма"**. +Эта концепция **асинхронного** кода, описанного выше, также иногда называется **"конкурентностью"**. Она отличается от **"параллелизма"**. -**Конкурентность** и **параллелизм** оба подразумевают, что "разные вещи происходят более или менее в одно время". +**Конкурентность** и **параллелизм** оба связаны с "разными вещами, происходящими более-менее одновременно". -Но детали между *конкурентностью* и *параллелизмом* достаточно разные. +Но детали между *конкурентностью* и *параллелизмом* весьма различны. -Чтобы увидеть разницу, представьте следующую историю о бургерах: +Чтобы увидеть разницу, представьте следующую историю про бургеры: ### Конкурентные бургеры -Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами. +Вы идёте со своей возлюбленной 😍 в фастфуд, становитесь в очередь, в это время кассир принимает заказы у посетителей перед вами. -Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе. +Когда, наконец, подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔🍔. -Отдаёте деньги 💸. - -Кассир 💁 что-то говорит поварам на кухне 👨‍🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔 (но пока они заняты бургерами предыдущих клиентов). +Кассир говорит кое-что повару на кухне, так что они знают, какие бургеры нужно приготовить (даже если в данный момент они готовят те, что для предыдущих клиентов). -Кассир даёт вам номер вашего заказа. +Вы платите. 💸 - +Кассир дает вам номер вашей очереди. -В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍 (поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨). +Пока вы ожидаете, вы идёте со своей возлюбленной выбрать столик, садитесь и довольно продолжительное время общаетесь (поскольку ваши бургеры самые навороченные, готовятся они не так быстро). -Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время, восхищаясь её великолепием, красотой и умом ✨😍✨. +Сидя за столиком с возлюбленной, вы можете приятно провести время, восхищаясь, как крута, мила и умна ваша возлюбленная ✨😍✨. -Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете, какой номер горит над прилавком, и не подошла ли уже ваша очередь. +Время от времени, разговаривая с вашей возлюбленной, вы проверяете, какой номер горит над прилавком, и не подошла ли уже ваша очередь. -И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик. +И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры и вернуться за столик. -Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨. +Вы с вашей возлюбленной едите бургеры и отлично проводите время. ✨ /// info | Информация -Прекрасные иллюстрации от Ketrina Thompson. 🎨 +Красивые иллюстрации от Кетрины Томпсон. 🎨 /// --- -А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖. +Представьте, что в этой истории вы компьютер / программа 🤖. -В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете. Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного. +Когда вы в очереди, вы просто ждёте своей очереди, не делая ничего особо "производительного". Но очередь движется быстро, потому что кассир только принимает заказы (не готовит их), так что это нормально. -Затем, когда наступает ваша очередь, вы делаете настоящую "продуктивную" работу, обрабатываете меню, решаете, что хотите, узнаёте выбор вашей возлюбленной, оплачиваете, проверяете, что даёте правильную сумму или карту, проверяете, правильно ли с вас взяли оплату, содержится ли в заказе всё, что нужно, и так далее. +Когда приходит ваша очередь, вы делаете фактически "производительную" работу: просматриваете меню, выбираете, что хотите, узнаёте, что хочет ваша возлюбленная, платите, проверяете, что отдали правильную банкноту или карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д. -И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸, поскольку теперь нужно ждать 🕙, когда заказ приготовят. +Но даже если вы пока не получили свои бургеры, ваша работа с кассиром "на паузе" ⏸, потому что вам нужно ждать, пока они будут готовы. -Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень "продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍. +Но, отойдя с номерком от прилавка, вы садитесь за столик и можете переключить внимание 🔀 на свою возлюбленную и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень "производительны" 🤓, мило болтаете вдвоём и всё такое 😍. -Кассир 💁 говорит "я закончил делать бургеры" через показ номера вашего заказа на табло, но вы не вскакиваете, как сумасшедший, когда отображаемый номер меняется на номер вашей очереди. Вы знаете, что никто не украдёт у вас бургеры, потому что у вас есть номер вашего заказа, а у других — свои. +Кассир 🏽 говорит "Я закончил с приготовлением бургеров" выставив номер вашей очереди на дисплей прилавка, но вы не прыгаете как безумный только увидев, как номер на дисплее поменялся на ваш. Вы уверены, что ваши бургеры никто не утащит, ведь у вас свой номерок, а у других свой. -Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓) и мило улыбнувшись, скажете, что идёте забирать заказ ⏸. +Таким образом, вы ждёте, пока история вашей возлюбленной не будет рассказана (завершена текущая работа ⏯ / задача 🤓), мило улыбаетесь и говорите, что идёте забирать заказ. -И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹. В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹. +Тогда вы идёте к прилавку 🔀, чтобы закончить начальную задачу ⏯, берете бургеры, и говорите спасибо, забираете их к столу. На этом заканчивается этап / задача взаимодействия с прилавком ⏹. Это в свою очередь, создаёт новую задачу "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹. ### Параллельные бургеры -Теперь представим, что это не "Конкурентные бургеры", а "Параллельные бургеры". +Теперь представьте, что это не "Конкурентные бургеры", а "Параллельные бургеры". -Вы идёте с вашей возлюбленной попробовать параллельный фастфуд. +Вы идёте со своей возлюбленной за параллельным фастфудом. -Вы становитесь в очередь, пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами. +Вы становитесь в очередь, в то время как несколько (скажем 8) кассиров, которые одновременно являются поварами, принимают заказы у клиентов перед вами. - - -При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ. +Каждый перед вами клиент ждёт, когда прилавок будет готов отпускать их бургеры, прежде чем отойти от прилавка потому что каждый из 8 кассиров идёт и сразу готовит бургер, перед тем как принять следующий заказ. -Затем, наконец, наступает ваша очередь, вы заказываете 2 очень вкусных бургера для вашей возлюбленной и вас. - -Ни о чём не жалея, расплачиваетесь 💸. +Наконец подходит ваша очередь, вы заказываете 2 очень навороченные бургера для вашей возлюбленной и себя. - +Вы платите 💸. Кассир идёт на кухню. -Вы ждёте, стоя перед прилавком 🕙, чтобы никто не забрал ваши бургеры перед вами, так как номеров заказа нет. - - +Вы ждёте, стоя перед прилавком 🕙, чтобы никто не забрал ваши бургеры, прежде чем вы это сделаете, так как нет никаких порядковых номеров. -Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь, у вас не получается уделять должного внимание своей даме сердца 😞. +Так как вы и ваша возлюбленная заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они прибудут, вы не можете уделить внимание своей возлюбленной. 😞 -Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки, когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой. +Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Вам нужно ждать 🕙 и быть в точности в тот момент, когда кассир/повар👨‍🍳 приготовит бургеры и вручит их вам, иначе кто-то другой может забрать их. -Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой. +Тогда ваш кассир/повар👨‍🍳, наконец-то возвращается с вашими бургерами, после долгого времени ожидания 🕙 там перед прилавком. -Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик. +Вы берете ваши бургеры и идёте за столик вместе со своей возлюбленной. -Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹. +Вы просто едите их, и всё. ⏹ -Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞. +Разговоров и флирта было немного, поскольку большую часть времени пришлось провести у прилавка. 😞 /// info | Информация -Прекрасные иллюстрации от Ketrina Thompson. 🎨 +Красивые иллюстрации от Кетрины Томпсон. 🎨 /// --- -В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍), на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе". +В этой истории о параллельных бургерах вы компьютер / программа 🤖 с двумя "процессорами" (вы и ваша возлюбленная 😍), оба ждут 🕙 и уделяют все своё внимание ⏯, чтобы стоять "на кассе" долгое время. -В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳. +Фастфуд имеет 8 "процессоров" (кассиров/поваров). В то время как в магазине конкурентных бургеров, возможно, их было всего 2 (один кассир и один повар). -Но всё же, окончательный опыт не самый лучший. 😞 +Но все равно итоговый опыт не из лучших. 😞 --- -Это была бы параллельная аналогичная история для бургеров. 🍔 - -Для более "реального" примера этого, представьте банк. - -До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинная очередь 🕙🕙🕙🕙🕙🕙🕙🕙. +Это была бы параллельная история для бургеров. 🍔 -Все кассиры занимались каждым клиентом один за другим 👨‍💼⏯. +Для более "реалистичного" примера этого представьте себе банк. -И вам долгое время приходилось ждать 🕙 в очереди, иначе потеряете свою очередь. +До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙. -Скорее всего, вам бы не захотелось брать вашу возлюбленную 😍 с собой для быстрого похода в банк 🏦. +Кассиры выполняют всю работу для клиента один за другим 👨‍💼⏯. -### Заключение о бургерах +А вам приходится долго стоять в очереди 🕙 или вы пропустите свою очередь. -В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙, поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯. +Вы вряд ли хотели бы взять свою возлюбленную 😍 в банк 🏦 оплачивать налоги. -И это и есть случай для большинства веб-приложений. +### Выводы о бургерах -Много, много пользователей, но ваш сервер ожидает 🕙, чтобы они отправили свои запросы через своё не очень хорошее соединение. +В этой истории с "фастфудом и бургером с вашей возлюбленной", так как много времени тратится на ожидание 🕙, имеет смысл иметь конкурентную систему ⏸🔀⏯. -И потом снова ждёт 🕙, чтобы ответы вернулись. +Это случай для большинства веб-приложений. -Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени. +Много-много пользователей, но ваш сервер ждёт 🕙 их не самого лучшего соединения, чтобы отправить их запросы. -Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API. +И ждёт снова 🕙, пока их ответы вернутся. -Большинство популярных фреймворков (включая Flask и Django) создавались до появления в Python новых возможностей асинхронного программирования. Поэтому их можно разворачивать с поддержкой параллельного исполнения или асинхронного программирования старого типа, которое не настолько эффективно. +Это "ожидание" 🕙 измеряется в микросекундах, но всё равно, складывая, это в итоге много времени ожидания. -При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером (ASGI) была разработана командой Django для внедрения поддержки веб-сокетов. +Вот почему так важно использовать асинхронный код для веб-API. -Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный), и в этом преимущество Go как языка программирования. +Такая асинхронность сделала NodeJS популярным (несмотря на то, что NodeJS не параллелен) и в этом сила Go как языка программирования. И это тот же уровень производительности, который вы получаете с **FastAPI**. -Поскольку можно использовать преимущества параллелизма и асинхронности вместе, вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков и на уровне с Go, который является компилируемым языком близким к C (всё благодаря Starlette). +И, поскольку вы можете использовать параллелизм и асинхронность вместе, вы достигнете большей производительности, чем у большинства протестированных фреймворков NodeJS и на уровне Go, который является компилируемым языком ближе к C (всё благодаря Starlette). -### Конкуренция лучше параллелизма? +### Получается, конкурентность лучше параллелизма? -Нет! Это не мораль истории. +Нет. Это не мораль истории. -Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание. Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях. +Конкурентность — это не то же самое, что параллелизм. Она лучше в **конкретных** сценариях, где много времени тратится на ожидание. Именно поэтому конкурентность часто лучше параллелизма при разработке веб-приложений. Но не всегда. -Так что, чтобы уравновесить это, представьте себе следующий короткий рассказ: +Чтобы уравновесить это, представьте следующую короткую историю: -> Вам нужно убрать большой, грязный дом. +> Вам нужно убрать в большом грязном доме. *Да, это вся история*. --- -Тут нет ожидания 🕙 нигде, просто много работы по разным местам дома. +Здесь нигде нет нужды ждать 🕙, просто много работы, которая должна быть выполнена в нескольких местах дома. -Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня, но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете. +Вы могли бы устанавливать очереди, как в примере с бургерами, сначала гостиная, потом кухня, но, так как вы нигде не ждете 🕙, просто убираете и убираете, очереди не повлияют ни на что. -И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё, и работы будет сделано тоже одинаковое количество. +Это заняло бы одинаковое количество времени, чтобы завершить, с или без очередей (конкурентности), и вы сделали бы одинаковое количество работы. -Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, и каждый из них (вместе с вами) взялся бы за свой участок дома, с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**. +Но в этом случае, если бы вы могли пригласить 8 бывших кассиров/поваров, а ныне уборщиков, и каждый из них (вместе с вами) мог бы взять участок дома, чтобы убраться, вы могли бы сделать всю работу параллельно, с дополнительной помощью, и закончить намного быстрее. -В этой ситуации каждый из уборщиков (включая вас) будет процессором, выполняющим свою часть работы. +В этом сценарии каждый из уборщиков (включая вас) был бы процессором, выполняющим свою часть работы. -И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание), а работу в компьютере делает ЦП, такие задачи называют ограниченными производительностью процессора. +И поскольку большая часть времени выполнения тратится на настоящую работу (а не на ожидание), и работа в компьютере выполняется ЦП, они называют такие задачи "ограниченными производительностью процессора". --- -Общие примеры операций, связанные с производительностью процессора, — это те, которые требуют сложных математических вычислений. +Операции, ограниченные производительностью процессора, включают в себя операции, требующие сложных математических вычислений. Например: * Обработка **звука** или **изображений**. -* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета, обработка обычно требует проведения расчётов по всем пикселям сразу. -* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов". Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить. -* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание. Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется специальный процессор для создания и / или использования построенных таким образом моделей. +* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения / цвета, и обработка требует выполнения вычислений для всех этих пикселей одновременно. +* **Машинное обучение**: обычно требуются множества умножений "матриц" и "векторов". Представьте большую электронную таблицу с числами и перемножьте их все сразу. +* **Глубинное обучение**: это подполе машинного обучения, поэтому то же самое применяется. Разница лишь в том, что у вас нет единственной электронной таблицы чисел для умножения, а есть их большое множество, и во многих случаях используется специальный процессор для создания и / atau использования таких моделей. -### Конкурентность + параллелизм: Веб + Машинное обучение +### Конкурентность + Параллелизм: Веб + Машинное обучение -**FastAPI** предоставляет возможности конкуретного программирования, которое очень распространено в веб-разработке (именно этим славится NodeJS). +С **FastAPI** вы можете использовать возможности конкуретного программирования, что очень распространено для веб-разработки (именно это привлекательно в NodeJS). -Кроме того, вы сможете использовать все преимущества параллелизма и многопроцессорности (когда несколько процессов работают параллельно), если рабочая нагрузка предполагает **ограничение по процессору**, как, например, в системах машинного обучения. +Тем не менее, вы можете также использовать преимущества параллелизма и многопроцессорности (несколько процессов, работающих параллельно) для рабочих нагрузок, ограниченных по процессору, таких как в Машинное обучение. -Необходимо также отметить, что Python является главным языком в области **дата-сайенс** (наука о данных), машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI отличным вариантом (среди многих других) для разработки веб-API и приложений в области дата-сайенс / машинного обучения. +Это, плюс простой факт, что Python является главным языком в области науки о данных, Машинного и, особенно, Глубинного обучения, делает FastAPI отличным выбором для создания веб-API и приложений для науки о данных и / atau машинного обучения (среди многих других). -Как добиться такого параллелизма в продакшне описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}. +Чтобы узнать, как добиться такого параллелизма в производственной эксплуатации, смотрите раздел [Развертывание](deployment/index.md){.internal-link target=_blank}. ## `async` и `await` -Современные версии Python реализуют асинхронное программирование интуитивно просто. Это похоже на обычный "последовательный" код с автоматизированным ожиданием в нужных моментах. +Современные версии Python предлагают очень интуитивный способ определения асинхронного кода. Это делает его похожим на обычный "последовательный" код и обеспечивает выполнение "ожиданий" для вас в нужные моменты. -При необходимости ожидания результата, если операция поддерживает современные возможности Python, код может быть написан следующим образом: +Когда существует операция, которая требует ожидания перед возвратом результатов и которая поддерживает эти новые функции Python, вы может записать её как: ```Python burgers = await get_burgers(2) ``` -Ключевое здесь — `await`. Оно сообщает Python, что необходимо дождаться ⏸ выполнения `get_burgers(2)` 🕙 прежде чем сохранять результат в `burgers`. Python понимает, что может переключиться на выполнение других задач 🔀 ⏯ (например, получение следующего запроса). +Ключевой момент здесь - `await`. Он говорит интерпретатору Python, что нужно дождаться ⏸ выполнения `get_burgers(2)`, прежде чем сохранить результаты в `burgers`. С этим Python будет знать, что он может заняться чем-то другим 🔀 ⏯, пока ждет (например, принять другой запрос). -Для работы `await`, оно должно находиться внутри функции, поддерживающей асинхронность. Это достигается объявлением с `async def`: +Чтобы `await` сработал, оно должно находиться внутри функции, которая поддерживает эту асинхронность. Для этого просто объявите её с `async def`: ```Python hl_lines="1" async def get_burgers(number: int): - # Выполняем некоторые асинхронные действия, чтобы создать бургеры + # Готовим бургеры по специальному асинхронному рецепту return burgers ``` @@ -337,22 +325,22 @@ async def get_burgers(number: int): ```Python hl_lines="2" # Это не асинхронный код def get_sequential_burgers(number: int): - # Выполняем последовательные действия, чтобы создать бургеры + # Готовим бургеры последовательно по шагам return burgers ``` -`async def` указывает интерпретатору на наличие ожидания `await` в функции, с возможностью "паузы" ⏸ и переключения на другие задачи 🔀 до возврата в исходное место. +Объявляя `async def`, интерпретатор Python знает, что внутри этой функции нужно быть внимательным к выражениям `await`, и что он может "поставить на паузу" ⏸ выполнение этой функции и выполнить что-то ещё 🔀 прежде, чем вернуться. -Если требуется вызвать `async def` функцию, нужно "ожидать" её. Поэтому такое не сработает: +Когда вы хотите вызвать функцию с `async def`, вам нужно "ожидать" её с помощью `await`. Таким образом, это не сработает: ```Python -# Это не сработает, потому что get_burgers была определена с использованием: async def +# Это не сработает, потому что get_burgers была объявлена с: async def burgers = get_burgers(2) ``` --- -Так что, если вы используете библиотеку, которая требует вызова с `await`, создавайте *функции-обработчики пути* с использованием `async def`, например: +Так что, если вы используете библиотеку, которая говорит вам, что можно вызвать её с помощью `await`, вам нужно создать *функции-обработчики пути*, которые используют её с `async def`, как в: ```Python hl_lines="2-3" @app.get('/burgers') @@ -361,96 +349,96 @@ async def read_burgers(): return burgers ``` -### Более технические подробности +### Технические подробности -Вы могли заметить, что `await` может применяться только в функциях, объявленных с использованием `async def`. +Вы могли заметить, что `await` можно использовать только внутри функций, определённых с помощью `async def`. -Но выполнение такой функции необходимо "ожидать" через `await`. Это означает, что её можно вызвать только из другой функции, также объявленной с `async def`. +Но одновременно функции, определённые с `async def`, должны быть "ожидание" с помощью `await`. Так что функции с `async def` можно вызывать только внутри функций, которые тоже определены с `async def`. -Итак, как же появилась первая *курица*? В смысле... как нам вызвать первую асинхронную функцию? +Так как же тогда появилась первая курица? То есть... как вызвать первую асинхронную функцию? -При работе с **FastAPI** не надо думать об этом, потому что "первой" функцией будет ваша *функция-обработчик пути*, и FastAPI будет знать, что делать. +Если вы работаете с **FastAPI**, то не нужно беспокоиться об этом, потому что эта "первая" функция будет вашей *и функции-обработчиком пути*, и FastAPI знает, как сделать всё правильно. -Если хотите использовать `async` / `await` без FastAPI, у вас также есть такая возможность. +Тем не менее, если вы захотите использовать `async` / `await` без FastAPI, вы также можете это сделать. ### Пишите свой асинхронный код -Starlette (и **FastAPI**) основаны на AnyIO, что делает их совместимыми как со стандартной библиотекой asyncio в Python, так и с Trio. +Starlette и **FastAPI** основаны на AnyIO, что делает их совместимыми как со стандартной библиотекой Python's asyncio, так и с Trio. -В частности, вы можете напрямую использовать AnyIO для сложных случаев использования конкурентности, требующих более сложных паттернов в вашем коде. +В частности, вы можете использовать AnyIO непосредственно для ваших расширенных вариантов использования конкурентности, которые требуют более сложных шаблонов в вашем коде. -Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью AnyIO, чтобы они были максимально совместимыми и получали его преимущества (например *структурная конкурентность*). +И даже если вы не использовали FastAPI, вы также можете писать свои асинхронные приложения с использованием AnyIO для обеспечения их высокой совместимости и получения его преимуществ (например, *структурированной конкурентности*). -Я создал другую библиотеку поверх AnyIO, как тонкий слой, чтобы немного улучшить аннотации типов и получить лучшее **автозавершение**, **встроенные ошибки** и т. д. У неё также есть дружелюбное введение и учебник, которые помогут вам **понять** и писать **свой асинхронный код**: Asyncer. Это будет особенно полезно, если вам нужно **комбинировать асинхронный код с обычным** (блокирующим/синхронным) кодом. +Я создал ещё одну библиотеку на базе AnyIO, как тонкий слой сверху, чтобы немного улучшить аннотации типов и получить лучшее **автозавершение кода**, **встроенные ошибки** и т. д. У неё также есть дружественное введение и руководство, чтобы помочь вам **понять** и написать **свой асинхронный код**: Asyncer. Она будет особенно полезна, если вам нужно **объединить асинхронный код с обычным** (блокирующимся/синхронным) кодом. -### Другие формы асинхронного кода +### Другие формы асинхронного программирования Этот стиль использования `async` и `await` относительно новый в языке. -Но он значительно облегчает работу с асинхронным кодом. +Но он сильно облегчает работу с асинхронным кодом. -Очень похожий синтаксис недавно был включён в современные версии JavaScript (в браузере и NodeJS). +Точно такой же синтаксис (или почти идентичный) недавно был включён в современные версии JavaScript (в браузере и NodeJS). -До этого поддержка асинхронного кода была реализована намного сложнее и труднее воспринималась. +Но до этого управление асинхронным кодом было гораздо более сложным. -В предыдущих версиях Python для этого использовались потоки или Gevent. Но такой код сложнее для понимания, отладки и размышлений. +В предыдущих версиях Python вы могли использовать потоки или Gevent. Но код при этом становился намного сложнее для понимания, отладки и мышления. -В предыдущих версиях NodeJS/JavaScript использовали "обратные вызовы", что приводило к аду обратных вызовов. +В предыдущих версиях NodeJS/Browser JavaScript вы могли использовать "обратные вызовы". Что приводило к callback hell. ## Сопрограммы -**Корутина** — это крутое словечко для именования той сущности, которая возвращается функцией `async def`. Python знает, что это что-то наподобие функции, что её можно запустить и она закончится в какой-то момент, но что её выполнение может быть остановлено ⏸ внутренне с помощью `await`. +**Сопрограмма** - это просто высокопарный термин для обозначения той вещи, которую функция `async def` возвращает. Интерпретатор Python знает, что это нечто вроде функции, что она может быть запущена и завершена в какой-то момент, но она также может быть поставлена на паузу ⏸, даже когда внутри неё есть `await`. -Вся функциональность асинхронного программирования с использованием `async` и `await` обобщается под термином "корутины". Они схожи с ключевой особенностью Go — "горутинами". +Но вся эта функциональность использования асинхронного кода с `async` и `await` во многих случаях обобщается как использование "сопрограмм". Это сопоставимо с ключевой отличительной особенностью языка Go, "горутины". ## Заключение -Давайте увидим ту же фразу сверху: +Давайте ещё раз вспомним ту фразу изначально: -> Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**. +> Современные версии Python поддерживают **"асинхронный код"**, используя что-то под названием **"сопрограммы"** с **синтаксисом `async` и `await`**. -Теперь это должно звучать более понятно. ✨ +Теперь это должно звучать понятнее. ✨ -На этом основана работа FastAPI (посредством Starlette), и именно это обеспечивает его высокую производительность. +Именно это в основном работает в FastAPI (через Starlette) и придаёт ему такую впечатляющую производительность. ## Очень технические подробности /// warning | Предупреждение -Этот раздел можно пропустить. +Вы, вероятно, можете пропустить это. -Здесь приводятся очень технические подробности устройства **FastAPI** внутри. +Это очень технические детали внутреннего устройства **FastAPI**. -Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.) и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`, читайте дальше. +Если у вас действительно много технических знаний (сопрограммы, потоки, блокировка и т. д.) и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычного `def`, читайте дальше. /// ### Функции-обработчики пути -Когда вы объявляете *функцию-обработчик пути* обычным образом с ключевым словом `def` вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем пуле потоков, а не напрямую (это бы заблокировало сервер). +Когда вы объявляете *функцию-обработчик пути* стандартным способом с `def` вместо `async def`, она выполняется в внешнем пуле потоков, который затем ожидается, а не вызывается напрямую (это бы заблокировало сервер). -Если ранее вы использовали другой асинхронный фреймворк, который работает иначе, и привыкли объявлять простые вычислительные *функции* через `def` ради незначительного прироста скорости (порядка 100 наносекунд), обратите внимание, что с **FastAPI** эффект будет обратный. В таких случаях лучше использовать `async def`, если только *функция-обработчик пути* не выполняет код, приводящий к блокировке I/O. +Если вы пришли из другого асинхронного фреймворка, который не работает так, как описано выше, и вы привыкли определять простые вычислительные *функции* с помощью обычного `def` ради микроскопического прироста производительности (порядка 100 наносекунд), обратите внимание, что в **FastAPI** эффект будет совершенно противоположный. В этих случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, который выполняет блокирующий I/O. -Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](index.md#performance){.internal-link target=_blank}, чем (или хотя бы на уровне с) ваш предыдущий фреймворк. +Тем не менее, несмотря на это, велика вероятность, что **FastAPI** [будет быстрее](index.md#performance){.internal-link target=_blank} (или по крайней мере сравнимо с) вашим предыдущим фреймворком ### Зависимости -То же самое относится и к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость объявлена с использованием стандартной функции `def`, она будет запущена во внешнем пуле потоков. +То же самое применимо и к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость оформлена как стандартная `def` функция вместо `async def`, она выполняется в внешнем пуле потоков. ### Подзависимости -Вы можете объявить множество ссылающихся друг на друга зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`, другие обычным образом через `def`, и такая схема вполне работоспособна. Функции, объявленные с помощью `def` будут запускаться на внешнем потоке (из пула), а не с помощью `await`. +Вы можете иметь несколько зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} требующих друг друга (в виде параметров определения функции), некоторые из которых могут быть созданы с помощью `async def`, а некоторые с обычным `def`. Они всё равно будут работать корректно, и те, которые созданы со стандартным `def`, будут вызываться на внешнем потоке (из пула), а не будут "ожидать". ### Другие служебные функции -Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы их запускаете. +Любые другие вспомогательные функции, которые вы вызываете напрямую, можно создать с помощью обычного `def` или `async def`, и FastAPI не будет влиять на способ их вызова. -Этим они отличаются от функций, которые FastAPI вызывает самостоятельно: *функции-обработчики пути* и зависимости. +Это контраст с функциями, которые вызываются FastAPI для вас: *функции-обработчики пути* и зависимости. -Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую (как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с помощью `async def`, её вызов должен осуществляться с ожиданием через `await`. +Если ваша служебная функция является обычной функцией с `def`, она будет вызвана напрямую (как вы напишете её в коде), не в пуле потоков, если функция создана с `async def`, тогда вы должны использовать `await`, вызывая её в вашем коде. --- -Теперь, когда у вас есть представление о больших технических подробностях, это может быть полезно, если вы специально их искали. +Ещё раз, эти технические подробности, вероятно, будут полезны, только если вы специально их искали. -В противном случае просто ознакомьтесь с основными принципами в разделе выше: Нет времени?. +В противном случае, ознакомьтесь со сводкой из раздела выше: Нет времени?. diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md index 8ab1d1d3b..bfa0b9a16 100644 --- a/docs/ru/docs/benchmarks.md +++ b/docs/ru/docs/benchmarks.md @@ -1,34 +1,34 @@ # Бенчмарки -Независимые тесты производительности от TechEmpower показывают, что приложения **FastAPI**, работающие под управлением Uvicorn, являются одними из самых быстрых Python-фреймворков, уступая только самим Starlette и Uvicorn (которые используются внутри FastAPI). +Независимые тесты производительности TechEmpower показывают, что приложения на **FastAPI**, работающие под управлением Uvicorn, являются одними из самых быстрых Python-фреймворков, уступая только Starlette и Uvicorn (которые используются внутри FastAPI). -Однако при просмотре бенчмарков и сравнений следует учитывать следующее. +Но при просмотре бенчмарков и сравнений следует иметь в виду следующее. ## Бенчмарки и скорость -Когда вы изучаете бенчмарки, часто можно увидеть сравнение нескольких инструментов разного типа, как если бы они были эквивалентны. +При просмотре бенчмарков часто можно увидеть, что инструменты разных типов сравниваются как эквивалентные. -В частности, можно увидеть, как сравниваются Uvicorn, Starlette и FastAPI (среди многих других инструментов). +В частности, Uvicorn, Starlette и FastAPI зачастую сравниваются вместе (среди множества других инструментов). -Чем проще задача, которую решает инструмент, тем лучше у него производительность. И большинство бенчмарков не проверяют дополнительные функции, предоставляемые инструментом. +Чем проще проблема, решаемая инструментом, тем выше будет его производительность. И большинство бенчмарков не тестируют дополнительные функции, предоставляемые инструментом. -Иерархия инструментов выглядит следующим образом: +Иерархия выглядит так: * **Uvicorn**: ASGI-сервер * **Starlette**: (использует Uvicorn) веб-микрофреймворк - * **FastAPI**: (использует Starlette) API-микрофреймворк с множеством дополнительных функций для создания API, таких как валидация данных и т.д. + * **FastAPI**: (использует Starlette) микрофреймворк для API с несколькими дополнительными функциями для создания API, с валидацией данных и т.д. * **Uvicorn**: - * Имеет наилучшую производительность, так как не содержит многого дополнительного кода, кроме самого сервера. - * Вы не будете писать приложение на Uvicorn напрямую. Это означало бы, что в вашем коде пришлось бы включать, по крайней мере, весь код, предоставляемый Starlette (или **FastAPI**). И если бы вы так сделали, то конечное приложение имело бы те же накладные расходы, что и при использовании фреймворка, минимизирующего код вашего приложения и ваши ошибки. - * Если сравнивать Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и другими серверами приложений. + * Будет иметь наилучшую производительность, так как не имеет большого количества дополнительного кода, кроме самого сервера. + * Вы не будете писать приложение на Uvicorn напрямую. Это означало бы, что ваш код должен включать, как минимум, весь код, предоставляемый Starlette (или **FastAPI**). И если вы так сделали бы, то в конечном итоге ваше приложение имело бы те же накладные расходы, что и при использовании фреймворка, минимизирующего код вашего приложения и ваши ошибки. + * Если вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и другими серверами приложений. * **Starlette**: - * Будет иметь следующую по производительности после Uvicorn. Фактически, Starlette использует Uvicorn для выполнения. Поэтому, вероятно, он может стать "медленнее" Uvicorn, так как выполняет больше кода. - * Однако он предоставляет вам инструменты для создания простых веб-приложений с маршрутизацией, основанной на путях и т.д. - * Если сравнивать Starlette, сравнивайте его с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками). + * Следующей по производительности будет Starlette, после Uvicorn. Фактически, Starlette использует Uvicorn для запуска. Таким образом, она может быть "медленнее" Uvicorn только из-за выполнения большего объема кода. + * Но она предоставляет инструменты для создания простых веб-приложений, с маршрутизацией на основе путей и т.д. + * Если вы сравниваете Starlette, сравнивайте ее с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками). * **FastAPI**: - * Так же как Starlette использует Uvicorn и не может быть быстрее его, **FastAPI** использует Starlette, поэтому не может быть быстрее его. - * FastAPI предоставляет больше возможностей поверх Starlette. Возможностей, которые почти всегда нужны при создании API, таких как валидация данных и сериализация. Используя его, вы получаете автоматическую документацию бесплатно (автоматическая документация даже не добавляет накладных расходов при выполнении приложений, она генерируется при запуске). - * Если бы вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент, такой как Sanic, Flask, Responder и т.д.), вам пришлось бы самостоятельно реализовывать всю валидацию и сериализацию данных. Таким образом, ваше конечное приложение все равно имело бы те же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. - * Таким образом, используя FastAPI, вы экономите время разработки, уменьшаете количество ошибок, количество строк кода и, вероятно, получаете ту же производительность (или лучше), как если бы не использовали его (поскольку вам пришлось бы реализовать все это в своем коде). - * Если вы сравниваете FastAPI, сравнивайте его с фреймворком веб-приложений (или набором инструментов), который предоставляет валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией. + * Так же как Starlette использует Uvicorn и не может быть быстрее его, **FastAPI** использует Starlette, так что он не может быть быстрее нее. + * FastAPI предоставляет больше возможностей на базе Starlette. Возможности, которые, скорее всего, понадобятся вам при создании API, такие как валидация и сериализация данных. И благодаря этому вы получаете автоматическую документацию "бесплатно" (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске). + * Если вы не использовали FastAPI и использовали Starlette напрямую (или другой инструмент, такой как Sanic, Flask, Responder и т.д.), вам пришлось бы самостоятельно реализовать всю валидацию и сериализацию данных. То есть, в итоге, ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объем кода, написанного в приложениях. + * Таким образом, используя FastAPI, вы экономите время разработки, сокращаете количество ошибок, количество строк кода и, вероятно, получите такую же производительность (или лучше), какую получили бы, если бы не использовали его (так как вам пришлось бы реализовать все это в своем коде). + * Если вы сравниваете FastAPI, сравнивайте его с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией. diff --git a/docs/ru/docs/deployment/manually.md b/docs/ru/docs/deployment/manually.md index 55d1fa329..7614694cd 100644 --- a/docs/ru/docs/deployment/manually.md +++ b/docs/ru/docs/deployment/manually.md @@ -1,8 +1,8 @@ -# Ручной запуск сервера +# Запуск сервера вручную ## Используйте команду `fastapi run` -Вкратце, используйте `fastapi run` для запуска вашего приложения FastAPI: +Кратко говоря, используйте `fastapi run` для запуска вашего приложения FastAPI:
@@ -38,45 +38,45 @@ $ fastapi run ASGI. FastAPI — это ASGI веб-фреймворк. +FastAPI использует стандарт для создания веб-фреймворков и серверов на Python под названием ASGI. FastAPI — это веб-фреймворк на основе ASGI. -Основное, что вам нужно для запуска приложения **FastAPI** (или любого другого ASGI приложения) на удалённой серверной машине — это программа сервера ASGI, такая как **Uvicorn**, которая поставляется по умолчанию с командой `fastapi`. +Основное, что вам требуется для запуска приложения **FastAPI** (или любого другого приложения на основе ASGI) на удаленной серверной машине — это программа ASGI-сервера, такая как **Uvicorn**, именно она используется по умолчанию в команде `fastapi`. -Существует ряд альтернатив, включая: +Существует несколько альтернатив, включая: * Uvicorn: высокопроизводительный ASGI-сервер. -* Hypercorn: ASGI-сервер, совместимый с HTTP/2 и Trio, среди прочих функций. +* Hypercorn: ASGI-сервер, поддерживающий HTTP/2 и Trio среди прочих возможностей. * Daphne: ASGI-сервер, созданный для Django Channels. -* Granian: сервер HTTP на Rust для Python приложений. -* NGINX Unit: лёгкая и универсальная среда выполнения веб-приложений. +* Granian: HTTP-сервер на Rust для Python-приложений. +* NGINX Unit: NGINX Unit — легковесная и универсальная среда выполнения веб-приложений. ## Сервер как машина и сервер как программа -Есть небольшой нюанс в терминологии, который стоит помнить. 💡 +Есть небольшая деталь в названиях, о которой стоит помнить. 💡 -Слово "**сервер**" часто используется для обозначения как удалённого/облачного компьютера (физической или виртуальной машины), так и программы, работающей на этой машине (например, Uvicorn). +Слово "**сервер**" обычно используется для обозначения как удаленного/облачного компьютера (физической или виртуальной машины), так и программы, которая на этой машине работает (например, Uvicorn). -Просто держите в уме, что, когда вы видите слово "сервер", это может относиться к одному из этих двух понятий. +Просто имейте в виду, что когда вы видите "сервер", это может относиться к одному из этих двух значений. -Когда говорят о удалённой машине, часто упоминают просто **сервер**, но также могут называть его **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают какой-то тип удалённого компьютера, обычно с операционной системой Linux, на котором вы запускаете программы. +Когда речь идет о удаленной машине, часто используется термин **сервер**, но также можно встретить **машина**, **ВМ** (виртуальная машина), **нода**. Все это обозначает какую-то удаленную машину, обычно под управлением Linux, на которой вы запускаете программы. -## Установка программы сервера +## Установка программного сервера -При установке FastAPI, он поставляется с продакшн-сервером, Uvicorn, и вы можете запустить его с командой `fastapi run`. +При установке FastAPI он поставляется с продакшн-сервером Uvicorn, и его можно запустить с помощью команды `fastapi run`. Но вы также можете установить ASGI-сервер вручную. -Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и затем вы можете установить серверное приложение. +Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем вы можете установить приложение сервера. -Например, чтобы установить Uvicorn: +Например, для установки Uvicorn:
@@ -88,21 +88,21 @@ $ pip install "uvicorn[standard]"
-Аналогичный процесс применим и к любой другой программе ASGI-сервера. +Схожий процесс применим к любым другим программам ASGI-серверов. /// tip | Подсказка -Добавив `standard`, Uvicorn установит и будет использовать некоторые рекомендуемые дополнительные зависимости. +Добавляя `standard`, Uvicorn установит и будет использовать некоторые рекомендованные дополнительные зависимости. -В их числе `uvloop`, высокопроизводительная замена `asyncio`, которая обеспечивает ощутимый прирост скорости обработки запросов с большими объемами данных. +Сюда входит `uvloop`, высокопроизводительная замена для `asyncio`, которая дает значительное ускорение производительности асинхронных программ. -Когда вы устанавливаете FastAPI с чем-то вроде `pip install "fastapi[standard]"`, вы уже получаете `uvicorn[standard]`. +Когда вы устанавливаете FastAPI подобно `pip install "fastapi[standard]"`, вы уже получаете `uvicorn[standard]`. /// ## Запуск программы сервера -Если вы установили ASGI-сервер вручную, вам обычно потребуется указать строку для импорта в специальном формате, чтобы он мог импортировать ваше FastAPI-приложение: +Если вы установили ASGI-сервер вручную, обычно вам нужно передать импортную строку в специальном формате, чтобы он импортировал ваше FastAPI приложение:
@@ -116,10 +116,10 @@ $ uvicorn main:app --host 0.0.0.0 --port 80 /// note | Примечание -Команда `uvicorn main:app` обозначает: +Команда `uvicorn main:app` относится к: -* `main`: файл `main.py` (модуль Python). -* `app`: объект, созданный внутри `main.py` строкой `app = FastAPI()`. +* `main`: файл `main.py` (Python "модуль"). +* `app`: объект, созданный внутри `main.py` с помощью строки `app = FastAPI()`. Это эквивалентно: @@ -129,29 +129,29 @@ from main import app /// -Каждая из альтернатив программ ASGI-сервера будет иметь схожую команду, вы можете узнать больше в их документации. +Каждая из альтернативных программ ASGI-серверов будет иметь аналогичную команду, вы можете узнать больше в их документации. /// warning | Предупреждение Uvicorn и другие серверы поддерживают опцию `--reload`, которая полезна в процессе разработки. -Опция `--reload` потребляет намного больше ресурсов, она менее стабильна и так далее. +Опция `--reload` потребляет гораздо больше ресурсов, более нестабильна и т. д. -Она очень помогает во время **разработки**, но **не рекомендуется** использовать её в **продакшн**. +Она очень помогает во время **разработки**, но **не следует** использовать её в **продакшне**. /// ## Концепции развёртывания -Эти примеры запускают серверные программы (например, Uvicorn), начиная с **одного процесса**, слушающего все IP-адреса (`0.0.0.0`) на определенном порту (например, `80`). +Эти примеры запускают программное обеспечение сервера (например, Uvicorn), начиная **один процесс**, слушающий все IP (`0.0.0.0`) на заранее определенном порту (например, `80`). -Это основная идея. Но вы, вероятно, захотите позаботиться о некоторых дополнительных вещах, таких как: +Это основная идея. Но, вероятно, вам захочется позаботиться о некоторых дополнительных вещах, таких как: * Безопасность - HTTPS -* Запуск при старте системы +* Запуск при старте * Перезапуски * Репликация (количество запущенных процессов) * Память -* Предыдущие шаги перед запуском +* Предварительные действия перед запуском -Я расскажу вам больше о каждой из этих концепций, о том, как их воспринимать, и дам конкретные примеры стратегий для работы с ними в следующих главах. 🚀 +Я расскажу вам больше о каждой из этих концепций, как о них думать и приведу конкретные примеры со стратегиями их решения в следующих главах. 🚀 diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md index 4971d9fe6..82007e2ac 100644 --- a/docs/ru/docs/help-fastapi.md +++ b/docs/ru/docs/help-fastapi.md @@ -1,258 +1,256 @@ # Помочь FastAPI - Получить помощь -Вам нравится **FastAPI**? +Нравится ли вам **FastAPI**? -Хотите помочь FastAPI, другим пользователям и автору? +Хотели бы вы помочь FastAPI, его пользователям и автору? -Или вы хотите получить помощь с **FastAPI**? +Или вам нужна помощь с **FastAPI**? -Существуют очень простые способы помочь (многие из них требуют всего один или два клика). +Есть очень простые способы помочь (несколько из них требуют всего один или два клика). -И также есть несколько способов получить помощь. +Также есть несколько способов получить помощь. ## Подписаться на новостную рассылку -Вы можете подписаться на (редкую) [рассылку **FastAPI и друзья**](newsletter.md){.internal-link target=_blank}, чтобы быть в курсе следующих событий: +Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md){.internal-link target=_blank}, чтобы быть в курсе: -* Новостях о FastAPI и его друзьях 🚀 -* Руководствах 📝 -* Возможностях ✨ -* Изменениях, нарушающих совместимость 🚨 -* Подсказках и хитростях ✅ +* Новостей о FastAPI и его друзьях 🚀 +* Руководств 📝 +* Возможностей ✨ +* Изменений, нарушающих совместимость 🚨 +* Советов и хитростей ✅ ## Подписаться на FastAPI в Twitter -Подписывайтесь на @fastapi в **Twitter**, чтобы получать последние новости о **FastAPI**. 🐦 +Подписаться на @fastapi в **Twitter** для получения наисвежайших новостей о **FastAPI**. 🐦 -## Добавить звезду **FastAPI** на GitHub +## Добавить **FastAPI** звезду на GitHub -Вы можете "поставить звезду" FastAPI на GitHub (нажав на кнопку звезды вверху справа): https://github.com/fastapi/fastapi. ⭐️ +Вы можете добавить FastAPI "звезду" на GitHub (кликнув на кнопку звезды в верхнем правом углу экрана): https://github.com/fastapi/fastapi. ⭐️ -Чем больше звёзд, тем легче другим пользователям найти проект и увидеть, что он уже был полезен многим. +Чем больше звёзд, тем легче другим пользователям найти его и увидеть, что проект уже стал полезным для многих. -## Отслеживать обновления в репозитории на GitHub +## Отслеживать свежие выпуски в репозитории на GitHub -Вы можете "отслеживать" FastAPI на GitHub (нажав на кнопку "watch" вверху справа): https://github.com/fastapi/fastapi. 👀 +Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 Там вы можете выбрать "Releases only". -Таким образом, вы будете получать уведомления (на ваш email) каждый раз, когда будет выходить новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми функциями. +Таким образом вы будете получать уведомления (по электронной почте) каждый раз, когда будет выпускаться новая версия **FastAPI** с исправлениями ошибок и новыми возможностями. ## Связаться с автором -Можно связаться со мной (Себаcтиян Рамирез / `tiangolo`), автором FastAPI. +Можно связаться со мной (Себастьян Рамирез / `tiangolo`), автором FastAPI. Вы можете: * Подписаться на меня на **GitHub**. - * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам. - * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом. + * Посмотреть другие мои open-source проекты, которые могут быть вам полезны. + * Подписавшись на меня, вы сможете видеть, когда я создаю новый проект с открытым исходным кодом. * Подписаться на меня в **Twitter** или в Mastodon. - * Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это). - * Получать уведомления, когда я делаю объявления и представляю новые инструменты. - * Вы также можете подписаться на @fastapi в Twitter (это отдельный аккаунт). + * Поделиться со мной, как вы используете FastAPI (мне это очень интересно). + * Узнавать обо всех моих анонсах и новых выпусках инструментов. + * Вы также можете подписаться на @fastapi в Twitter (это отдельная учетная запись). * Подписаться на меня в **LinkedIn**. - * Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷‍♂). -* Читать, что я пишу (или подписаться на меня) в **Dev.to** или в **Medium**. - * Читать другие идеи, статьи и читать об инструментах созданных мной. - * Подпишитесь на меня, чтобы читать, когда я публикую что-нибудь новое. + * Узнавать обо всех моих анонсах и новых выпусках инструментов (хотя я чаще использую Twitter 🤷‍♂). +* Читайте мои статьи (или подпишитесь на меня) на **Dev.to** или **Medium**. + * Читайте другие идеи, статьи и обзор инструментов, которые я создал. + * Подпишитесь, чтобы увидеть, когда я публикую что-то новое. -## Написать твит о **FastAPI** +## Оставить сообщение в Twitter о **FastAPI** -Напишите твит о **FastAPI**, и позвольте мне и другим узнать, почему он вам нравится. 🎉 +Оставьте сообщение в Twitter о **FastAPI** и дайте мне и другим узнать, почему он вам нравится. 🎉 -Мне нравится слышать о том, как используется **FastAPI**, что вам в нём понравилось, в каком проекте/компании вы его используете и т.п. +Мне очень нравится узнавать о том, как **FastAPI** используется, что вам нравится в нем, на каких проектах/компаниях вы его применяете и т.п. ## Оставить голос за FastAPI * Голосуйте за **FastAPI** в Slant. * Голосуйте за **FastAPI** в AlternativeTo. -* Расскажите, как Вы используете **FastAPI** на StackShare. +* Сообщите, что используете **FastAPI** на StackShare. -## Помочь другим с их вопросами на GitHub +## Помочь другим с вопросами на GitHub -Вы можете помочь другим с их вопросами: +Вы можете попробовать помочь другим с их вопросами на: -* GitHub Discussions -* GitHub Issues +* Обсуждениях на GitHub +* Issues на GitHub -Во многих случаях, весьма вероятно, Вы уже знаете ответ на эти вопросы. 🤓 +Во многих случаях вы можете уже знать ответ на эти вопросы. 🤓 -Если Вы будете много помогать людям с решением их вопросов, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 +Если вы будете много помогать людям с их вопросами, вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 -Просто помните, самое важное: старайтесь быть добрыми. Люди приходят со своими разочарованиями и часто не задают вопросы так, как следовало бы, но старайтесь быть как можно добрее. 🤗 +Только помните, самое важное — старайтесь быть добрыми. Люди приходят со своими разочарованиями и в большинстве случаев не задают вопросы лучшим образом, но старайтесь проявить максимум доброты. 🤗 -Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимным. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге. +Идея сообщества **FastAPI** заключается в доброжелательности и гостеприимстве. В то же время не допускайте издевательств или неуважительного поведения к другим. Мы должны заботиться друг о друге. --- -Как помочь другим с их вопросами (в обсуждениях или issues): +Как помочь другим с вопросами (в обсуждениях или в вопросах): ### Понять вопрос -* Убедитесь, что вы поняли, какова **цель** и заслуга человека, задающего вопрос. +* Удостоверьтесь, что понимаете **цель** и обстоятельства задающего вопрос. -* Затем убедитесь, что вопрос (в большинстве случаев это вопрос) **ясен**. +* Затем удостоверьтесь, что вопрос (в подавляющем большинстве случаев это именно вопрос) для вас **ясен**. -* Во многих случаях вопрос касается выдуманного решения пользователя, но существует **лучшее** решение. Если вы сможете понять основную проблему и контекст лучше, вы сможете предложить альтернативное **решение**. +* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и **лучше**. Если вы поймете проблему и обстоятельства случая, то сможете предложить **альтернативное решение**. -* Если вопрос вам не ясен, попросите больше **деталей**. +* Если вопрос вам непонятен, запросите больше **деталей**. -### Воспроизведите проблему +### Воспроизвести проблему -В большинстве случаев и вопросов что-то связано с **исходным кодом** пользователя. +Для большинства случаев и большинства вопросов существует что-то связанное с **исходным кодом** того, кто задает вопрос. -В большинстве случаев и по большинству вопросов есть что-то связанное с **исходным кодом** вопрошающего. +Во многих случаях они будут копировать только фрагмент кода, но этого недостаточно для **воспроизведения проблемы**. -* Вы можете попросить их предоставить минимальный, воспроизводимый пример, который вы можете **копировать и вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, которое они наблюдают, или чтобы лучше понять их контекст. +* Вы можете попросить предоставить минимальный воспроизводимый пример, который вы можете **скопировать-вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, или лучше понять их использование. -* Если вы чувствуете щедрость, вы можете попробовать **создать пример** самостоятельно, только на основе описания проблемы. Просто помните, что это может занять много времени и, возможно, лучше сначала попросить их прояснить проблему. +* Если вы чувствуете себя слишком щедрым, попытайтесь **создать подобный пример** самостоятельно, основываясь только на описании проблемы. Просто имейте в виду, что это может занять много времени, и, возможно, лучше сначала уточнить проблему. -### Предложите решения +### Предложить решения -* После того, как вы смогли понять вопрос, вы можете предложить возможный **ответ**. +* После того как вы поняли вопрос, вы можете дать возможный **ответ**. -* Во многих случаях лучше понять их **основную проблему или контекст**, так как может быть лучшее решение, чем то, которое они пытаются использовать. +* В большинстве случаев лучше понять их **основную проблему или обстоятельства**, потому что может быть лучший способ ее решения, чем то, что они пытаются сделать. ### Попросить закрыть -### Попросить закрыть вопрос +Если они ответят, высока вероятность, что вам удалось решить проблему, поздравляю, **вы - герой**! 🦸 -Если Вам ответили, высоки шансы, что Вам удалось решить их проблему, поздравляю, **Вы - герой**! 🦸 - -* В таком случае, если вопрос решён, попросите их: - - * В GitHub Discussions: отметить ваш комментарий как **ответ**. - * В GitHub Issues: **закрыть** тикет. +* Если вопрос решен, попросите их: + + * В GitHub Discussions: отметить комментарий как **ответ**. + * В GitHub Issues: **закрыть** issue. ## Отслеживать репозиторий на GitHub -Вы можете "отслеживать" FastAPI на GitHub (нажав на кнопку "watch" вверху справа): https://github.com/fastapi/fastapi. 👀 +Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 -Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления, когда кто-либо создаст новый тикет или вопрос. Вы также можете указать, что хотите получать уведомления только о новых тикетах, обсуждениях или пулл-реквестах и т.д. +Если вы выберете "Watching" вместо "Releases only", то получите уведомления, когда кто-то создаст новый issue или вопрос. Вы также можете указать, что хотите получать уведомления только о новых issues, обсуждениях или пул-реквестах и т.д. -Тогда Вы можете попробовать решить эти вопросы. +Затем вы можете попробовать помочь им решить эти вопросы. -## Задать вопросы +## Задавать вопросы -Вы можете создать новый вопрос в репозитории на GitHub, например: +Вы можете создать новый вопрос в репозитории на GitHub, например, чтобы: -* Задать **вопрос** или попросить помощи в решении **проблемы**. +* Задать **вопрос** или спросить о **проблеме**. * Предложить новую **возможность**. -**Заметка**: если Вы создаёте подобные вопросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉 +**Заметка**: если вы это сделаете, я попрошу вас также помочь другим. 😉 -## Проверять пулл-реквесты +## Проверять пул-реквесты -Вы можете помочь мне проверять пулл-реквесты других участников. +Вы можете помочь мне проверять пул-реквесты от других участников. -Снова повторяю, пожалуйста, старайтесь быть добрыми. 🤗 +И повторюсь, постарайтесь быть добрыми. 🤗 --- -О том, что нужно иметь в виду при проверке пулл-реквестов: +Вот что стоит иметь в виду при проверке пул-реквестов: ### Понять проблему -* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение в GitHub Discussion или ticket. +* Во-первых, убедитесь, что **понимаете проблему**, которую пул-реквест пытается решить. Возможно, это будет сделано через более длинное обсуждение в Discussion или issue на GitHub. -* Также есть вероятность, что пулл-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт. +* Есть также вероятность, что пул-реквест не нужен, так как проблема может быть решена **другим путем**. Тогда вы можете предложить или спросить об этом. -### Не беспокойтесь о стиле +### Не переживайте о стиле -* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах. При слиянии пулл-реквеста с основной веткой, я буду сжимать и настраивать всё вручную. +* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную. * Также не беспокойтесь о правилах стиля, уже есть автоматизированные инструменты, которые это проверяют. -И если всё же потребуются другие правила стиля или согласованность, я попрошу об этом непосредственно, или добавлю нужные изменения сам. +И если все-таки потребуется другой стиль или согласованность, я попрошу об этом напрямую или добавлю сам коммиты с необходимыми изменениями. -### Проверка кода +### Проверить код -* Проверьте и прочтите код, посмотрев, имеет ли он смысл, **запустите его локально** и посмотрите, действительно ли он решает задачу. +* Проверьте и прочитайте код, посмотрите, имеет ли он смысл, **запустите его локально** и посмотрите, решает ли он действительно проблему. -* Затем **прокомментируйте**, что Вы сделали эту проверку, тогда я буду знать, что Вы действительно проверили код. +* Затем оставьте **комментарий**, что вы это сделали, так я узнаю, что вы действительно проверили его. /// info | Информация -К сожалению, я не могу так просто доверять пулл-реквестам, у которых уже есть несколько одобрений. +К сожалению, я не могу просто доверять PR, которые просто получили несколько одобрений. -Бывали случаи, что пулл-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пулл-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅 +Было несколько случаев, когда пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅 -Поэтому действительно важно, чтобы вы прочли и исполнили код, и сообщили мне в комментариях, что вы это сделали. 🤓 +Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что вы проделали эти действия. 🤓 /// -* Если Вы считаете, что пулл-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах. +* Если можно упростить пул-реквест, вы можете попросить об этом, но нет нужды быть слишком дотошным, может существовать много субъективных точек зрения (и у меня своя тоже будет 🙈), так что лучше, если вы сосредоточитесь на фундаментальных вещах. ### Тестирование -* Помогите мне проверить, что у пулл-реквеста есть **тесты**. +* Помогите мне проверить, что у пул-реквеста есть **тесты**. -* Проверьте, что тесты **падали** до пулл-реквеста. 🚨 +* Проверьте, что тесты **падают** до пул-реквеста. 🚨 -* Затем проверьте, что тесты **не падают** после пулл-реквеста. ✅ +* Затем проверьте, что тесты **проходят** после пул-реквеста. ✅ -* Многие пулл-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим. +* Многие пул-реквесты не имеют тестов, вы можете **напомнить** об их добавлении или даже **предложить** какие-либо тесты сами. Это одна из тех вещей, которые отнимают много времени, и вы можете оказать значительную помощь в этом. -* Затем также прокомментируйте, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓 +* Затем добавьте комментарий, что вы испробовали в ходе проверки. Таким образом я буду знать, как вы произвели проверку. 🤓 -## Создать пулл-реквест +## Создать пул-реквест -Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в кодовую базу, предложив пулл-реквесты, например: +Вы можете [внести вклад](contributing.md){.internal-link target=_blank} в исходный код с помощью пул-реквестов, например: -* Исправить опечатку в документации, которую Вы нашли. -* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли, изменив этот файл. - * Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела. -* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык. - * Вы также можете проверять переводы, сделанные другими. +* Исправить опечатку, которую вы нашли в документации. +* Поделиться статьей, видео или подкастом о FastAPI, которые вы создали или нашли, отредактировав этот файл. + * Убедитесь, что вы добавили свою ссылку в начало соответствующего раздела. +* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на ваш язык. + * Вы также можете помочь проверять переводы, сделанные другими. * Предложить новые разделы документации. -* Исправить существующую проблему/баг. +* Исправить существующую проблему/ошибку. * Убедитесь, что добавили тесты. -* Чтобы добавить новую возможность. +* Добавить новую возможность. * Убедитесь, что добавили тесты. - * Убедитесь, что добавили документацию, если это необходимо. + * Убедитесь, что добавили документацию, если она необходима. -## Помогите поддерживать FastAPI +## Помочь поддерживать FastAPI -Помогите мне поддержать **FastAPI**! 🤓 +Помогите мне поддерживать **FastAPI**! 🤓 -Есть много работы, и большую часть из неё **ВЫ** можете сделать. +Предстоит еще много работы, и в большей части из нее **вы** можете помочь. -Основные задачи, которые вы можете сделать прямо сейчас: +Основные задачи, которые вы можете сделать сейчас: -* [Помочь другим с их вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (смотрите вышестоящую секцию). -* [Проверить пул-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите вышестоящую секцию). +* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github) (смотрите выше). +* [Проверять пул-реквесты](#review-pull-requests) (смотрите выше). -Эти две задачи **занимают больше всего времени**. Это основная работа по поддержке FastAPI. +Эти две задачи — те, что чаще всего **занимают время**. Это основная работа по поддержке FastAPI. -Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 +Если вы можете помочь мне с этим, **вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 -## Присоединяйтесь к чату +## Подключиться к чату -Подключайтесь к 👥 чат-серверу в Discord 👥 и общайтесь с другими участниками сообщества FastAPI. +Подключайтесь к 👥 чату на сервере Discord 👥 и общайтесь с другими участниками сообщества FastAPI. /// tip | Подсказка -Для вопросов, задавайте их в GitHub Discussions, там больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. +Для вопросов, задавайте их в GitHub Discussions, там больше шансов получить помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. Используйте чат только для других общих разговоров. /// -### Не используйте чат для вопросов +### Не использовать чаты для вопросов -Помните, что в чатах легче задаются вопросы, которые носят слишком общий характер и на них труднее найти ответы, поэтому вы можете не получить ответы. +Имейте в виду, что так как чаты позволяют более "свободное общение", легко задать вопросы, которые слишком общие и сложнее на них ответить, поэтому вы можете не получить ответов. -В разделе обсуждений на GitHub, шаблон поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу гарантировать те же ответы в чатах. 😅 +На GitHub шаблон поможет вам задать правильный вопрос, чтобы легче было получить хороший ответ или даже решить проблему самостоятельно до того, как вы его зададите. И на GitHub я могу быть уверен, что всегда отвечаю на все, даже если это займет время. Я не могу сделать то же самое в чатах. 😅 -Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только вопросы решаемые на GitHub учитываются в получении титула [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub. +Общение в чатах не так легко ищется, как на GitHub, поэтому вопросы и ответы могут затеряться в разговоре. И только запросы на GitHub учитываются для получения звания [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, поэтому, вероятнее всего, вы получите больше внимания на GitHub. -С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время trouver кого-то, с кем можно поговорить. 😄 +С другой стороны в чатах тысячи пользователей, поэтому вы с большой вероятностью найдете кого-то, с кем можно поговорить, почти в любое время. 😄 -## Спонсировать автора +## Спонсорство для автора -Если ваш **продукт/компания** зависит от или связан с **FastAPI** и вы хотите донести до его пользователей, вы можете спонсировать автора (меня) через GitHub sponsors. В зависимости от уровня, вы можете получать некоторые дополнительные преимущества, такие как значок в документации. 🎁 +Если ваш **продукт/компания** зависят от **FastAPI** или связаны с ним, и вы хотите донести до пользователей, вы можете также спонсировать автора (меня) через GitHub sponsors. В зависимости от уровня поддержки, вы можете получить дополнительные преимущества, такие как знак в документации. 🎁 --- -Благодарствую! 🚀 +Благодарю! 🚀 diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 281f8cf19..c852384b4 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -8,7 +8,7 @@ FastAPI

- Фреймворк FastAPI: высокая производительность, простота освоения, быстрая разработка, готов к использованию в производстве + Готовый к внедрению высокопроизводительный фреймворк, простой в изучении и разработке.

@@ -33,7 +33,7 @@ --- -FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API, использующий Python и стандартные аннотации типов Python. +FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API используя Python, в основе которого лежит стандартная аннотация типов Python. Ключевые особенности: @@ -46,7 +46,7 @@ FastAPI — это современный, быстрый (высокопрои * **Надежность**: Получите готовый к работе код. С автоматической интерактивной документацией. * **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: OpenAPI (ранее известном как Swagger) и JSON Schema. -* оценка на основе тестов внутренней команды разработчиков, создающих продакшн приложения. +* оценка на основе тестов внутренней команды разработчиков, создающих производственные приложения. ## Спонсоры @@ -67,74 +67,68 @@ FastAPI — это современный, быстрый (высокопрои ## Отзывы -"_[...] В последнее время я много использую **FastAPI**. [...] На самом деле, я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._" +"_В последнее время я много где использую **FastAPI**. [...] На самом деле я планирую использовать его для всех **сервисов машинного обучения моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._"

Kabir Khan - Microsoft (ref)
--- -"_Мы приняли библиотеку **FastAPI** для создания сервера **REST**, к которому можно обращаться для получения **прогнозов**. [для Ludwig]_" +"_Мы использовали библиотеку **FastAPI** для создания сервера **REST**, к которому можно делать запросы для получения **прогнозов**. [для Ludwig]_"
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
--- -"_**Netflix** рада объявить о выпуске фреймворка для оркестрации **кризисного управления**: **Dispatch**! [создан с использованием **FastAPI**]_" +"_**Netflix** рада объявить о выпуске опенсорсного фреймворка для оркестровки **антикризисного управления**: **Dispatch**! [создана с помощью **FastAPI**]_"
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
--- -"_Меня невероятно радует **FastAPI**. Это так весело!_" +"_Я в полном восторге от **FastAPI**. Это так весело!_" -
Brian Okken - Python Bytes ведущий подкаста (ref)
+
Brian Okken - Python Bytes podcast host (ref)
--- -"_Честно говоря, то, что вы создали, выглядит очень солидно и отшлифовано. В многих отношениях это то, чем я хотел, чтобы было **Hug** — это действительно вдохновляет, когда кто-то создает такое._" +"_Честно говоря, то, что вы создали, выглядит очень солидно и отполировано. Во многих смыслах я хотел, чтобы **Hug** был именно таким — это действительно вдохновляет, когда кто-то создаёт такое._" -
Timothy Crosley - Hug создатель (ref)
+
Timothy Crosley - Hug creator (ref)
--- -"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания REST API, ознакомьтесь с **FastAPI** [...] Это быстрый, простой в использовании и в изучении фреймворк [...]_" +"_Если вы хотите изучить какой-нибудь **современный фреймворк** для создания REST API, ознакомьтесь с **FastAPI** [...] Он быстрый, лёгкий и простой в изучении [...]_" -"_Мы перешли на **FastAPI** для наших **API** [...] Думаю, он вам понравится [...]_" +"_Мы перешли на **FastAPI** для наших **API** [...] Я думаю, вам тоже понравится [...]_"
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
--- -"_Если кто-то хочет создать продакшн Python API, я бы настоятельно рекомендовал **FastAPI**. Он **прекрасно разработан**, **прост в использовании** и **высокомасштабируем**, он стал **ключевым компонентом** нашей стратегии разработки API-first и управляет множеством автоматизаций и сервисов, таких как наш виртуальный инженер TAC._" +"_Если кто-то хочет построить продакшн Python API, я настоятельно рекомендую **FastAPI**. Он **прекрасно спроектирован**, **прост в использовании** и **высоко масштабируем**, он стал **ключевым компонентом** нашей стратегии разработки API-first и управляет многими автоматизациями и услугами, такими как наш Виртуальный TAC-инженер._"
Deon Pillsbury - Cisco (ref)
--- -"_Если кто-то хочет создать производственный Python API, я бы очень рекомендовал **FastAPI**. Он **замечательно спроектирован**, **прост в использовании** и **очень масштабируем**, он стал **ключевым компонентом** в нашей стратегии разработки API. Благодаря нему автоматизация и сервисы, такие как наш Виртуальный Инженер TAC, стали возможными._" - -
Deon Pillsbury - Cisco (ref)
- ---- - -## **Typer**, FastAPI для CLI +## **Typer**, интерфейс командной строки для FastAPI -Если вы создаете приложение для CLI, используемое в терминале вместо веб API, ознакомьтесь с **Typer**. +Если вы создаете приложение CLI для использования в терминале вместо веб-API, ознакомьтесь с **Typer**. -**Typer** — младший брат FastAPI. Он предназначен быть **FastAPI для CLI**. ⌨️ 🚀 +**Typer** — младший брат FastAPI. И он предназначен для использования в качестве **интерфейса командной строки для FastAPI**. ⌨️ 🚀 -## Требования +## Зависимости -FastAPI опирается на гигантов: +FastAPI стоит на плечах гигантов: -* Starlette для веб-компонентов. -* Pydantic для работы с данными. +* Starlette для части связанной с вебом. +* Pydantic для части связанной с данными. ## Установка -Создайте и активируйте виртуальное окружение, а затем установите FastAPI: +Создайте и активируйте виртуальное окружение, затем установите FastAPI:
@@ -146,13 +140,13 @@ $ pip install "fastapi[standard]"
-**Примечание**: Убедитесь, что вы используете кавычки для `"fastapi[standard]"`, чтобы обеспечить его работу во всех терминалах. +**Примечание**: Убедитесь, что вы взяли в кавычки `"fastapi[standard]"`, чтобы это работало во всех терминалах. ## Пример ### Создание -Создайте файл `main.py` с: +Создайте файл `main.py` со следующим содержимым: ```Python from typing import Union @@ -197,7 +191,7 @@ async def read_item(item_id: int, q: Union[str, None] = None): **Примечание**: -Если вы не знаете, проверьте раздел _"Нет времени?"_ в документации об `async` и `await`. +Если вы не знаете, проверьте раздел _"Торопитесь?"_ в документации об `async` и `await`. @@ -235,9 +229,9 @@ INFO: Application startup complete.
О команде fastapi dev main.py... -Команда `fastapi dev` считывает файл `main.py`, определяет в нем приложение **FastAPI** и запускает сервер с использованием Uvicorn. +Команда `fastapi dev` читает ваш файл `main.py`, обнаруживает приложение **FastAPI** в нем и запускает сервер с использованием Uvicorn. -По умолчанию `fastapi dev` запускает приложение с включенной авто-перезагрузкой для локальной разработки. +По умолчанию `fastapi dev` запускается с включенной авто-перезагрузкой для локальной разработки. Вы можете узнать больше об этом в документации FastAPI CLI. @@ -245,7 +239,7 @@ INFO: Application startup complete. ### Проверка -Откройте ваш браузер на http://127.0.0.1:8000/items/5?q=somequery. +Откройте браузер на http://127.0.0.1:8000/items/5?q=somequery. Вы увидите следующий JSON ответ: @@ -255,10 +249,10 @@ INFO: Application startup complete. Вы уже создали API, который: -* Получает HTTP-запросы в _пути_ `/` и `/items/{item_id}`. -* Оба _пути_ принимают операции `GET` (также известные как HTTP методы). -* _Путь_ `/items/{item_id}` принимает _параметр пути_ `item_id`, который должен быть `int`. -* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`. +* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`. +* И первый и второй _путь_ используют `GET` операции (также известные как HTTP _методы_). +* _путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`. +* _путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`. ### Интерактивная документация по API @@ -276,11 +270,11 @@ INFO: Application startup complete. ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Обновление примера +## Пример обновления -Теперь измените файл `main.py`, чтобы получать тело из `PUT` запроса. +Теперь измените файл `main.py`, чтобы получить тело ответа из `PUT` запроса. -Объявите тело, используя стандартную типизацию Python, благодаря Pydantic. +Объявите тело, используя стандартную типизацию Python, спасибо Pydantic. ```Python hl_lines="4 9-12 25-27" from typing import Union @@ -312,41 +306,41 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -Сервер `fastapi dev` должен автоматически перезагрузиться. +Сервер должен перезагрузиться автоматически. -### Обновление интерактивной документации по API +### Интерактивное обновление документации API -Теперь перейдите на http://127.0.0.1:8000/docs. +Перейдите на http://127.0.0.1:8000/docs. -* Интерактивная документация 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 А теперь перейдите на http://127.0.0.1:8000/redoc. -* Альтернативная документация также отразит новый параметр запроса и тело: +* Альтернативная документация также будет отражать новый параметр и тело запроса: ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### Итоги +### Подведём итоги -Подводя итоги, вы объявляете **один раз** типы параметров, тела и т. д. в качестве параметров функции. +Таким образом, вы объявляете **один раз** типы параметров, тело и т. д. в качестве параметров функции. -Вы делаете это с использованием стандартной современной типизации Python. +Вы делаете это используя стандартную современную типизацию Python. Вам не нужно изучать новый синтаксис, методы или классы конкретной библиотеки и т. д. -Просто стандартный **Python**. +Только стандартный **Python**. Например, для `int`: @@ -360,24 +354,24 @@ item_id: int item: Item ``` -...и с этим единственным объявлением вы получаете: +... и с этим единственным объявлением вы получаете: -* Поддержку редактора, включая: +* Поддержка редактора, в том числе: * Автозавершение. - * Проверку типов. -* Валидацию данных: - * Автоматические и чёткие ошибки, когда данные недействительны. - * Валидацию даже для глубоко вложенных объектов JSON. -* Преобразование входных данных: поступающих из сети в данные и типы Python. Чтение из: + * Проверка типов. +* Валидация данных: + * Автоматические и четкие ошибки, когда данные недействительны. + * Проверка даже для глубоко вложенных объектов JSON. +* Преобразование входных данных: поступающие из сети в объекты Python с соблюдением типов. Чтение из: * JSON. * Параметров пути. * Параметров запроса. * Cookies. - * Заголовков. + * HTTP-заголовков. * Форм. * Файлов. -* Преобразование выходных данных: преобразование данных и типов Python в данные сети (например JSON): - * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т. д.). +* Преобразование выходных данных: преобразование объектов Python в данные передаваемые по сети интернет (такие как JSON): + * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list`, и т.д.). * Объекты `datetime`. * Объекты `UUID`. * Модели баз данных. @@ -390,28 +384,28 @@ item: Item Возвращаясь к предыдущему примеру кода, **FastAPI** будет: -* Проверять, что в пути есть `item_id` для `GET` и `PUT` запросов. -* Проверять, что `item_id` имеет тип `int` для `GET` и `PUT` запросов. - * Если это не так, клиент увидит полезную, чёткую ошибку. +* Проверять наличие `item_id` в пути для запросов `GET` и `PUT`. +* Проверять, что `item_id` имеет тип `int` для запросов `GET` и `PUT`. + * Если это не так, клиент увидит полезную чёткую ошибку. * Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` запросов. * Поскольку параметр `q` объявлен с `= None`, он является необязательным. - * Без `None` он бы был обязательным (как тело в случае с `PUT`). + * Без `None` он был бы необходим (как тело в случае с `PUT`). * Для `PUT` запросов к `/items/{item_id}` читать тело как JSON: - * Проверять, что у него есть обязательное свойство `name`, которое должно быть `str`. - * Проверять, что у него есть обязательное свойство `price`, которое должно быть `float`. - * Проверять, что у него есть необязательное свойство `is_offer`, которое должно быть `bool`, если оно присутствует. - * Всё это также будет работать для глубоко вложенных объектов JSON. + * Проверять, что у него есть обязательный атрибут `name`, который должен быть `str`. + * Проверять, что у него есть обязательный атрибут `price`, который должен быть `float`. + * Проверять, что у него есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует. + * Все это также будет работать для глубоко вложенных объектов JSON. * Преобразовывать из и в JSON автоматически. -* Документировать всё с помощью OpenAPI, что можно использовать: +* Документировать с помощью OpenAPI все, что может быть использовано: * Системы интерактивной документации. - * Автоматические системы генерации клиентского кода для многих языков. -* Предоставлять 2 интерактивных веб-интерфейса документации напрямую. + * Системы автоматической генерации клиентского кода для многих языков. +* Обеспечит 2 интерактивных веб-интерфейса документации напрямую. --- -Мы только немного поверхностно ознакомились, но вы уже поняли, как все это работает. +Мы только немного копнули поверхность, но вы уже поняли, как все это работает. -Попробуйте изменить строку: +Попробуйте изменить строку с помощью: ```Python return {"item_name": item.name, "item_id": item_id} @@ -429,30 +423,30 @@ item: Item ... "item_price": item.price ... ``` -...и посмотрите, как ваш редактор автоматически завершает атрибуты и знает их типы: +... и посмотрите, как ваш редактор будет автоматически заполнять атрибуты и узнавать их типы: ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) Более полный пример с дополнительными функциями см. в Учебное руководство - Руководство пользователя. -**Внимание, спойлер**: учебное руководство - Руководство пользователя включает: +**Осторожно, спойлер**: руководство пользователя включает в себя: * Объявление **параметров** из других мест, таких как: **заголовки**, **cookies**, **поля формы** и **файлы**. * Как установить **ограничительные проверки** такие как `maximum_length` или `regex`. -* Очень мощная и простая в использовании система **Внедрение Зависимостей**. -* Безопасность и аутентификация, включая поддержку **OAuth2** с **токенами JWT** и **HTTP Basic** авторизация. -* Более продвинутые (но столь же простые) методы объявления **глубоко вложенных моделей JSON** (благодаря Pydantic). +* Очень мощная и простая в использовании система **внедрения зависимостей**. +* Безопасность и аутентификация, включая поддержку **OAuth2** с **токенами JWT** и **HTTP Basic** аутентификацию. +* Более продвинутые (но столь же простые) методы объявления **глубоко вложенных моделей JSON** (спасибо Pydantic). * **GraphQL** интеграция с Strawberry и другими библиотеками. -* Много дополнительных функций (благодаря Starlette), как например: - * **WebSockets** - * невероятно простые тесты, основанные на HTTPX и `pytest` +* Множество дополнительных функций (благодаря Starlette), таких как: + * **Веб-сокеты** + * очень простые тесты на основе HTTPX и `pytest` * **CORS** - * **Сессии с использованием Cookie** + * **Сессии с использованием cookie** * ...и многое другое. ## Производительность -Независимые бенчмарки TechEmpower демонстрируют приложения **FastAPI**, работающие под Uvicorn, как один из самых быстрых доступных фреймворков на Python, уступающий только самим Starlette и Uvicorn (используемых внутри FastAPI). (*) +Независимые тесты TechEmpower показывают приложения **FastAPI**, работающие под управлением Uvicorn, как один из самых быстрых доступных фреймворков Python, уступающий только самим Starlette и Uvicorn (используемых внутри FastAPI). (*) Чтобы узнать больше об этом, см. раздел Тесты производительности. @@ -462,7 +456,7 @@ FastAPI зависит от Pydantic и Starlette. ### Зависимости `standard` -Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он включает группу зависимостей `standard`: +Когда вы устанавливаете FastAPI с помощью `pip install "fastapi[standard]"`, он поставляется с группой необязательных зависимостей `standard`: Используется Pydantic: @@ -476,26 +470,26 @@ FastAPI зависит от Pydantic и Starlette. Используется FastAPI: -* uvicorn - для сервера, который загружает и обслуживает ваше приложение. Это включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), необходимые для высокопроизводительного обслуживания. +* uvicorn - для сервера, который загружает и обслуживает ваше приложение. Включает `uvicorn[standard]`, который включает некоторые зависимости (например, `uvloop`), необходимые для высокопроизводительного обслуживания. * `fastapi-cli[standard]` - для предоставления команды `fastapi`. - * Это включает `fastapi-cloud-cli`, который позволяет разворачивать ваше приложение FastAPI в FastAPI Cloud. + * Включает `fastapi-cloud-cli`, который позволяет развернуть ваше приложение FastAPI в FastAPI Cloud. ### Без зависимостей `standard` -Если вы не хотите включать необязательные зависимости `standard`, вы можете установить FastAPI с помощью `pip install fastapi` вместо `pip install "fastapi[standard]"`. +Если вы не хотите включать необязательные зависимости `standard`, вы можете установить с `pip install fastapi` вместо `pip install "fastapi[standard]"`. ### Без `fastapi-cloud-cli` -Если вы хотите установить FastAPI с стандартными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. +Если вы хотите установить FastAPI с обычными зависимостями, но без `fastapi-cloud-cli`, вы можете установить с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. ### Дополнительные необязательные зависимости -Существуют некоторые дополнительные зависимости, которые вы можете захотеть установить. +Есть некоторые дополнительные зависимости, которые вы, возможно, захотите установить. Дополнительные необязательные зависимости Pydantic: * pydantic-settings - для управления настройками. -* pydantic-extra-types - для дополнительных типов, которые могут быть использованы с Pydantic. +* pydantic-extra-types - для дополнительных типов, которые можно использовать с Pydantic. Дополнительные необязательные зависимости FastAPI: diff --git a/docs/ru/docs/project-generation.md b/docs/ru/docs/project-generation.md index ae7218f03..300cdf004 100644 --- a/docs/ru/docs/project-generation.md +++ b/docs/ru/docs/project-generation.md @@ -1,28 +1,28 @@ # Full Stack FastAPI Шаблон -Шаблоны обычно идут с определенной настройкой, но они разработаны гибкими и настраиваемыми. Это позволяет вам модифицировать и адаптировать их в соответствии с требованиями вашего проекта, превращая их в отличную отправную точку. 🏁 +Шаблоны, хотя и содержат определённые настройки, разработаны для гибкости и настраиваемости. Это позволяет вам модифицировать и адаптировать их в соответствии с требованиями вашего проекта, делая их отличной отправной точкой. 🏁 -Вы можете использовать этот шаблон, чтобы начать, так как он включает множество начальных настроек, безопасности, базу данных и некоторые API эндпоинты уже готовы. +Вы можете использовать этот шаблон, чтобы быстрее начать работу, так как он включает в себя множество начальных настроек, функции безопасности, баз данных и несколько эндпоинтов API. -Репозиторий на GitHub: Full Stack FastAPI Template +Репозиторий GitHub: Full Stack FastAPI Template -## Full Stack FastAPI Шаблон - Технологии и Особенности +## Full Stack FastAPI Шаблон - Технологический стек и функциональные возможности -- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python бэкенда API. - - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия Python с SQL базой данных (ORM). +- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) для Python-бэкенда API. + - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия с SQL-базами данных на Python (ORM). - 🔍 [Pydantic](https://docs.pydantic.dev), используемый FastAPI, для валидации данных и управления настройками. - - 💾 [PostgreSQL](https://www.postgresql.org) в качестве SQL базы данных. + - 💾 [PostgreSQL](https://www.postgresql.org) как SQL база данных. - 🚀 [React](https://react.dev) для фронтенда. - - 💃 Использование TypeScript, hooks, [Vite](https://vitejs.dev), и других компонентов современного стека фронтенда. - - 🎨 [Chakra UI](https://chakra-ui.com) для компонентов фронтенда. - - 🤖 Автоматически сгенерированный фронтенд клиент. + - 💃 Использование TypeScript, хуков, [Vite](https://vitejs.dev) и других компонентов современного стека фронтенда. + - 🎨 [Chakra UI](https://chakra-ui.com) для фронтенд-компонентов. + - 🤖 Автоматически сгенерированный фронтенд-клиент. - 🧪 [Playwright](https://playwright.dev) для End-to-End тестирования. - - 🦇 Поддержка темного режима. + - 🦇 Поддержка тёмного режима. - 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна. -- 🔒 Безопасное хеширование паролей по умолчанию. -- 🔑 Аутентификация с помощью JWT токенов. +- 🔒 Безопасное хэширование паролей по умолчанию. +- 🔑 Аутентификация на основе JWT токенов. - 📫 Восстановление пароля через email. - ✅ Тесты с использованием [Pytest](https://pytest.org). - 📞 [Traefik](https://traefik.io) в качестве реверс-прокси / балансировщика нагрузки. -- 🚢 Инструкции по развёртыванию с Docker Compose, включая настройку фронтенд прокси Traefik для автоматического управления HTTPS сертификатами. +- 🚢 Инструкции по развертыванию с использованием Docker Compose, включая настройку фронтенд-прокси Traefik для автоматической обработки HTTPS-сертификатов. - 🏭 CI (непрерывная интеграция) и CD (непрерывное развёртывание) на базе GitHub Actions. diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md index 3224e8265..091a3f9b4 100644 --- a/docs/ru/docs/tutorial/body-multiple-params.md +++ b/docs/ru/docs/tutorial/body-multiple-params.md @@ -1,24 +1,24 @@ -# Тело запроса - Множество параметров +# Body - Множество параметров Теперь, когда мы увидели, как использовать `Path` и `Query`, давайте рассмотрим более продвинутые примеры объявления тела запроса. ## Объединение `Path`, `Query` и параметров тела запроса -Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления параметров тела запроса, и **FastAPI** автоматически поймёт, что с ними делать. +Во-первых, конечно, вы можете свободно объединять параметры `Path`, `Query` и объявления тела запроса, и **FastAPI** автоматически определит, что с ними делать. -Вы также можете объявлять параметры тела как необязательные, установив значение по умолчанию `None`: +Вы также можете объявить параметры тела запроса как необязательные, установив значение по умолчанию, равное `None`: {* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *} /// note | Заметка -Заметьте, что в данном случае параметр `item`, который будет взят из тела запроса, необязателен. Так как у него установлено значение `None` по умолчанию. +Заметьте, что в данном случае параметр `item`, который будет взят из тела запроса, необязателен. Так как было установлено значение `None` по умолчанию. /// -## Множественные параметры тела +## Несколько параметров тела запроса -В предыдущем примере, *операции пути* ожидали JSON-тело с атрибутами `Item`, например: +В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON с параметрами, соответствующими атрибутам `Item`, например: ```JSON { @@ -29,13 +29,13 @@ } ``` -Но вы также можете объявить множество параметров тела запроса, например параметры `item` и `user`: +Но вы также можете объявить множество параметров тела запроса, например `item` и `user`: {* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *} -В этом случае **FastAPI** заметит, что в функции больше одного параметра тела (два параметра, которые являются моделями Pydantic). +В этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются моделями Pydantic). -Таким образом, в теле запроса будут использоваться имена параметров в качестве ключей (имен полей), и будет ожидаться запрос следующего формата: +Таким образом, имена параметров будут использоваться в качестве ключей (имён полей) в теле запроса, и будет ожидаться запрос следующего формата: ```JSON { @@ -52,29 +52,29 @@ } ``` -/// note | Заметка +/// note | Внимание -Обратите внимание, что хотя параметр `item` был объявлен таким же образом, как и раньше, теперь предполагается, что он находится внутри тела запроса с ключом `item`. +Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`. /// -**FastAPI** сделает автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с параметром `user`. +**FastAPI** выполнит автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое произойдет с `user`. -Он выполнит проверку составных данных и задокументирует это в схеме OpenAPI и автоматической документации. +Произойдет проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах. -## Отдельные значения в теле +## Отдельные значения в теле запроса -Так же, как существуют `Query` и `Path` для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет эквивалент для тела - `Body`. +Точно так же, как `Query` и `Path` используются для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет аналогичный инструмент - `Body`. -Например, расширяя предыдущую модель, вы можете решить, что вам нужен ещё один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`. +Например, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`. -Если вы объявите его как есть, поскольку это простой тип данных, **FastAPI** будет считать, что это query-параметр. +Если вы объявите его без указания, какой именно объект (Path, Query, Body и т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать его query-параметром. -Но вы можете указать **FastAPI** обрабатывать его как ещё один ключ тела запроса, используя `Body`: +Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`: {* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *} -В этом случае **FastAPI** будет ожидать тело такого вида: +В этом случае, **FastAPI** будет ожидать тело запроса в формате: ```JSON { @@ -92,13 +92,13 @@ } ``` -И снова, он преобразует типы данных, проверит, задокументирует и т.д. +И все будет работать так же: преобразование типов данных, валидация, документирование и т.д. -## Множество body-параметров и query +## Множество body и query параметров -Конечно, вы также можете объявлять дополнительные query-параметры в любое время, дополнительно к любым body-параметрам. +Конечно, вы также можете объявлять дополнительные query-параметры в любое время, в дополнение к любым body-параметрам. -Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так: +Поскольку по умолчанию отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так: ```Python q: Union[str, None] = None @@ -120,19 +120,19 @@ q: str | None = None /// -## Встраивание одного параметра тела +## Добавление одного body-параметра -Предположим, у вас есть только один параметр тела `item` из модели Pydantic `Item`. +Предположим, у вас есть только один body-параметр `item` из Pydantic-модели `Item`. -По умолчанию **FastAPI** ожидает получить тело запроса напрямую. +По умолчанию, **FastAPI** ожидает получить тело запроса напрямую. -Но если вы хотите, чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`: +Но если вы хотите, чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, также как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`: ```Python item: Item = Body(embed=True) ``` -как в этом примере: +так же, как в этом примере: {* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *} @@ -149,7 +149,7 @@ item: Item = Body(embed=True) } ``` -вместо: +вместо этого: ```JSON { @@ -162,10 +162,10 @@ item: Item = Body(embed=True) ## Резюме -Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря на то, что запрос может содержать только одно тело. +Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря даже на то, что запрос может содержать только одно тело. -Но **FastAPI** справится с этим, предоставит вам правильные данные в вашей функции, а также выполнит валидацию и документирование правильной схемы *операции пути*. +Но **FastAPI** справится с этим, предоставит правильные данные в вашей функции, а также сделает валидацию и документацию правильной схемы *операции пути*. -Вы также можете объявлять отдельные значения для получения в рамках тела запроса. +Вы также можете объявить отдельные значения для получения в рамках тела запроса. -И вы можете настроить **FastAPI** так, чтобы включить тело запроса в ключ, даже если объявлен только один параметр. +И вы можете настроить **FastAPI** таким образом, чтобы включить тело запроса в ключ, даже если объявлен только один параметр. diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md index 4cfcf703c..1cf436357 100644 --- a/docs/ru/docs/tutorial/cors.md +++ b/docs/ru/docs/tutorial/cors.md @@ -1,54 +1,54 @@ # CORS (Cross-Origin Resource Sharing) -CORS или "Cross-Origin Resource Sharing" относится к ситуациям, когда фронтенд, работающий в браузере, использует JavaScript-код для взаимодействия с бэкендом, который находится в другом "источнике" по сравнению с фронтендом. +Понятие CORS или "Cross-Origin Resource Sharing" относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом "источнике" ("origin"). ## Источник -Источник - это сочетание протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`). +Источник - это совокупность протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`). -Таким образом, все это различные источники: +Поэтому это три разных источника: * `http://localhost` * `https://localhost` * `http://localhost:8080` -Даже если они все находятся на `localhost`, они используют разные протоколы или порты, следовательно, это разные "источники". +Даже если они все расположены в `localhost`, они используют разные протоколы и порты, а значит, являются разными источниками. ## Шаги -Предположим, у вас есть фронтенд, работающий в вашем браузере по адресу `http://localhost:8080`, и его JavaScript пытается взаимодействовать с бэкендом, работающим по адресу `http://localhost` (так как порт не указан, браузер предполагает использование порта `80`). +Допустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`). -Затем браузер отправит HTTP-запрос `OPTIONS` на бэкенд на порту `80`, и если бэкенд отправит соответствующие заголовки, разрешающие взаимодействие с этого отличающегося источника (`http://localhost:8080`), тогда браузер на порту `8080` позволит JavaScript на фронтенде отправить свой запрос на бэкенд на порту `80`. +Затем браузер отправит бэкенду HTTP-запрос `OPTIONS`, и если бэкенд вернёт соответствующие HTTP-заголовки для авторизации взаимодействия с другим источником (`http://localhost:8080`), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд. -Чтобы это воплотилось, бэкенд на порту `80` должен иметь список "разрешённых источников". +Чтобы это работало, у бэкенда должен быть список "разрешённых источников" ("allowed origins"). -В данном случае список должен содержать `http://localhost:8080`, чтобы фронтенд на порту `8080` работал корректно. +В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд работал корректно. ## Подстановочные символы -Можно указать список, используя подстановочный символ `"*"`, чтобы разрешить любые источники. +В качестве списка источников можно указать подстановочный символ `"*"` ("wildcard"), чтобы разрешить любые источники. -Но тогда не будут разрешены некоторые виды взаимодействия, включая всё, что связано с учётными данными: куки, заголовки Authorization с токенами Bearer и т.п. +Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, HTTP-заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п. -Поэтому, чтобы всё функционировало правильно, лучше явно указывать разрешённые источники. +Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников. ## Использование `CORSMiddleware` -Вы можете настроить это в вашем приложении **FastAPI** с помощью `CORSMiddleware`. +Вы можете настроить этот механизм в вашем **FastAPI** приложении, используя `CORSMiddleware`. * Импортируйте `CORSMiddleware`. -* Создайте список разрешённых источников (как строки). -* Добавьте его как "middleware" к вашему приложению **FastAPI**. +* Создайте список разрешённых источников (в виде строк). +* Добавьте его как "middleware" к вашему **FastAPI** приложению. -Вы также можете указать, позволяет ли ваш бэкенд использовать: +Вы также можете указать, разрешает ли ваш бэкенд использование: -* Учётные данные (заголовки Authorization, куки и т.п.). -* Специфические HTTP-методы (`POST`, `PUT`) или все из них с помощью подстановочного символа `"*"`. -* Специфические HTTP-заголовки или все из них с помощью подстановочного символа `"*"`. +* Учётных данных (включая HTTP-заголовки Authorization, куки и т.п.). +* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`. +* Отдельных HTTP-заголовков или всех вместе, используя `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:12,14:20] *} +{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} -По умолчанию параметры, используемые в реализации `CORSMiddleware`, имеют ограничительные значения, поэтому вам необходимо явно разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте. +`CORSMiddleware` использует для параметров "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте. Поддерживаются следующие аргументы: @@ -56,30 +56,33 @@ * `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\.example\.org'`. * `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию равно `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы. * `allow_headers` - Список HTTP-заголовков, которые должны поддерживаться при кросс-доменных запросах. По умолчанию равно `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для простых CORS-запросов. -* `allow_credentials` - Указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. Ни один из параметров `allow_origins`, `allow_methods` и `allow_headers` не может быть установлен в `['*']`, если `allow_credentials` установлен в `True`. Все они должны быть явно указаны. +* `allow_credentials` - указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. + + Ни один из параметров `allow_origins`, `allow_methods` и `allow_headers` нельзя задавать значением `['*']`, если `allow_credentials` равно `True`. Все они должны быть явно указаны. + * `expose_headers` - Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию равно `[]`. -* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузеры могут кэшировать CORS-ответы. По умолчанию равно `600`. +* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию равно `600`. -Middleware отвечает на два определённых типа HTTP-запросов... +`CORSMiddleware` отвечает на два типа HTTP-запросов... ### CORS-запросы с предварительной проверкой -Это любые `OPTIONS` запросы с заголовками `Origin` и `Access-Control-Request-Method`. +Это любые `OPTIONS` запросы с HTTP-заголовками `Origin` и `Access-Control-Request-Method`. -В этом случае middleware перехватывает входящий запрос и отправляет соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` для информационных целей. +В этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` в информационных целях. ### Простые запросы -Любые запросы с заголовком `Origin`. В этом случае middleware пропускает запрос дальше, как обычно, но добавляет соответствующие CORS-заголовки к ответу. +Любые запросы с заголовком `Origin`. В этом случае middleware передаст запрос дальше как обычно, но добавит соответствующие CORS-заголовки к ответу. -## Дополнительная информация +## Больше информации -Для получения более подробной информации о CORS, обратитесь к документации CORS от Mozilla. +Для получения более подробной информации о CORS, обратитесь к Документации CORS от Mozilla. /// note | Технические детали Вы также можете использовать `from starlette.middleware.cors import CORSMiddleware`. -**FastAPI** предоставляет несколько middleware в `fastapi.middleware` исключительно для вашего удобства как разработчика. Но большинство доступных middleware непосредственно поступают из Starlette. +**FastAPI** предоставляет несколько middleware в `fastapi.middleware` только для вашего удобства как разработчика. Но большинство доступных middleware взяты напрямую из Starlette. /// diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md index fe7276db6..28e90deb9 100644 --- a/docs/ru/docs/tutorial/extra-models.md +++ b/docs/ru/docs/tutorial/extra-models.md @@ -1,57 +1,56 @@ # Дополнительные модели -Продолжая с предыдущим примером, будет обычным явлением иметь более одной связанной модели. +В продолжение прошлого примера, будет обычным делом иметь несколько связанных между собой моделей. -Это особенно применимо в случае пользовательских моделей, потому что: +Это особенно касается моделей пользователя, потому что: -* **Модель для ввода** должна иметь возможность включать пароль. +* **Модель для ввода** должна иметь возможность содержать пароль. * **Модель для вывода** не должна содержать пароль. -* **Модель для базы данных** вероятно должна включать хэшированный пароль. +* **Модель для базы данных**, вероятно, должна содержать хэшированный пароль. -/// danger | Опасность +/// danger | Внимание -Никогда не храните пароли пользователей в открытом виде. Всегда храните "безопасный хэш", который вы затем сможете проверить. +Никогда не храните пароли пользователей в чистом виде. Всегда храните "защищенный хэш", который вы затем сможете проверять. -Если вы не знаете, вы можете узнать, что такое "хэш пароля" в [главе по безопасности](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}. +Если вы не знаете, вы узнаете, что такое "хэш пароля" в [главах о безопасности](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}. /// ## Множественные модели -Вот общая идея о том, как могут выглядеть модели с их полями пароля и где они используются: +Ниже представлено общее представление о том, как могут выглядеть эти модели с их полями для паролей и где они используются: {* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} - /// info | Информация -В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был устаревшим (но всё ещё поддерживается) и переименован в `.model_dump()`. +В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он устарел (но все еще поддерживается) и был переименован в `.model_dump()`. -В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, следует использовать `.model_dump()`. +В приведенных примерах используется `.dict()` для совместимости с Pydantic v1, но вам следует использовать `.model_dump()`, если вы можете использовать Pydantic v2. /// -### Про `**user_in.dict()` +### О `**user_in.dict()` #### `.dict()` из Pydantic -`user_in` — это модель Pydantic класса `UserIn`. +`user_in` — это Pydantic модель класса `UserIn`. -У моделей Pydantic есть метод `.dict()`, который возвращает `dict` с данными модели. +У Pydantic моделей есть метод `.dict()`, который возвращает `dict` с данными модели. -Итак, если мы создадим объект Pydantic `user_in` так: +Поэтому, если мы создадим Pydantic объект `user_in` таким образом: ```Python user_in = UserIn(username="john", password="secret", email="john.doe@example.com") ``` -а затем вызовем: +и затем вызовем: ```Python user_dict = user_in.dict() ``` -теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic- модели). +то теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic модели). И если мы вызовем: @@ -59,7 +58,7 @@ user_dict = user_in.dict() print(user_dict) ``` -мы получим Python `dict` с: +мы бы получили Python `dict` с: ```Python { @@ -72,15 +71,15 @@ print(user_dict) #### Распаковка `dict` -Если мы возьмём `dict` вроде `user_dict` и передадим его в функцию (или класс) с помощью `**user_dict`, Python "распакует" его. Он передаст ключи и значения `user_dict` напрямую как аргументы ключ-значение. +Если мы возьмем `dict`, аналогичный `user_dict`, и передадим его в функцию (или класс) с `**user_dict`, Python его "распакует". Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение. -Поэтому, продолжая с `user_dict`, написание: +Поэтому, продолжая с `user_dict`, написание следующего кода: ```Python UserInDB(**user_dict) ``` -будет эквивалентно: +будет аналогично следующему: ```Python UserInDB( @@ -91,7 +90,7 @@ UserInDB( ) ``` -Или более точно, используя `user_dict` напрямую, с любым потенциальным содержимым: +Или, более точно, используя `user_dict` напрямую с любым потенциальным содержимым: ```Python UserInDB( @@ -102,7 +101,7 @@ UserInDB( ) ``` -#### Pydantic-модель из содержимого другой модели +#### Pydantic модель из содержимого другой модели Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код: @@ -111,25 +110,25 @@ user_dict = user_in.dict() UserInDB(**user_dict) ``` -будет эквивалентен: +будет равнозначен следующему: ```Python UserInDB(**user_in.dict()) ``` -...потому что `user_in.dict()` — это `dict`, и затем мы указываем Python "распаковать" его, передавая его в `UserInDB`, добавив перед ним `**`. +...потому что `user_in.dict()` — это `dict`, и затем мы заставляем Python его "распаковать" при передаче в `UserInDB`, поставив впереди `**`. -Таким образом, мы получаем Pydantic-модель из данных другой Pydantic-модели. +Таким образом, мы получаем Pydantic модель на основе данных из другой Pydantic модели. #### Распаковка `dict` и дополнительные именованные аргументы -И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password`, как здесь: +И затем добавляя дополнительный именованный аргумент `hashed_password=hashed_password`, как в: ```Python UserInDB(**user_in.dict(), hashed_password=hashed_password) ``` -...это будет равно: +...это будет равноценно: ```Python UserInDB( @@ -143,78 +142,81 @@ UserInDB( /// warning | Предупреждение -Используемые в примере вспомогательные функции `fake_password_hasher` и `fake_save_user` служат лишь для демонстрации возможного потока данных, но, конечно, они не обеспечивают настоящую безопасность. +Используемые в примере вспомогательные функции `fake_password_hasher` и `fake_save_user` предназначены только для демонстрации возможного потока данных, но, конечно, они не обеспечивают реальной безопасности. /// ## Сократите дублирование -Сокращение дублирования кода — одна из основных идей **FastAPI**. +Сокращение дублирования кода — одна из основных идей в **FastAPI**. -Поскольку дублирование кода увеличивает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д. +Поскольку дублирование кода увеличивает шансы на баги, проблемы с безопасностью, проблемы с десинхронизацией кода (когда вы обновляете код в одном месте, но не обновляете в другом) и т.д. -И все эти модели разделяют много данных и дублируют названия и типы атрибутов. +А все описанные выше модели совместно используют много данных и дублируют названия атрибутов и типов. -Мы могли бы сделать лучше. +Мы можем это улучшить. -Мы можем объявить модель `UserBase`, которая будет базовой для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию и т.п.). +Мы можем объявить модель `UserBase`, которая будет использоваться в качестве основы для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию и т.п.). -Все операции конвертации, валидации, документации и т.п. будут по-прежнему работать нормально. +Все операции конвертации данных, валидации, составления документации и прочего будут по-прежнему работать нормально. -Таким образом, мы можем определить только отличия между моделями (с открытым `password`, с `hashed_password` и без пароля): +Таким образом, мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля): {* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *} ## `Union` или `anyOf` -Вы можете объявить ответ как `Union` из двух или более типов, это значит, что ответ должен соответствовать одному из них. +Вы можете объявить, что ответ должен быть `Union` из двух или более типов, это значит, что ответ может соответствовать любому из них. -Он будет определён в OpenAPI как `anyOf`. +Это будет определено в OpenAPI как `anyOf`. -Для этого используйте стандартный аннотацию типа Python `typing.Union`: +Для этого используйте стандартную аннотацию типа в Python `typing.Union`: /// note | Примечание -При определении `Union`, сначала указывайте самый специфичный тип, затем менее специфичные. В примере ниже более специфичный `PlaneItem` идёт перед `CarItem` в `Union[PlaneItem, CarItem]`. +При определении `Union`, сначала указывайте самый конкретный тип, а затем менее конкретный тип. В примере ниже более конкретный `PlaneItem` идет перед `CarItem` в `Union[PlaneItem, CarItem]`. /// {* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} + ### `Union` в Python 3.10 -В этом примере мы передаём `Union[PlaneItem, CarItem]` как значение аргумента `response_model`. +В этом примере мы передаем `Union[PlaneItem, CarItem]` как значение аргумента `response_model`. -Поскольку мы передаём его как **значение для аргумента**, а не помещаем его в **аннотацию типа**, нам необходимо использовать `Union` даже в Python 3.10. +Поскольку мы передаем его как **значение аргумента**, а не как часть **аннотации типа**, мы должны использовать `Union` даже в Python 3.10. -Если бы это было в аннотации типа, мы могли бы использовать вертикальную черту, как в примере: +Если бы это было в аннотации типа, мы могли бы использовать вертикальную черту, например: ```Python some_variable: PlaneItem | CarItem ``` -Но если мы поместим это в `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа. +Но если мы поместим это в присваивание `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа. ## Список моделей -Аналогичным образом вы можете объявить ответы как списки объектов. +Аналогично, вы можете объявить ответы в виде списков объектов. -Для этого используйте стандартный Python `typing.List` (или просто `list` в Python 3.9 и выше): +Для этого используйте стандартный `typing.List` из Python (или просто `list` в Python 3.9 и выше): {* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} + ## Ответ с произвольным `dict` -Вы также можете объявлять ответ, используя простой необязательный `dict`, определяя только типы ключей и значений без использования Pydantic-моделей. +Вы также можете объявить ответ, используя произвольный одноуровневый `dict`, задавая только типы ключей и значений без использования Pydantic модели. -Это полезно, если вы заранее не знаете допустимые названия полей/атрибутов (которые понадобятся для использования Pydantic-модели). +Это полезно, если вы не знаете заранее допустимые названия полей/атрибутов (которые понадобятся при использовании Pydantic модели). -В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше): +В этом случае можно использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше): {* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} + ## Резюме -Используйте несколько Pydantic-моделей и свободно наследуйте для каждого случая. +Используйте несколько Pydantic моделей и свободно применяйте наследование в каждом случае. -Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность существовать в разных "состояниях". Как в случае с "сущностью" пользователя с состояниями, включающими `password`, `password_hash` и без пароля. +Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля. diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md index 19b0465af..57a3ae3cf 100644 --- a/docs/ru/docs/tutorial/first-steps.md +++ b/docs/ru/docs/tutorial/first-steps.md @@ -1,12 +1,12 @@ # Первые шаги -Самый простой файл FastAPI может выглядеть следующим образом: +Самый простой FastAPI файл может выглядеть так: {* ../../docs_src/first_steps/tutorial001.py *} -Скопируйте это в файл `main.py`. +Скопируйте в файл `main.py`. -Запустите live сервер: +Запустите сервер в режиме разработки:
@@ -51,16 +51,16 @@ $ fastapi dev http://127.0.0.1:8000. +Откройте браузер по адресу: http://127.0.0.1:8000. -Вы увидите JSON-ответ, который выглядит следующим образом: +Вы увидите JSON-ответ следующего вида: ```JSON {"message": "Hello World"} @@ -68,51 +68,51 @@ INFO: Uvicorn запущен по адресу http://127.0.0.1:8000 (наж ### Интерактивная документация API -Теперь перейдите по адресу http://127.0.0.1:8000/docs. +Перейдите по адресу: http://127.0.0.1:8000/docs. -Вы увидите автоматическую интерактивную документацию API (предоставленную Swagger UI): +Вы увидите автоматически сгенерированную, интерактивную документацию по API (предоставленную Swagger UI): ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) ### Альтернативная документация API -И теперь перейдите по адресу http://127.0.0.1:8000/redoc. +Теперь перейдите по адресу http://127.0.0.1:8000/redoc. -Вы увидите альтернативную автоматическую документацию (предоставленную ReDoc): +Вы увидите альтернативную автоматически сгенерированную документацию (предоставленную ReDoc): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) ### OpenAPI -**FastAPI** генерирует "схему" всего вашего API, используя стандарт **OpenAPI** для определения API. +**FastAPI** генерирует "схему" всего API, используя стандарт **OpenAPI**. #### "Схема" -"Схема" — это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание. +"Схема" - это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание. -#### "Схема" API +#### API "схема" -В данном случае, OpenAPI — это спецификация, которая определяет, как описывать схему API. +OpenAPI - это спецификация, которая определяет, как описывать схему API. -Это определение схемы включает в себя пути вашего API, возможные параметры, которые они принимают, и т.д. +Определение схемы содержит пути (paths) API, их параметры и т.п. #### "Схема" данных -Термин "схема" также может относиться к формату данных, например, к содержимому JSON. +Термин "схема" также может относиться к формату или структуре некоторых данных, например, JSON. -В этом случае это будет означать атрибуты JSON и типы данных, которые они имеют, и т.д. +Тогда, подразумеваются атрибуты JSON, их типы данных и т.п. #### OpenAPI и JSON Schema -OpenAPI определяет схему API для вашего API. А эта схема включает в себя определения (или "схемы") данных, отправляемых и получаемых вашим API, используя **JSON Schema**, стандарт для схем данных JSON. +OpenAPI описывает схему API. Эта схема содержит определения (или "схемы") данных, отправляемых и получаемых API. Для описания структуры данных в JSON используется стандарт **JSON Schema**. -#### Посмотрите `openapi.json` +#### Рассмотрим `openapi.json` -Если вам интересно, как выглядит необработанная схема OpenAPI, FastAPI автоматически генерирует JSON (схему) с описаниями всего вашего API. +Если Вас интересует, как выглядит исходная схема OpenAPI, то FastAPI автоматически генерирует JSON-схему со всеми описаниями API. -Вы можете увидеть её непосредственно по адресу: http://127.0.0.1:8000/openapi.json. +Можете посмотреть здесь: http://127.0.0.1:8000/openapi.json. -Она покажет JSON, начинающийся примерно так: +Вы увидите примерно такой JSON: ```JSON { @@ -137,11 +137,11 @@ OpenAPI определяет схему API для вашего API. А эта #### Для чего нужен OpenAPI -Схема OpenAPI обеспечивает работу двух включенных систем интерактивной документации. +Схема OpenAPI является основой для обеих систем интерактивной документации. -Существуют десятки альтернатив, все они основываются на OpenAPI. Вы можете легко добавить любую из этих альтернатив к своему приложению на **FastAPI**. +Существуют десятки альтернативных инструментов, основанных на OpenAPI. Вы можете легко добавить любой из них к **FastAPI** приложению. -Вы также можете использовать её для автоматической генерации кода для клиентов, которые взаимодействуют с вашим API. Например, для фронтенд-, мобильных или IoT-приложений. +Вы также можете использовать OpenAPI для автоматической генерации кода для клиентов, которые взаимодействуют с API. Например, для фронтенд-, мобильных или IoT-приложений. ## Рассмотрим поэтапно @@ -149,99 +149,97 @@ OpenAPI определяет схему API для вашего API. А эта {* ../../docs_src/first_steps/tutorial001.py hl[1] *} -`FastAPI` — это класс Python, который предоставляет всю функциональность для вашего API. +`FastAPI` это класс в Python, который предоставляет всю функциональность для API. /// note | Технические детали -`FastAPI` — это класс, который наследуется напрямую от `Starlette`. +`FastAPI` это класс, который наследуется непосредственно от `Starlette`. -Вы можете использовать всю функциональность Starlette с `FastAPI`. +Вы можете использовать всю функциональность Starlette в `FastAPI`. /// -### Шаг 2: создайте "экземпляр" `FastAPI` +### Шаг 2: создайте экземпляр `FastAPI` {* ../../docs_src/first_steps/tutorial001.py hl[3] *} -Здесь переменная `app` будет "экземпляром" класса `FastAPI`. +Переменная `app` является экземпляром класса `FastAPI`. -Это единая точка входа для создания и взаимодействия с API. +### Шаг 3: определите *операцию пути (path operation)* -### Шаг 3: создайте *операцию пути* +#### Путь (path) -#### Путь +"Путь" это часть URL, после первого символа `/`, следующего за именем домена. -Здесь "путь" относится к последней части URL, начиная с первого `/`. - -Таким образом, в URL типа: +Для URL: ``` https://example.com/items/foo ``` -...путь будет: +...путь выглядит так: ``` /items/foo ``` -/// info +/// info | Дополнительная информация -"Путь" также часто называют "endpoint" или "route". +Термин "path" также часто называется "endpoint" или "route". /// -При создании API "путь" является основным способом отделения "задач" и "ресурсов". +При создании API, "путь" является основным способом разделения "задач" и "ресурсов". -#### Операция +#### Операция (operation) -Здесь "операция" относится к одному из HTTP "методов". +"Операция" это один из "методов" HTTP. -Одному из: +Таких, как: * `POST` * `GET` * `PUT` * `DELETE` -...и более экзотическим: +...и более экзотических: * `OPTIONS` * `HEAD` * `PATCH` * `TRACE` -По протоколу HTTP вы можете взаимодействовать с каждым путем, используя один (или более) из этих "методов". +По протоколу HTTP можно обращаться к каждому пути, используя один (или несколько) из этих "методов". --- -При создании API вы обычно используете эти конкретные HTTP методы для выполнения определенных действий. +При создании API принято использовать конкретные HTTP-методы для выполнения определенных действий. -Обычно вы используете: +Обычно используют: -* `POST`: для создания данных. -* `GET`: для чтения данных. -* `PUT`: для обновления данных. -* `DELETE`: для удаления данных. +* `POST`: создать данные. +* `GET`: прочитать. +* `PUT`: изменить (обновить). +* `DELETE`: удалить. -Таким образом, в OpenAPI каждый из HTTP методов называется "операцией". +В OpenAPI каждый HTTP метод называется "**операция**". -Мы также будем называть их "**операциями**". +Мы также будем придерживаться этого термина. -#### Определите *декоратор операции пути* +#### Определите *декоратор операции пути (path operation decorator)* {* ../../docs_src/first_steps/tutorial001.py hl[6] *} -`@app.get("/")` сообщает **FastAPI**, что функция, расположенная прямо под ним, отвечает за обработку запросов, поступающих по адресу: +Декоратор `@app.get("/")` указывает **FastAPI**, что функция, прямо под ним, отвечает за обработку запросов, поступающих по адресу: * путь `/` -* использующих операцию get +* использующих get операцию -/// info | `@decorator` Информация +/// info | `@decorator` Info Синтаксис `@something` в Python называется "декоратор". -Вы располагаете его над функцией. Подобно декоративной шляпе (вероятно, отсюда и происходит этот термин). +Вы помещаете его над функцией. Как красивую декоративную шляпу (думаю, что оттуда и происходит этот термин). "Декоратор" принимает функцию ниже и выполняет с ней какое-то действие. @@ -251,7 +249,7 @@ https://example.com/items/foo /// -Вы также можете использовать другие операции: +Можно также использовать операции: * `@app.post()` * `@app.put()` @@ -266,53 +264,53 @@ https://example.com/items/foo /// tip | Подсказка -Вы можете использовать каждую операцию (HTTP метод) по своему усмотрению. +Вы можете использовать каждую операцию (HTTP-метод) по своему усмотрению. -**FastAPI** не навязывает какого-либо специфического значения. +**FastAPI** не навязывает определенного значения для каждого метода. -Информация здесь представлена в качестве рекомендации, а не требования. +Информация здесь представлена как рекомендация, а не требование. -Например, при использовании GraphQL обычно все действия выполняются только с помощью `POST` операций. +Например, при использовании GraphQL обычно все действия выполняются только с помощью POST операций. /// ### Шаг 4: определите **функцию операции пути** -Это наша "**функция операции пути**": +Вот "**функция операции пути**": -* **путь**: это `/`. -* **операция**: это `get`. -* **функция**: это функция под "декоратором" (под `@app.get("/")`). +* **путь**: `/`. +* **операция**: `get`. +* **функция**: функция ниже "декоратора" (ниже `@app.get("/")`). {* ../../docs_src/first_steps/tutorial001.py hl[7] *} -Это нормальная функция Python. +Это обычная Python функция. -Она будет вызываться **FastAPI** каждый раз, когда будет получен запрос к URL "`/`" с использованием операции `GET`. +**FastAPI** будет вызывать её каждый раз при получении `GET` запроса к URL "`/`". -В данном случае она является асинхронной функцией. +В данном случае это асинхронная функция. --- -Вы также можете определить её как обычную функцию вместо `async def`: +Вы также можете определить ее как обычную функцию вместо `async def`: {* ../../docs_src/first_steps/tutorial003.py hl[7] *} /// note -Если вы не знаете разницы, посмотрите [Асинхронность: *"В торопях?"*](../async.md#in-a-hurry){.internal-link target=_blank}. +Если не знаете в чём разница, посмотрите [Асинхронность: *"Нет времени?"*](../async.md#_1){.internal-link target=_blank}. /// -### Шаг 5: верните содержимое +### Шаг 5: верните результат {* ../../docs_src/first_steps/tutorial001.py hl[8] *} Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д. -Также вы можете вернуть модели Pydantic (вы узнаете об этом позже). +Также можно вернуть модели Pydantic (рассмотрим это позже). -Множество других объектов и моделей будут автоматически преобразованы в JSON (включая ORM и т.п.). Попробуйте использовать ваши любимые — они с большой вероятностью уже поддерживаются. +Многие объекты и модели будут автоматически преобразованы в JSON (включая ORM). Пробуйте использовать другие объекты, которые предпочтительней для Вас, вероятно, они уже поддерживаются. ## Резюме @@ -320,4 +318,4 @@ https://example.com/items/foo * Создаём экземпляр `app`. * Пишем **декоратор операции пути** (такой как `@app.get("/")`). * Пишем **функцию операции пути** (`def root(): ...`). -* Запускаем сервер в режиме разработки (`fastapi dev`). +* Запускаем сервер в режиме разработки с использованием команды `fastapi dev`. diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md index 8b7fa5366..06d23e906 100644 --- a/docs/ru/docs/tutorial/handling-errors.md +++ b/docs/ru/docs/tutorial/handling-errors.md @@ -17,27 +17,27 @@ Четырёхсотые статус-коды означают, что ошибка произошла по вине клиента. -Помните ли ошибки **"404 Not Found"** (и шутки)? +Помните ли ошибки **"404 Not Found "** (и шутки) ? ## Использование `HTTPException` -Для возврата HTTP-ответов с ошибками клиенту используется `HTTPException`. +Для возврата клиенту HTTP-ответов с ошибками используется `HTTPException`. ### Импортируйте `HTTPException` {* ../../docs_src/handling_errors/tutorial001.py hl[1] *} -### Вызовите `HTTPException` в своём коде +### Вызовите `HTTPException` в своем коде `HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API. Поскольку это исключение Python, то его не `возвращают`, а `вызывают`. -Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы вызываете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту. +Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы поднимаете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту. -Польза от `вызова` исключения, а не `возврата` значения, станет очевидной в разделе, посвящённом зависимостям и безопасности. +О том, насколько выгоднее `вызывать` исключение, чем `возвращать` значение, будет рассказано в разделе, посвященном зависимостям и безопасности. -В этом примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`: +В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`: {* ../../docs_src/handling_errors/tutorial001.py hl[11] *} @@ -91,7 +91,7 @@ {* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *} -Здесь, если вы запросите `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`. +Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`. Но оно будет обработано `unicorn_exception_handler`. @@ -230,13 +230,11 @@ path -> item_id **FastAPI** имеет собственный `HTTPException`. -И класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`. +Класс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`. -Единственное отличие заключается в том, что `HTTPException` от **FastAPI** позволяет добавлять заголовки, которые будут включены в ответ. +Единственное отличие заключается в том, что исключение **FastAPI** `HTTPException` принимает любые данные, преобразуемые в JSON, в поле `detail`, в то время как исключение Starlette `HTTPException` принимает только строки. -Он необходим/используется внутри системы для OAuth 2.0 и некоторых утилит безопасности. - -Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своём коде. +Таким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своем коде. Но когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette. @@ -254,4 +252,4 @@ from starlette.exceptions import HTTPException as StarletteHTTPException {* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *} -В этом примере вы просто выводите в терминал ошибку с очень выразительным сообщением, но вы поняли основную идею. Вы можете использовать исключение и затем просто повторно использовать стандартные обработчики исключений. +В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений. diff --git a/docs/ru/docs/tutorial/index.md b/docs/ru/docs/tutorial/index.md index aadcf75e7..b56cef964 100644 --- a/docs/ru/docs/tutorial/index.md +++ b/docs/ru/docs/tutorial/index.md @@ -1,16 +1,18 @@ # Учебник - Руководство пользователя -Этот учебник показывает вам, как использовать **FastAPI** с большинством его функций, шаг за шагом. +В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций. -Каждый раздел постепенно основан на предыдущих, но он структурирован по отдельным темам, чтобы вы могли перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API. +Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API. -Этот учебник также предназначен для использования в качестве справочника в будущем, так что вы можете вернуться и посмотреть именно то, что вам нужно. +Он также создан для использования в качестве будущего справочника. -Все блоки кода можно копировать и использовать напрямую (это действительно проверенные файлы Python). +Так что вы можете вернуться и посмотреть именно то, что вам нужно. + +## Запустите код Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python). -Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с: +Чтобы запустить любой из примеров, скопируйте код в файл `main.py`, и запустите `fastapi dev` с:
@@ -52,9 +54,9 @@ $ fastapi dev fastapi dev @@ -74,22 +76,22 @@ $ pip install "fastapi[standard]"
-/// note | Примечание +/// note | Технические детали -Если вы устанавливаете с помощью `pip install "fastapi[standard]"`, это включает в себя некоторые стандартные необязательные зависимости, включая `fastapi-cloud-cli`, который позволяет развернуть на FastAPI Cloud. +Когда вы устанавливаете с помощью `pip install "fastapi[standard]"`, это включает некоторые стандартные необязательные зависимости, включая `fastapi-cloud-cli`, который позволяет развернуть приложение на FastAPI Cloud. -Если вы не хотите иметь эти необязательные зависимости, можно установить `pip install fastapi`. +Если вы не хотите иметь эти необязательные зависимости, вы можете вместо этого выполнить установку с помощью `pip install fastapi`. -Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, установите с помощью `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. +Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, вы можете установить их с `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. /// ## Продвинутое руководство пользователя -Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после **Учебника - Руководства пользователя**. +Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**. -**Продвинутое руководство пользователя** основывается на этом, использует те же концепции и учит вас некоторым дополнительным функциям. +**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям. -Но сначала вы должны прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). +Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). -Он разработан таким образом, чтобы вы могли создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**. +Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**. diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md index 5b1af44da..5f06ba4f3 100644 --- a/docs/ru/docs/tutorial/middleware.md +++ b/docs/ru/docs/tutorial/middleware.md @@ -1,43 +1,43 @@ -# Middleware (Промежуточное ПО) +# Middleware (Промежуточный слой) -Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение. +Вы можете добавить middleware (промежуточный слой) в **FastAPI** приложение. "Middleware" это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением. -* Оно обрабатывает каждый **запрос**, поступающий в ваше приложение. -* Может что-то сделать с этим **запросом** или выполнить любой необходимый код. -* Затем передает **запрос** для дальнейшей обработки остальным приложением (какой-либо *операцией пути*). -* Затем оно обрабатывает **ответ**, сгенерированный приложением (какой-либо *операцией пути*). -* Может что-то сделать с этим **ответом** или выполнить любой необходимый код. -* Затем возвращает **ответ**. +* Она принимает каждый поступающий **запрос**. +* Может что-то сделать с этим **запросом** или выполнить любой нужный код. +* Затем передает **запрос** для последующей обработки (какой-либо *операцией пути*). +* Получает **ответ** (от *операции пути*). +* Может что-то сделать с этим **ответом** или выполнить любой нужный код. +* И возвращает **ответ**. /// note | Технические детали -Если у вас есть зависимости с `yield`, код выхода выполнится *после* промежуточного ПО. +Если у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware. -Если есть какие-либо фоновые задачи (рассматриваемые в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}, вы увидите это позже), они будут выполнены *после* всего промежуточного ПО. +Если у вас имеются некие фоновые задачи (рассмотренные в разделе [Фоновые задачи](background-tasks.md){.internal-link target=_blank}), они будут запущены *после* всех middleware. /// ## Создание middleware -Для создания middleware используйте декоратор `@app.middleware("http")` над функцией. +Для создания middleware используйте декоратор `@app.middleware("http")` перед функцией. -Функция промежуточного ПО получает: +Функция middleware получает: -* `request` (запрос). -* Функцию `call_next`, которая получит `request` в качестве параметра. - * Эта функция передаст `request` соответствующей *операции пути*. - * Затем она возвратит `response`, сгенерированный соответствующей *операцией пути*. -* Вы можете дополнительно изменить `response`, прежде чем вернуть его. +* `request` (объект запроса). +* Функцию `call_next`, которая принимает `request` в качестве параметра. + * Эта функция передает `request` соответствующей *операции пути*. + * Затем она возвращает ответ `response`, сгенерированный *операцией пути*. +* Также имеется возможность видоизменить `response`, перед тем как его вернуть. {* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *} -/// tip | Совет +/// tip | Примечание -Имейте в виду, что вы можете добавлять собственные закрытые заголовки с помощью префикса 'X-'. +Имейте в виду, что собственные проприетарные заголовки можно добавлять при помощи префикса 'X-'. -Но если у вас есть собственные заголовки, которые вы хотите показать клиенту в браузере, вам необходимо добавить их в конфигурации CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) с использованием параметра `expose_headers`, документированного в документации по CORS Starlette. +Если же у вас есть собственные заголовки, которые клиент в браузере должен видеть, вам нужно добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию Starlette's CORS docs. /// @@ -45,33 +45,33 @@ Вы также можете использовать `from starlette.requests import Request`. -**FastAPI** предоставляет это для удобства разработчиков. Но, на самом деле, это `Request` из библиотеки Starlette. +**FastAPI** предоставляет это для удобства разработчиков. Но на самом деле это `Request` из Starlette. /// ### До и после `response` -Вы можете добавить код, который будет выполнен с `request`, до того как какая-либо *операция пути* его получит. +Вы можете добавить код, использующий `request` до передачи его какой-либо *операцией пути*. -А также после формирования `response`, до его возврата. +А также после формирования `response`, до того, как вы его вернёте. -Например, вы можете добавить пользовательский заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и формирования ответа: +Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа: {* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *} /// tip | Примечание -Мы используем `time.perf_counter()` вместо `time.time()` для обеспечения большей точности наших примеров. 🤓 +Мы используем `time.perf_counter()` вместо `time.time()`, потому что это может быть более точным для таких случаев. 🤓 /// ## Порядок выполнения нескольких middleware -Когда вы добавляете несколько middleware с помощью декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, образуя стек. Последнее добавленное middleware будет *внешним*, а первое — *внутренним*. +Когда вы добавляете несколько middleware с использованием декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, формируя стек. Последнее добавленное middleware становится самым *внешним*, а первое — самым *внутренним*. -На этапе запроса сначала выполняется *внешнее* middleware. +На пути **запроса**, самое *внешнее* middleware выполняется первым. -На этапе ответа оно выполняется последним. +На пути **ответа** оно выполняется последним. Например: @@ -80,16 +80,16 @@ app.add_middleware(MiddlewareA) app.add_middleware(MiddlewareB) ``` -Это приведет к следующему порядку выполнения: +Это приводит к следующему порядку выполнения: * **Запрос**: MiddlewareB → MiddlewareA → маршрут * **Ответ**: маршрут → MiddlewareA → MiddlewareB -Такое поведение стека обеспечивает выполнение middleware в предсказуемом и контролируемом порядке. +Такое поведение с упаковкой обеспечивает выполнение middleware в предсказуемом и контролируемом порядке. ## Другие middleware О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}. -В следующем разделе вы узнаете, как настроить CORS с помощью промежуточного ПО. +В следующем разделе вы можете прочитать, как настроить CORS с помощью middleware. diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md index 718739b5c..25f5d8f46 100644 --- a/docs/ru/docs/tutorial/query-params-str-validations.md +++ b/docs/ru/docs/tutorial/query-params-str-validations.md @@ -1,51 +1,49 @@ # Query-параметры и валидация строк -**FastAPI** позволяет объявлять дополнительную информацию и валидацию для ваших параметров. +**FastAPI** позволяет определять дополнительную информацию и валидацию для ваших параметров. Рассмотрим этот пример приложения: {* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *} -Query-параметр `q` имеет тип `str | None`. Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный. +Query-параметр `q` имеет тип `str | None`, что означает, что он имеет тип `str`, но также может быть `None`, и по умолчанию его значение `None`, так что FastAPI будет знать, что он не является обязательным. /// note | Технические детали -FastAPI определит, что значение `q` не является обязательным благодаря значению по умолчанию `= None`. +FastAPI определяет, что значение `q` не является обязательным благодаря значению по умолчанию `= None`. -`str | None` позволит редактору кода оказать вам лучшую поддержку и найти ошибки. +`str | None` позволяет вашему редактору кода предоставлять лучшую поддержку и обнаруживать ошибки. /// ## Дополнительная валидация -Добавим дополнительное условие валидации параметра `q` — **длина строки не более 50 символов**. +Мы собираемся обеспечить, что даже если `q` является необязательным, в случаях, когда он предоставлен, **его длина не превышает 50 символов**. ### Импорт `Query` и `Annotated` -Для этого сначала импортируйте: +Чтобы достигнуть этой цели, сначала импортируйте: -* `Query` из пакета `fastapi` -* `Annotated` из пакета `typing` +* `Query` из `fastapi` +* `Annotated` из `typing` {* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *} /// info | Дополнительная информация -FastAPI добавил поддержку `Annotated` (и начал рекомендовать его) в версии 0.95.0. +FastAPI добавил поддержку `Annotated` (и начал рекомендовать его использование) в версии 0.95.0. -Если у вас более старая версия, вы получите ошибки при попытке использовать `Annotated`. - -Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`. +Если у вас более старая версия, при попытке использования `Annotated` вы получите ошибки. Убедитесь, что вы [Обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до как минимум 0.95.1 перед использованием `Annotated`. /// -## Использование `Annotated` в типе для параметра `q` +## Использование `Annotated` в типе параметра `q` -Помните, я говорил вам ранее, что `Annotated` может использоваться для добавления метаданных к вашим параметрам в [Введение в аннотации типов Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}? +Помните, что я говорил ранее, что `Annotated` можно использовать для добавления метаинформации к вашим параметрам в разделе [Введение в аннотации типов Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}? -Теперь пришло время использовать его с FastAPI. 🚀 +Теперь пришло время использовать это в FastAPI. 🚀 -У нас была следующая аннотация типа: +У нас была аннотация типа: //// tab | Python 3.10+ @@ -63,7 +61,7 @@ q: Union[str, None] = None //// -Теперь мы обернем это в `Annotated`, чтобы получить: +Что мы сделаем: обернём это в `Annotated`, таким образом: //// tab | Python 3.10+ @@ -81,47 +79,47 @@ q: Annotated[Union[str, None]] = None //// -Обе эти версии означают одно и то же. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`. +Обе этих версии означают одно и то же, `q` — это параметр, который может быть `str` или `None`, и по умолчанию он будет `None`. -Теперь перейдем к самому интересному. 🎉 +Теперь перейдём к интересному. 🎉 ## Добавим `Query` в `Annotated` для параметра `q` -Теперь, когда у нас есть `Annotated`, где мы можем поместить больше информации (в данном случае дополнительную валидацию), добавим `Query` внутрь `Annotated` и установим параметр `max_length` равным `50`: +Теперь, когда у нас есть этот `Annotated`, куда мы можем поместить больше информации (в данном случае — дополнительную валидацию), добавим внутрь `Annotated` `Query`, и установим параметр `max_length` равным `50`: {* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *} -Обратите внимание, что значение по умолчанию все еще `None`, так что параметр остается необязательным. +Обратите внимание, что значение по умолчанию все ещё `None`, так что параметр остается необязательным. -Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим иметь **дополнительные условия валидации** для этого значения, чтобы его длина не превышала 50 символов. 😎 +Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим иметь **дополнительную валидацию** для этого значения, мы хотим, чтобы оно содержало максимум 50 символов. 😎 /// tip | Подсказка -Здесь мы используем `Query()`, так как это **query-параметр**. Позже мы увидим другие параметры, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают те же аргументы, что и `Query()`. +Здесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие, такие как `Path()`, `Body()`, `Header()`, и `Cookie()`, которые также принимают такие же аргументы, как и `Query()`. /// -Теперь FastAPI: +Теперь FastAPI будет: -* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов -* Показывает **понятную ошибку** для клиента в случаях, когда данные не валидны -* **Документирует** параметр в схему OpenAPI *операции пути* (что отображается в **UI автоматической документации**) +* **Валидировать** данные, удостоверяясь, что максимальная длина составляет 50 символов +* Показать **четкую ошибку** клиенту, когда данные не валидны +* **Документировать** параметр в схеме OpenAPI операции пути (таким образом, он будет отображаться в **UI автоматической документации**) ## Альтернативный (устаревший) способ: `Query` как значение по умолчанию -В предыдущих версиях FastAPI (до 0.95.0) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню. +До версии 0.95.0 FastAPI требовалось использовать `Query` как значение по умолчанию для вашего параметра, а не помещать его в `Annotated`. Вероятно, вы увидите такой код, поэтому я объясню его вам. /// tip | Подсказка -Для нового кода и когда это возможно, используйте `Annotated`, как описано выше. Есть множество преимуществ (объяснены ниже) и никаких недостатков. 🍰 +Для нового кода и везде где это возможно, используйте `Annotated` как описано выше. У этого способа есть несколько преимуществ (описаны ниже) и нет недостатков. 🍰 /// -Вот как вы бы использовали `Query()` в качестве значения по умолчанию параметра вашей функции, устанавливая параметр `max_length` равным 50: +Так вы бы использовали `Query()` в качестве значения по умолчанию для параметра функции, устанавливая параметр `max_length` равным 50: {* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *} -В этом случае (без использования `Annotated`) мы заменяем значение по умолчанию `None` функции на `Query()`, теперь нам необходимо установить значение по умолчанию с параметром `Query(default=None)`, это служит той же цели определения значения по умолчанию (по крайней мере для FastAPI). +Так как в этом случае (без использования `Annotated`) нам приходится заменять значение по умолчанию `None` в функции на `Query()`, теперь нам нужно установить значение по умолчанию с параметром `Query(default=None)`, это выполняет ту же цель, как определение значения по умолчанию (по крайней мере, для FastAPI). Таким образом: @@ -129,44 +127,44 @@ q: Annotated[Union[str, None]] = None q: str | None = Query(default=None) ``` -...делает параметр необязательным, со значением по умолчанию `None`, то же самое, что и: +...делает параметр необязательным со значением по умолчанию `None`, чем эквивалентен: ```Python q: str | None = None ``` -Но версия с `Query` объявляет его как query-параметр. +Но версия `Query` явно объявляет его как query-параметр. -Теперь, мы можем указать больше параметров для `Query`. В данном случае, параметр `max_length` применяется к строкам: +Затем, мы можем передать больше параметров в `Query`. В данном случае, это параметр `max_length`, который применяется к строкам: ```Python q: str | None = Query(default=None, max_length=50) ``` -Входные данные будут проверены. Если данные недействительны, тогда будет указано на ошибку в запросе. Параметр также будет задокументирован в схеме OpenAPI данной *операции пути*. +Это позволит валидировать данные, показать четкую ошибку когда данные не валидны, и задокументировать параметр в операции пути схемы OpenAPI. -### `Query` как значение по умолчанию или в `Annotated` +### Использование `Query` как значения по умолчанию или в `Annotated` -Имейте в виду, что при использовании `Query` внутри `Annotated` вы не можете использовать параметр `default` у `Query`. +Имейте в виду, что при использовании `Query` внутри `Annotated`, вы не можете использовать параметр `default` у `Query`. -Вместо этого, используйте обычное указание значения по умолчанию для параметра функции. Иначе это будет несовместимо. +Вместо этого, используйте фактическое значение по умолчанию параметра функции. Иначе это будет некорректно. -Например, это не разрешено: +Например, это неправильно: ```Python q: Annotated[str, Query(default="rick")] = "morty" ``` -...потому что не ясно, какое именно значение должно быть по умолчанию: `"rick"` или `"morty"`. +...потому что непонятно, какое именно значение должно быть по умолчанию: `"rick"` или `"morty"`. -Так что вы бы использовали (предпочтительно): +Так что, лучше всего использовать: ```Python q: Annotated[str, Query()] = "rick" ``` -...или в кодовой базе, которую вам может встретиться: +...или в старых кодовых базах можно встретить: ```Python q: str = Query(default="rick") @@ -174,43 +172,43 @@ q: str = Query(default="rick") ### Преимущества `Annotated` -**Рекомендуется использовать `Annotated`** вместо значения по умолчанию в параметрах функции. Это **лучше** по нескольким причинам. 🤓 +**Рекомендуется использовать `Annotated`** вместо значения по умолчанию в параметрах функции, поскольку это **лучше** по нескольким причинам. 🤓 -Значение **по умолчанию** у **параметров функции** — это **действительно значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌 +Значение **по умолчанию** у **параметров функции** — это **действительное значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌 -Вы можете **вызвать** ту же функцию в **иных местах** без FastAPI, и она **сработает как ожидалось**. Если это **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке. **Python** также укажет на ошибку, если вы вызовете функцию без передачи ей обязательного параметра. +Вы можете **вызвать** ту же функцию в **других местах** без FastAPI, и она **будет работать, как и ожидалось**. Если параметр является **обязательным** (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** также предупредит, если вы попытаетесь вызвать её без передачи этого обязательного параметра. -Если вы вместо `Annotated` используете **(устаревший) стиль значений по умолчанию**, тогда при вызове этой функции без FastAPI в **других местах** вам необходимо **помнить** о передаче аргументов функции, чтобы она работала корректно. В противном случае, значения будут отличаться от тех, что вы ожидаете (например, `QueryInfo` или что-то подобное вместо `str`). И ни ваш редактор кода, ни Python не будут жаловаться на работу этой функции, только когда вычисления внутри дадут сбой. +Когда вы не используете `Annotated`, а вместо этого используете **(устаревший) стиль значений по умолчанию**, если вы вызовете эту функцию без FastAPI в **других местах**, вам придется **помнить** об аргументах, которые нужно передать в функцию, чтобы она работала корректно, иначе значения будут отличаться от ожидаемых (например, `QueryInfo` или что-то похожее вместо `str`). И ваш редактор кода не сообщит об ошибке, и Python не сообщит об ошибке при выполнении функции, только когда выполнение операции внутри несовместимо. -Так как `Annotated` может иметь более одной аннотации метаданных, вы теперь даже можете использовать одну и ту же функцию с другими инструментами, такими как Typer. 🚀 +Поскольку `Annotated` может иметь более одной аннотации метаданных, вы теперь можете использовать ту же функцию с другими инструментами, такими как Typer. 🚀 -## Дополнительная валидация +## Добавим больше валидаций -Вы также можете добавить параметр `min_length`: +Также можно добавить параметр `min_length`: {* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *} -## Добавление регулярных выражений +## Регулярные выражения Вы можете определить регулярное выражение `pattern`, которому должен соответствовать параметр: {* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *} -Это регулярное выражение проверяет, что полученное значение параметра: +Это конкретное регулярное выражение проверяет, что полученное значение параметра: -* `^`: начинается с следующих символов, не имеет символов перед. -* `fixedquery`: в точности содержит строку `fixedquery`. -* `$`: заканчивается там, где `fixedquery`, не имеет символов после. +* `^`: начинается с следующих символов, не имеет символов перед этим. +* `fixedquery`: содержит точное значение `fixedquery`. +* `$`: заканчивается здесь, не имеет символов после `fixedquery`. -Если вам сложно дается концепция **"регулярные выражения"**, не беспокойтесь. Для многих людей это трудная тема. Вы можете делать множество вещей, не прибегая к регулярным выражениям. +Если вас пугает тема **"регулярных выражений"**, не переживайте. Это сложная тема для многих людей. Вы можете реализовать множество вещей без использования регулярных выражений. -Теперь вы знаете, что, когда вам понадобятся регулярные выражения, вы сможете использовать их в **FastAPI**. +Теперь вы знаете, что когда они вам понадобятся, вы можете использовать их в **FastAPI**. -### `regex` в Pydantic v1 вместо `pattern` +### Pydantic v1 `regex` вместо `pattern` -До версии Pydantic 2 и FastAPI 0.100.0, параметр назывался `regex` вместо `pattern`, но сейчас он считается устаревшим. +До версии Pydantic 2 и FastAPI 0.100.0, параметр назывался `regex`, а не `pattern`, но теперь он устарел. -Вы всё ещё можете встретить код, использующий его: +Всё ещё можно увидеть код, где это используется: //// tab | Pydantic v1 @@ -218,25 +216,25 @@ q: str = Query(default="rick") //// -Однако знайте, что это устарело и стоит обновить используемый параметр на `pattern`. 🤓 +Но это устаревший метод и его нужно обновить для использования нового параметра `pattern`. 🤓 ## Значения по умолчанию -Вы можете также указать любое значение `по умолчанию`, отличное от `None`. +Вы, конечно, можете использовать значения по умолчанию, отличные от `None`. -Например, если вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`: +Предположим, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`: {* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *} /// note | Технические детали -Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным (не требуется). +Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным. /// -## Обязательный параметр +## Обязательные параметры -Когда вам не требуется дополнительная валидация или другие метаданные для параметра запроса, вы можете сделать параметр `q` обязательным просто не указывая значения по умолчанию. Например: +Когда нам не требуется указывать дополнительные валидации или метаданные, мы можем сделать query-параметр `q` обязательным, просто не указывая значение по умолчанию, например: ```Python q: str @@ -248,7 +246,7 @@ q: str q: str | None = None ``` -Но в настоящее время мы определяем его через `Query`. Например: +Но мы определяем его с помощью `Query`, например, так: //// tab | Annotated @@ -258,35 +256,35 @@ q: Annotated[str | None, Query(min_length=3)] = None //// -Так что, если вы хотите сделать query-параметр `Query` обязательным, вы можете просто не указывать значение по умолчанию: +Так что, когда вам нужно сделать значение обязательным, используя `Query`, вы просто не указываете значение по умолчанию: {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} -### Обязательно, может быть `None` +### Обязательный параметр, может быть `None` -Вы можете объявить, что параметр может принимать значение `None`, но при этом является обязательным. Это заставит клиентов отправлять значение, даже если оно равно `None`. +Вы можете определить, что параметр может принимать `None`, но он всё равно является обязательным. Это заставит клиентов отправлять значение, даже если оно `None`. -Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но не указывать значение по умолчанию: +Для этого вы можете объявить, что `None` является допустимым типом, но просто не указывайте значение по умолчанию: {* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *} ## Множество значений для query-параметра -Для query-параметра `Query` можно указать, что он принимает список значений (множество значений). +Когда вы явным образом определяете query-параметр с помощью `Query`, вы также можете указать его как принимающий список значений, или, проще говоря, принимающий множество значений. -Например, чтобы объявить query-параметр `q`, который может появляться несколько раз в URL, вы можете написать: +Например, чтобы объявить query-параметр `q`, который может появляться несколько раз в URL, вы можете написать так: {* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *} -Затем, с таким URL: +Затем, с URL вида: ``` http://localhost:8000/items/?q=foo&q=bar ``` -вы получите несколько значений *query-параметра* `q` (`foo` и `bar`) в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`. +вы получите множество значений *query-параметров* `q` (`foo` и `bar`) в виде `list` Python внутри вашей *функции обработки пути*, в *функциональном параметре* `q`. -Так что ответ на этот URL будет: +Таким образом, ответ на этот URL будет: ```JSON { @@ -299,27 +297,27 @@ http://localhost:8000/items/?q=foo&q=bar /// tip | Подсказка -Чтобы объявить query-параметр типа `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса. +Чтобы объявить query-параметр типом `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса. /// -Интерактивная документация API обновится соответственно, чтобы разрешить множество значений: +Интерактивный UI документации API будет обновлён соответствующим образом, чтобы разрешать множество значений: -### Список значений для query-параметра / несколько значений по умолчанию +### Множество значений для query-параметра с дефолтными значениями -Вы также можете определить значение по умолчанию `list` для случаев, когда никакие значения не предоставлены: +Вы также можете определить список значений по умолчанию, если они не предоставлены: {* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *} -Если вы перейдете по: +Если вы перейдете по такому URL: ``` http://localhost:8000/items/ ``` -значением по умолчанию для `q` будет: `["foo", "bar"]` и ваш ответ будет: +значение по умолчанию для `q` будет: `["foo", "bar"]` и ответ будет: ```JSON { @@ -330,7 +328,7 @@ http://localhost:8000/items/ } ``` -#### Использование только `list` +#### Использование `list` Вы также можете использовать `list` напрямую вместо `list[str]`: @@ -338,27 +336,27 @@ http://localhost:8000/items/ /// note | Технические детали -Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка. +Имейте в виду, что в таком случае, FastAPI не будет проверять содержимое списка. -Например, для List[int] список будет валидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет. +Например, `list[int]` проверяет (и документирует), что содержимое списка - целые числа. Но просто `list` такую проверку не проводит. /// -## Объявление дополнительных метаданных +## Больше метаданных Вы можете добавить больше информации о параметре. -Эта информация будет включена в генерируемую OpenAPI и использована интерфейсами документации и внешними инструментами. +Эта информация будет включена в сгенерированный OpenAPI и использована интерфейсами документации и внешними инструментами. /// note | Технические детали -Имейте в виду, что разные инструменты могут иметь разный уровень поддержки OpenAPI. +Имейте в виду, что разные инструменты могут иметь различные уровни поддержки OpenAPI. -Некоторые из них могут не отображать всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке. +Некоторые из них могут все еще не показывать всю дополнительную информацию, хотя в большинстве случаев, недостающая функция уже запланирована к разработке. /// -Вы можете добавить название query-параметра, используя параметр `title`: +Вы можете добавить `title`: {* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *} @@ -368,109 +366,109 @@ http://localhost:8000/items/ ## Псевдонимы параметров -Представьте, что вы хотите, чтобы параметр был `item-query`. +Представьте, что вы хотите использовать параметр с названием `item-query`. -Как в: +Как в следующем примере: ``` http://127.0.0.1:8000/items/?item-query=foobaritems ``` -Но `item-query` не является допустимым именем переменной в Python. +Но `item-query` является невалидным именем переменной в Python. -Ближайшее к нему было бы `item_query`. +Наиболее похожее валидное имя `item_query`. -Но вам все еще нужно, чтобы он был именно `item-query`... +Но вам всё равно необходимо использовать `item-query`… -Тогда вы можете объявить `псевдоним`, и этот псевдоним будет использоваться для поиска значения параметра: +Тогда вы можете объявить `псевдоним`, и именно он будет использован для поиска значения параметра: {* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *} ## Устаревшие параметры -Теперь предположим, вам больше не нравится этот параметр. +Теперь допустим, что вам больше не нравится этот параметр. -Вы должны оставить его на некоторое время, потому что клиенты все еще его используют, но вы хотите, чтобы в документации он явно отображался как устаревший. +Вы должны оставить его на некоторое время, поскольку есть клиенты, которые его используют, но вы хотите, чтобы в документации он ясно показывался как устаревший. -Затем передайте параметр `deprecated=True` в `Query`: +Тогда передайте параметр `deprecated=True` метод `Query`: {* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *} -Документация будет отображать это так: +В документации это будет отображено следующим образом: ## Исключение параметров из OpenAPI -Чтобы исключить query-параметр из сгенерированной схемы OpenAPI (и, следовательно, из системы автоматической документации), установите параметр `include_in_schema` для `Query` в `False`: +Чтобы исключить query-параметр из сгенерированной схемы OpenAPI (и таким образом, из системы автоматической документации), установите параметр `include_in_schema` в `Query` равным `False`: {* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *} -## Кастомная валидация +## Пользовательская валидация -Могут быть случаи, когда вам нужно исполнить **кастомную валидацию**, которую нельзя выполнить с использованием только параметров, описанных выше. +Могут быть случаи, когда вам нужно сделать какую-либо **пользовательскую валидацию**, которую нельзя осуществить с помощью вышеуказанных параметров. -В таких сценариях, вы можете использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки значения на совпадение с `str`). +В этих случаях вы можете использовать **функцию пользовательского валидатора**, которая будет применяться после нормальной валидации (например, после проверки, что значение `str`). Это можно сделать, используя `AfterValidator` из Pydantic внутри `Annotated`. /// tip | Подсказка -Pydantic также имеет `BeforeValidator` и другие. 🤓 +Pydantic также предоставляет `BeforeValidator` и другие. 🤓 /// -Например, следующий кастомный валидатор проверяет, начинается ли ID статьи с `isbn-` (для международного стандартного номера книги ISBN) или с `imdb-` (для URL-идентификатора фильма на IMDb): +Например, этот пользовательский валидатор проверяет, что ID элемента начинается с `isbn-` для номера книги по ISBN или с `imdb-` для ID URL фильма по IMDB: {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *} -/// info | Дополнительная информация +/// info | Информация -Это доступно начиная с версии Pydantic 2 или выше. 😎 +Это доступно в версии Pydantic 2 или выше. 😎 /// /// tip | Подсказка -Если вам нужно выполнить валидацию, которая требует связи с **внешним компонентом**, например с базой данных или другим API, используйте **FastAPI Dependencies**. Вы узнаете о них позже. +Если вам нужно выполнить какую-либо валидацию, которая требует связи с каким-либо **внешним компонентом**, например, базой данных или другим API, вам следует вместо этого использовать **FastAPI Dependencies**, вы узнаете о них позже. -Эти кастомные валидаторы предназначены для выполнения проверок, которые можно осуществить, используя **исключительно** **те же данные**, переданные в запросе. +Эти пользовательские валидаторы предназначены для вещей, которые можно проверить только с использованием **тех же данных**, предоставленных в запросе. /// -### Понимание кода +### Понять этот код -Основное — это использование **`AfterValidator` с функцией внутри `Annotated`**. Если вы хотите, вы можете пропустить эту часть. 🤸 +Основным пунктом является использование **`AfterValidator` с функцией внутри `Annotated`**. Не стесняйтесь пропустить эту часть. 🤸 --- -Но если вам интересно или вы всё ещё намерены продолжить, вот несколько дополнительных подробностей. +Но если вам интересно рассмотреть этот пример кода, который все еще вызывает интерес, вот несколько дополнительных деталей. #### Строка с `value.startswith()` -Обратили внимание? строка, использующая `value.startswith()`, может принять кортеж, и она проверит каждое значение в кортеже: +Заметили? Строка, использующая `value.startswith()`, может принимать кортеж, и проверит каждое значение в кортеже: {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *} -#### Случайный предмет +#### Случайный элемент -С `data.items()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. +С `data.items()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. -Мы преобразуем этот итерируемый объект в обычный `list` с помощью `list(data.items())`. +Мы преобразуем этот итерируемый объект в настоящий `list` с `list(data.items())`. -Затем через `random.choice()` мы можем получить **случайное значение** из списка, это будет кортеж `(id, name)`. Пример: `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`. +Тогда, с помощью `random.choice()` можем получить **случайное значение** из списка, так мы получаем кортеж `(id, name)`. Он будет чем-то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`. -Потом мы **присваиваем эти два значения** из кортежа переменным `id` и `name`. +Затем мы **присваиваем эти два значения** из кортежа переменным `id` и `name`. -Так, если пользователь не передал ID элемента, они всё равно получат случайное предложение. +Так что, если пользователь не предоставил ID элемента, они получат случайную рекомендацию. -...всё это выполняется в одной **простой строке**. 🤯 Разве вы не любите Python? 🐍 +...мы выполняем все это в **одной простой строке**. 🤯 Разве Python не потрясающий? 🐍 {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *} ## Резюме -Вы можете объявлять дополнительные правила валидации и метаданные для ваших параметров. +Вы можете объявлять дополнительные валидации и метаданные для ваших параметров. Общие валидации и метаданные: @@ -479,14 +477,14 @@ Pydantic также имеет `http.HTTPStatus`. +В качестве значения параметра `status_code` также может использоваться `IntEnum`, например, из библиотеки `http.HTTPStatus` в Python. /// Это позволит: * Возвращать указанный код статуса в ответе. -* Документировать его как таковой в OpenAPI схеме (а значит, и в пользовательском интерфейсе): +* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательском интерфейсе): /// note | Примечание -Некоторые коды ответа (см. следующий раздел) указывают, что ответа с телом не будет. +Некоторые коды статуса ответа (см. следующий раздел) указывают на то, что ответ не имеет тела. -FastAPI знает об этом и создаст документацию OpenAPI, которая укажет, что тело ответа отсутствует. +FastAPI знает об этом и создаст документацию OpenAPI, в которой будет указано, что тело ответа отсутствует. /// -## Об HTTP статус-кодах +## Об HTTP кодах статуса ответа /// note | Примечание -Если вы уже знаете, что такое HTTP статус-коды, можете пропустить этот раздел. +Если вы уже знаете, что представляют собой HTTP коды статуса ответа, можете перейти к следующему разделу. /// -В HTTP вы отправляете числовой код состояния из 3 цифр как часть ответа. +В протоколе HTTP числовой код состояния из 3 цифр отправляется как часть ответа. -У этих кодов статуса есть связанные с ними названия для их распознавания, но важна именно числовая часть. +У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения. -Кратко о значениях: +Кратко о значениях кодов: -* `100 - 199` — это информационные коды. Вы редко используете их напрямую. Ответы с этими кодами не должны содержать тело. -* **`200 - 299`** — это успешные ответы. Эти вы будете использовать чаще всего. - * `200` — это код по умолчанию, который означает, что все прошло "OK". - * Другой пример — `201`, "Created". Он часто используется после создания новой записи в базе данных. - * Особый случай — `204`, "No Content". Этот ответ используется, когда нет содержимого для возврата клиенту, и поэтому тело отсутствует. -* **`300 - 399`** — это коды перенаправлений. Ответы с этими кодами статуса могут, а могут и не иметь тело, за исключением `304`, "Not Modified", у которого его не должно быть. -* **`400 - 499`** — это ошибки клиента. Это вторая группа, которую вы, вероятно, будете использовать чаще всего. - * Пример — `404`, для ответа "Not Found". - * Для общих ошибок клиента можно использовать просто `400`. -* `500 - 599` — это ошибки сервера. Вы почти никогда не используете их напрямую. Когда что-то идет не так в коде вашего приложения или на сервере, он автоматически возвращает один из этих кодов. +* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела. +* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего. + * `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK". + * Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных. + * Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела. +* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела. +* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория. + * Пример – код `404` для статуса "Not Found". + * Для общих ошибок со стороны клиента можно просто использовать код `400`. +* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов. -/// tip | Совет +/// tip | Подсказка -Чтобы узнать больше о каждом статус-коде и для чего он предназначен, ознакомьтесь с документацией MDN об HTTP кодах статуса. +Чтобы узнать больше о HTTP статус-кодах и о том, для чего каждый из них предназначен, ознакомьтесь с документацией MDN об HTTP кодах статуса ответа. /// -## Удобные сокращения для запоминания названий +## Краткие обозначения для запоминания названий кодов -Давайте еще раз рассмотрим предыдущий пример: +Рассмотрим предыдущий пример еще раз: {* ../../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] *} -Они содержат те же числовые значения, но позволяют использовать авто-завершение редактора для выбора кода статуса: +Они содержат те же числовые значения, но позволяют использовать подсказки редактора для выбора кода статуса: /// note | Технические детали -Вы также можете использовать `from starlette import status`. +Вы также можете использовать `from starlette import status` вместо `from fastapi import status`. -**FastAPI** предоставляет `starlette.status` как `fastapi.status` исключительно для удобства разработчиков. Однако он поставляется непосредственно из Starlette. +**FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette. /// -## Изменение кода по умолчанию +## Изменение кода статуса по умолчанию -Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP код статуса, отличный от используемого здесь кода по умолчанию. +Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP коды статуса, отличные от используемого здесь кода статуса по умолчанию. diff --git a/docs/ru/docs/tutorial/sql-databases.md b/docs/ru/docs/tutorial/sql-databases.md index 149281347..b127e44d5 100644 --- a/docs/ru/docs/tutorial/sql-databases.md +++ b/docs/ru/docs/tutorial/sql-databases.md @@ -1,40 +1,40 @@ # SQL (реляционные) базы данных -**FastAPI** не требует от вас использования реляционной базы данных. Но вы можете использовать **любую базу данных**, которую захотите. +**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которой хотите. -Здесь мы увидим пример, использующий SQLModel. +В этом разделе мы продемонстрируем, как работать с SQLModel. -**SQLModel** построен на основе SQLAlchemy и Pydantic. Он был создан автором **FastAPI** и является идеальным выбором для приложений FastAPI, которые нуждаются в реляционных базах данных. +Библиотека **SQLModel** построена на основе SQLAlchemy и Pydantic. Она была разработана автором **FastAPI** специально для приложений на основе FastAPI, которые используют **реляционные базы данных**. -/// tip | Совет +/// tip | Подсказка -Вы можете использовать любую другую библиотеку для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных, в некоторых случаях называемую "ORMs". FastAPI не заставляет вас использовать что-то конкретное. 😎 +Вы можете воспользоваться любой библиотекой для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных. (Их ещё называют **ORM** библиотеками). FastAPI не принуждает вас к использованию чего-либо конкретного. 😎 /// -Поскольку SQLModel основан на SQLAlchemy, вы можете легко использовать **любую базу данных, поддерживаемую** SQLAlchemy (соответственно поддерживаемую SQLModel), например: +В основе SQLModel лежит SQLAlchemy, поэтому вы спокойно можете использовать любую базу данных, поддерживаемую SQLAlchemy (и, соответственно, поддерживаемую SQLModel), например: * PostgreSQL * MySQL * SQLite * Oracle -* Microsoft SQL Server и т. д. +* Microsoft SQL Server, и т.д. -В этом примере мы будем использовать базу данных **SQLite**, потому что она использует один файл, и поддержка Python встроена. Таким образом, вы можете скопировать этот пример и запустить его как есть. +В данном примере мы будем использовать базу данных **SQLite**, т.к. она состоит из единственного файла и поддерживается встроенными библиотеками Python. Таким образом, вы сможете скопировать данный пример и запустить его как он есть. -В дальнейшем, для продакшн-версии вашего приложения, возможно, вам стоит использовать серверную базу данных, такую как **PostgreSQL**. +В дальнейшем, для продакшн-версии вашего приложения, возможно, вам стоит использовать серверную базу данных, например, **PostgreSQL**. -/// tip | Совет +/// tip | Подсказка -Существует официальный генератор проектов с **FastAPI** и **PostgreSQL**, включая frontend и другие инструменты: https://github.com/fastapi/full-stack-fastapi-template +Существует официальный генератор проектов на **FastAPI** и **PostgreSQL**, который также включает frontend и дополнительные инструменты https://github.com/fastapi/full-stack-fastapi-template /// -Это очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, об SQL или более продвинутых возможностях, обратитесь к документации SQLModel. +Это очень простое и короткое руководство, поэтому, если вы хотите узнать о базах данных в целом, об SQL, разобраться с более продвинутым функционалом, то воспользуйтесь документацией SQLModel. ## Установка `SQLModel` -Сначала убедитесь, что вы создали свое [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили `sqlmodel`: +Создайте виртуальное окружение [virtual environment](../virtual-environments.md){.internal-link target=_blank}, активируйте его и установите `sqlmodel`:
@@ -45,11 +45,11 @@ $ pip install sqlmodel
-## Создание приложения с одной моделью +## Создание приложения с единственной моделью -Мы сначала создадим самую простую версию приложения с одной моделью **SQLModel**. +Мы начнем с создания наиболее простой первой версии нашего приложения с одной единственной моделью **SQLModel**. -Позже мы улучшим его, повысив безопасность и универсальность за счет **нескольких моделей** ниже. 🤓 +В дальнейшем с помощью **дополнительных моделей** мы его улучшим и сделаем более безопасным и универсальным. 🤓 ### Создание моделей @@ -57,97 +57,98 @@ $ pip install sqlmodel {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *} -Класс `Hero` очень похож на модель Pydantic (по сути, под капотом, это действительно *модель Pydantic*). +Класс `Hero` очень напоминает модель Pydantic (фактически, под капотом, *это и есть модель Pydantic*). -Но есть несколько различий: +Но есть и некоторые различия -* `table=True` говорит SQLModel, что это *модель таблицы*, она должна представлять **таблицу** в реляционной базе данных, это не просто *модель данных* (в отличие от обычного класса Pydantic). +* `table=True` для SQLModel означает, что это *модель-таблица*, которая должна представлять **таблицу** в реляционной базе данных. Это не просто *модель данных* (в отличие от обычного класса в Pydantic). -* `Field(primary_key=True)` говорит SQLModel, что `id` является **первичным ключом** в базе данных SQL (более подробно о первичных ключах SQL можно узнать в документации SQLModel). +* `Field(primary_key=True)` для SQLModel означает, что поле `id` является первичным ключом в таблице базы данных (вы можете подробнее узнать о первичных ключах баз данных в документации по SQLModel). - Тип `int | None` сообщает SQLModel, что этот столбец должен быть `INTEGER` в базе данных SQL и что он должен быть `NULLABLE`. + Тип `int | None` сигнализирует для SQLModel, что столбец таблицы базы данных должен иметь тип `INTEGER`, или иметь пустое значение `NULL`. -* `Field(index=True)` говорит SQLModel, что он должен создать **SQL индекс** для этого столбца, что позволит ускорить поиск в базе данных при чтении данных, отфильтрованных по этому столбцу. +* `Field(index=True)` для SQLModel означает, что нужно создать **SQL индекс** для данного столбца. Это обеспечит более быстрый поиск при чтении данных, отфильтрованных по данному столбцу. - SQLModel будет знать, что нечто объявленное как `str` будет SQL-столбцом типа `TEXT` (или `VARCHAR`, в зависимости от базы данных). + SQLModel будет знать, что данные типа `str`, будут представлены в базе данных как `TEXT` (или `VARCHAR`, в зависимости от типа базы данных). -### Создание подключения +### Создание соединения с базой данных (Engine) -Объект `engine` в SQLModel (по сути это `Engine` из SQLAlchemy) **удерживает соединения** с базой данных. +В SQLModel объект соединения `engine` (по сути это `Engine` из SQLAlchemy) **содержит пул соединений** к базе данных. -Для обеспечения всех подключений приложения к одной базе данных существует **единственный объект `engine`**. +Для обеспечения всех подключений приложения к одной базе данных нужен только один объект соединения `engine`. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *} -Использование `check_same_thread=False` позволяет FastAPI использовать одну и ту же SQLite базу данных в различных потоках. Это необходимо, так как **один запрос** может использовать **более одного потока** (например, в зависимостях). +Использование настройки `check_same_thread=False` позволяет FastAPI использовать одну и ту же SQLite базу данных в различных потоках (threads). Это необходимо, когда **один запрос** использует **более одного потока** (например, в зависимостях). -Не беспокойтесь, с такой структурой кода, мы позаботимся о том, чтобы использовать **отдельную *сессию* SQLModel для каждого запроса** позже, именно это и пытается достичь `check_same_thread`. +Не беспокойтесь, учитывая структуру кода, мы позже позаботимся о том, чтобы использовать **отдельную SQLModel-сессию на каждый отдельный запрос**, это как раз то, что пытается обеспечить `check_same_thread`. ### Создание таблиц -Далее мы добавляем функцию, использующую `SQLModel.metadata.create_all(engine)`, для того чтобы создать **таблицы** для всех **моделей таблиц**. +Далее мы добавляем функцию, использующую `SQLModel.metadata.create_all(engine)`, для того, чтобы создать **таблицы** для каждой из **моделей таблицы**. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *} ### Создание зависимости Session -Сессия базы данных (**`Session`**) хранит **объекты в памяти** и отслеживает любые изменения в данных, затем она **использует `engine`** для связи с базой данных. +Сессия базы данных (**`Session`**) хранит **объекты в памяти** и отслеживает любые необходимые изменения в данных, а затем **использует `engine`** для коммуникации с базой данных. -Мы создадим зависимость FastAPI с использованием `yield`, которая будет предоставлять новую `Session` для каждого запроса. Это именно то, что обеспечит использование отдельной сессии для каждого запроса. 🤓 +Мы создадим FastAPI-**зависимость** с помощью `yield`, которая будет создавать новую сессию (Session) для каждого запроса. Это как раз и обеспечит использование отдельной сессии на каждый отдельный запрос. 🤓 -Затем мы создадим объявленную зависимость `SessionDep`, чтобы упростить остальной код, который будет использовать эту зависимость. +Затем мы создадим объявленную (`Annotated`) зависимость `SessionDep`. Мы сделаем это для того, чтобы упростить остальной код, который будет использовать эту зависимость. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *} -### Создание таблиц базы данных при старте приложения +### Создание таблиц базы данных при запуске приложения -Мы создадим таблицы базы данных при запуске приложения. +Мы будем создавать таблицы базы данных при запуске приложения. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *} -Здесь мы создаём таблицы на событии начала работы приложения. +В данном примере мы создаем таблицы при наступлении события запуска приложения. -Для продакшн-версии вы, вероятно, будете использовать скрипт миграции базы данных, который выполняется перед запуском вашего приложения. 🤓 +В продуктовом приложении вы, скорее всего, будете использовать скрипт для миграции базы данных, который выполняется перед запуском приложения. 🤓 -/// tip | Совет +/// tip | Подсказка -В SQLModel будут включены утилиты для миграции на основе Alembic, но пока вы можете использовать Alembic напрямую. +В SQLModel будут включены утилиты миграции, входящие в состав Alembic, но на данный момент вы просто можете использовать +Alembic напрямую. /// -### Создание героя +### Создание героя (Hero) -Поскольку каждая модель в SQLModel также является моделью Pydantic, вы можете использовать её в тех же **аннотациях типов**, что и модели Pydantic. +Каждая модель в SQLModel является также моделью Pydantic, поэтому вы можете использовать её при **объявлении типов**, точно также, как и модели Pydantic. -Например, если вы объявите параметр типа `Hero`, он будет прочитан из **тела JSON**. +Например, при объявлении параметра типа `Hero`, она будет считана из **тела JSON**. -Точно так же, вы можете объявить его как **возвращаемый тип функции**, и тогда форма данных будет отображаться в интерфейсе автоматической документации API. +Точно также, вы можете использовать её при объявлении типа значения, возвращаемого функцией, и тогда структурированные данные будут отображены через пользовательский интерфейс автоматически сгенерированной документации FastAPI. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} -Здесь мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их. +Мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их. -### Чтение данных героев +### Чтение данных о героях -Мы можем **читать** данных героев из базы данных, используя `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов. +Мы можем **читать** данные героев из базы данных с помощью `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *} -### Чтение данных одного героя +### Чтение данных отдельного героя -Мы можем **читать** данные одного героя. +Мы можем прочитать данные отдельного героя (`Hero`). {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *} -### Удаление героя +### Удаление данных героя -Мы можем также **удалить** героя. +Мы также можем удалить героя `Hero` из базы данных. {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *} ### Запуск приложения -Вы можете запустить приложение: +Вы можете запустить приложение следующим образом:
@@ -159,49 +160,49 @@ $ fastapi dev main.py
-Затем перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также для **сериализации** и **проверки** данных. +Далее перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует модели для создания документации API. Эти же модели используются для сериализации и проверки данных.
-## Обновление приложения с несколькими моделями +## Добавление в приложение дополнительных (вспомогательных) моделей -Теперь давайте немного **отрефакторим** это приложение, чтобы повысить его **безопасность** и **универсальность**. +Теперь давайте проведём **рефакторинг** нашего приложения, чтобы сделать его более безопасным и более универсальным. -Если вы посмотрите на предыдущее приложение, в UI вы увидите, что до сих пор оно позволяет клиенту задавать `id` создаваемого героя (`Hero`). 😱 +Обратите внимание, что на данном этапе наше приложение позволяет на уровне клиента определять `id` создаваемого героя (`Hero`). 😱 -Нам нельзя допускать этого, так как они могут перезаписать `id`, который у нас уже есть в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда** или **на уровне базы данных**, **не на уровне клиента**. +Мы не можем этого допустить, т.к. существует риск переписать уже присвоенные `id` в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда (backend)** или **на уровне базы данных**, но никак **не на уровне клиента**. -Кроме того, мы создаём `secret_name` для героя, но на данный момент мы возвращаем его везде, и это не очень **секретно**... 😅 +Кроме того, мы создаем секретное имя `secret_name` для героя, но пока что, мы возвращаем его повсеместно, и это слабо напоминает **секретность**... 😅 -Мы исправим это, добавив несколько **дополнительных моделей**. Вот где SQLModel действительно засияет. ✨ +Мы поправим это с помощью нескольких дополнительных (вспомогательных) моделей. Вот где SQLModel по-настоящему покажет себя. ✨ -### Создание нескольких моделей +### Создание дополнительных моделей -В **SQLModel** любая модель класса, содержащая `table=True`, является **моделью таблицы**. +В **SQLModel**, любая модель с параметром `table=True` является **моделью таблицы**. -А любая модель класса без `table=True` является **моделью данных**, они на самом деле представляют собой модели Pydantic (с несколькими небольшими дополнительными возможностями). 🤓 +Любая модель, не содержащая `table=True` является **моделью данных**, это по сути обычные модели Pydantic (с несколько расширенным функционалом). 🤓 -С помощью SQLModel мы можем использовать **наследование**, чтобы **избежать дублирования** всех полей во всех случаях. +С помощью SQLModel мы можем использовать **наследование**, что поможет нам **избежать дублирования** всех полей. -#### `HeroBase` - базовый класс +#### Базовый класс `HeroBase` -Начнем с модели `HeroBase`, которая имеет все **общие поля** для всех моделей: +Давайте начнём с модели `HeroBase`, которая содержит поля, общие для всех моделей: * `name` * `age` {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *} -#### `Hero` - *модель таблицы* +#### Модель таблицы `Hero` -Затем создадим `Hero`, это фактическая *модель таблицы*, с **дополнительными полями**, которых может не быть в других моделях: +Далее давайте создадим **модель таблицы** `Hero` с дополнительными полями, которых может не быть в других моделях: * `id` * `secret_name` -Так как `Hero` наследует от `HeroBase`, он **также** содержит **поля**, объявленные в `HeroBase`, так что все поля для `Hero` следующие: +Модель `Hero` наследует от `HeroBase`, и поэтому включает также поля из `HeroBase`. Таким образом, все поля, содержащиеся в `Hero`, будут следующими: * `id` * `name` @@ -210,25 +211,25 @@ $ fastapi dev main.py {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *} -#### `HeroPublic` - публичная *модель данных* +#### Публичная модель данных `HeroPublic` -Далее создаём модель `HeroPublic`, это модель, которая будет **возвращаться** клиентам API. +Далее мы создадим модель `HeroPublic`. Мы будем возвращать её клиентам API. -Она имеет те же поля, что и `HeroBase`, поэтому не будет включать `secret_name`. +Она включает в себя те же поля, что и `HeroBase`, и, соответственно, поле `secret_name` в ней отсутствует. -Наконец-то личности наших героев защищены! 🥷 +Наконец-то личность наших героев защищена! 🥷 -Также она повторном объявляет `id: int`. Таким образом мы устанавливаем **договоренность** с клиентами API, что они всегда могут ожидать наличие `id` и то, что это будет `int` (оно никогда не будет `None`). +В модели `HeroPublic` также объявляется поле `id: int`. Мы как бы заключаем договоренность с API клиентом, на то, что передаваемые данные всегда должны содержать поле `id`, и это поле должно содержать целое число (и никогда не содержать `None`). -/// tip | Совет +/// tip | Подсказка -Наличие в модели возврата гарантии того, что значение всегда будет доступно и будет `int` (не `None`), очень полезно для API-клиентов, они могут писать более простой код с этой уверенностью. +Модель ответа, гарантирующая наличие поля со значением типа `int` (не `None`), очень полезна при разработке API клиентов. Определенность в передаваемых данных может обеспечить написание более простого кода. -Кроме того, автоматически сгенерированные клиенты будут иметь более простые интерфейсы, так что разработчикам, работающим с вашим API, будет значительно проще. 😎 +Также **автоматически генерируемые клиенты** будут иметь более простой интерфейс. И в результате жизнь разработчиков, использующих ваш API, станет значительно легче. 😎 /// -Все поля в `HeroPublic` такие же, как в `HeroBase`, с `id`, объявленным как `int` (не `None`): +`HeroPublic` содержит все поля `HeroBase`, а также поле `id`, объявленное как `int` (не `None`): * `id` * `name` @@ -236,23 +237,23 @@ $ fastapi dev main.py {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *} -#### `HeroCreate` - *модель данных* для создания героя +#### Модель для создания героя `HeroCreate` -Сейчас мы создаём модель `HeroCreate`. Это модель, которая будет **проверять** данные от клиентов. +Сейчас мы создадим модель `HeroCreate`. Эта модель будет использоваться для проверки данных, переданных клиентом. -Она содержит те же поля, что и `HeroBase`, а также `secret_name`. +Она содержит те же поля, что и `HeroBase`, а также поле `secret_name`. -Теперь, когда клиенты **создают нового героя**, они отправят `secret_name`, он будет сохранён в базе данных, но эти секретные имена не будут возвращаться в API клиентам. +Теперь, при создании нового героя, клиенты будут передавать секретное имя `secret_name`, которое будет сохранено в базе данных, но не будет возвращено в ответе API клиентам. -/// tip | Совет +/// tip | Подсказка -Это то, как вы должны обрабатывать **пароли**: получайте их, но не возвращайте их в API. +Вот как нужно работать с **паролями**: получайте их, но не возвращайте их через API. -Также **хешируйте** значения паролей перед их сохранением, **никогда не храните их в открытом виде**. +Также хэшируйте значения паролей перед тем, как их сохранить. Ни в коем случае не храните пароли в открытом виде, как обычный текст. /// -Поля `HeroCreate`: +Поля модели `HeroCreate`: * `name` * `age` @@ -260,15 +261,15 @@ $ fastapi dev main.py {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *} -#### Модель для обновления героя `HeroUpdate` +#### Модель для обновления данных героя `HeroUpdate` -В предыдущих версиях нашего приложения у нас не было способа **обновить героя**, но теперь с **несколькими моделями** мы можем это сделать. 🎉 +В предыдущих версиях нашей программы мы не могли обновить данные героя, теперь, воспользовавшись дополнительными моделями, мы сможем это сделать. 🎉 -*Данные модели* `HeroUpdate` несколько особенные, у них есть **все те же поля**, которые потребуются для создания нового героя, но все поля **необязательны** (они все имеют значение по умолчанию). Таким образом, при обновлении героя вы можете отправить только те поля, которые хотите обновить. +Модель данных `HeroUpdate` в некотором смысле особенная. Она содержит все те же поля, что и модель создания героя, но все поля модели являются **необязательными**. (Все они имеют значение по умолчанию.) Таким образом, при обновлении данных героя, вам достаточно передать только те поля, которые требуют изменения. -Поскольку **все поля фактически изменяются** (тип теперь включает `None` и теперь у них значение по умолчанию `None`), мы должны их **объявить заново**. +Поскольку **все поля по сути меняются** (теперь тип каждого поля допускает значение `None` и значение по умолчанию `None`), мы должны их **объявить заново**. -Нам не нужно наследовать от `HeroBase` потому что мы все равно повторном объявляем все поля. Я оставлю наследование просто для поддержания общего стиля, но это необязательно. Это скорее дело вкуса. 🤷 +Фактически, нам не нужно наследоваться от `HeroBase`, потому что мы будем заново объявлять все поля. Я оставлю наследование просто для поддержания общего стиля, но оно (наследование) здесь необязательно. 🤷 Поля `HeroUpdate`: @@ -278,59 +279,59 @@ $ fastapi dev main.py {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *} -### Создание с помощью `HeroCreate` и возврат `HeroPublic` +### Создание героя с помощью `HeroCreate` и возвращение результатов с помощью `HeroPublic` -Теперь, когда у нас есть **несколько моделей**, мы можем обновить части приложения, которые их используют. +Теперь, когда у нас есть дополнительные модели, мы можем обновить те части приложения, которые их используют. -Мы получаем в запросе модель данных `HeroCreate`, и из нее создаём модель таблицы `Hero`. +Вместе c запросом на создание героя мы получаем объект данных `HeroCreate`, и создаем на его основе объект модели таблицы `Hero`. -Эта новая модель таблицы `Hero` будет иметь поля, отправленные клиентом, а также `id`, сгенерированное базой данных. +Созданный объект *модели таблицы* `Hero` будет иметь все поля, переданные клиентом, а также поле `id`, сгенерированное базой данных. -Затем возвращаем ту же модель таблицы `Hero` как есть из функции. Но так как мы объявляем `response_model` с моделью данных `HeroPublic`, **FastAPI** будет использовать `HeroPublic` для проверки и сериализации данных. +Далее функция вернёт объект *модели таблицы* `Hero`. Но поскольку, мы объявили `HeroPublic` как модель ответа, то **FastAPI** будет использовать именно её для проверки и сериализации данных. {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *} -/// tip | Совет +/// tip | Подсказка -Теперь мы используем `response_model=HeroPublic` вместо аннотации **возвращаемого типа** `-> HeroPublic`, потому что значение, которое мы возвращаем, **на самом деле не** `HeroPublic`. +Теперь мы используем модель ответа `response_model=HeroPublic`, вместо того, чтобы объявить тип возвращаемого значения как `-> HeroPublic`. Мы это делаем потому, что тип возвращаемого значения не относится к `HeroPublic`. -Если бы мы объявили `-> HeroPublic`, ваш редактор и линтер бы пожаловались (и справедливо), что вы возвращаете `Hero`, а не `HeroPublic`. +Если бы мы объявили тип возвращаемого значения как `-> HeroPublic`, то редактор и линтер начали бы ругаться (и вполне справедливо), что возвращаемое значение принадлежит типу `Hero`, а совсем не `HeroPublic`. -Объявляя это в `response_model`, мы говорим **FastAPI** делать свое дело, не вмешиваясь в аннотации типов и не полагаясь на помощь редактора и других инструментов. +Объявляя модель ответа в `response_model`, мы как бы говорим **FastAPI**: делай свое дело, не вмешиваясь в аннотацию типов и не полагаясь на помощь редактора или других инструментов. /// -### Чтение героев с `HeroPublic` +### Чтение данных героев с помощью `HeroPublic` -Мы можем сделать то же самое, как и раньше для **чтения** данных героев, используя `response_model=list[HeroPublic]`, чтобы обеспечить правильную валидацию и сериализацию данных. +Мы можем проделать то же самое **для чтения данных** героев. Мы применим модель ответа `response_model=list[HeroPublic]`, и тем самым обеспечим правильную проверку и сериализацию данных. {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *} -### Чтение данных одного героя с `HeroPublic` +### Чтение данных отдельного героя с помощью `HeroPublic` -Мы можем **читать** данные одного героя: +Мы можем **прочитать** данные отдельного героя: {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *} -### Обновление героя с помощью `HeroUpdate` +### Обновление данных героя с помощью `HeroUpdate` -Мы можем **обновить героя**. Для этого мы используем HTTP-операцию `PATCH`. +Мы можем **обновить данные героя**. Для этого мы воспользуемся HTTP методом `PATCH`. -И в коде мы получаем объект `dict` со всеми данными, отправленными клиентом, содержанием **только данных, отправленных клиентом**, исключая любые значения, которые могут быть там только как значения по умолчанию. Для этого мы используем `exclude_unset=True`. Это главный трюк. 🪄 +В коде мы получаем объект словаря `dict` с данными, переданными клиентом (т.е. **только c данными, переданными клиентом**, исключая любые значения, которые могли бы быть там только потому, что они являются значениями по умолчанию). Для того чтобы сделать это, мы воспользуемся опцией `exclude_unset=True`. В этом главная хитрость. 🪄 -Затем используем `hero_db.sqlmodel_update(hero_data)`, чтобы обновить `hero_db` данными из `hero_data`. +Затем мы применим `hero_db.sqlmodel_update(hero_data)`, и обновим `hero_db`, использовав данные `hero_data`. {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *} -### Удаление героя снова +### Удалим героя ещё раз -Операция **удаления** героя остаётся практически неизменной. +Операция **удаления** героя практически не меняется. -В этом случае желание *`отрефакторить всё`* остаётся неудовлетворённым. 😅 +В данном случае желание *`отрефакторить всё`* остаётся неудовлетворенным. 😅 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} -### Снова запуск приложения +### Снова запустим приложение Вы можете снова запустить приложение: @@ -344,7 +345,7 @@ $ fastapi dev main.py
-Если вы пойдете в пользовательский интерфейс API `/docs`, вы увидите, что он обновлен и больше не ожидает получение параметра `id` от клиента при создании нового героя и т.д. +Если вы перейдете в пользовательский интерфейс API `/docs`, то вы увидите, что он был обновлен, и больше не принимает параметра `id` от клиента при создании нового героя, и т.д.
@@ -352,6 +353,6 @@ $ fastapi dev main.py ## Резюме -Вы можете использовать **SQLModel** для взаимодействия с реляционной базой данных и упрощения кода с *моделями данных* и *моделями таблиц*. +Вы можете использовать **SQLModel** для взаимодействия с реляционными базами данных, а также для упрощения работы с **моделями данных** и **моделями таблиц**. -Вы можете узнать гораздо больше в документации **SQLModel**, там есть более длительное мини руководство по использованию SQLModel с **FastAPI**. 🚀 +Вы можете узнать гораздо больше информации в документации по **SQLModel**. Там вы найдете более подробное мини-руководство по использованию SQLModel с **FastAPI**. 🚀 diff --git a/docs/ru/docs/virtual-environments.md b/docs/ru/docs/virtual-environments.md index d5a1e271d..3a40ddbce 100644 --- a/docs/ru/docs/virtual-environments.md +++ b/docs/ru/docs/virtual-environments.md @@ -1,28 +1,28 @@ # Виртуальное окружение -Когда вы работаете с проектами на Python, вероятно, вам стоит использовать **виртуальное окружение** (или аналогичный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта. +Когда вы работаете с проектами на Python, рекомендуется использовать **виртуальное окружение** (или подобный механизм) для изоляции пакетов, которые вы устанавливаете для каждого проекта. -/// info | Информация +/// info | Дополнительная информация Если вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓 /// -/// tip | Совет +/// tip | Подсказка **Виртуальное окружение** отличается от **переменной окружения**. -**Переменная окружения** — это системная переменная, которую могут использовать программы. +**Переменная окружения** — это переменная в системе, которую могут использовать программы. **Виртуальное окружение** — это директория с файлами. /// -/// info | Информация +/// info | Дополнительная информация Этот раздел научит вас использовать **виртуальные окружения** и как они работают. -Если вы готовы начать использовать **инструмент, который управляет всем** за вас (включая установку Python), попробуйте uv. +Если вы готовы использовать **инструмент, который управляет всем** за вас (включая установку Python), попробуйте uv. /// @@ -30,22 +30,22 @@ Сначала создайте директорию для вашего проекта. -Обычно я создаю директорию с именем `code` внутри моего домашнего каталога. +Обычно я создаю директорию, названную `code`, внутри моего домашнего каталога `/home/user`. -И внутри этой директории создаю одну папку для каждого проекта. +Затем, внутри этой директории, я создаю отдельную папку для каждого проекта.
```console -// Перейти в домашний каталог +// Перейдите в домашний каталог $ cd -// Создайте директорию для всех ваших проектов с кодом +// Создайте отдельную папку под всё ваше программное обеспечение (code) $ mkdir code -// Войдите в указанную директорию +// Войдите в директорию code $ cd code -// Создайте директорию для этого проекта +// Создайте директорию для данного проекта $ mkdir awesome-project -// Перейдите в эту директорию проекта +// Перейдите в созданную директорию проекта $ cd awesome-project ``` @@ -53,17 +53,17 @@ $ cd awesome-project ## Создание виртуального окружения -Когда вы начинаете работать над Python-проектом **в первый раз**, создайте виртуальное окружение **внутри вашего проекта**. +Когда вы начинаете работать над Python-проектом **впервые**, создайте виртуальное окружение **внутри вашего проекта**. -/// tip | Совет +/// tip | Подсказка -Вы должны сделать это **один раз на проект**, а не каждый раз, когда работаете. +Это нужно сделать **один раз для каждого проекта**, а не каждый раз, когда вы начинаете работу. /// //// tab | `venv` -Чтобы создать виртуальное окружение, вы можете использовать модуль `venv`, который входит в комплект поставки Python. +Для создания виртуального окружения можно использовать модуль `venv`, который встроен в Python.
@@ -73,10 +73,10 @@ $ python -m venv .venv
-/// details | Что делает эта команда +/// details | Что делает эта команда? -* `python`: использовать программу `python` -* `-m`: вызвать модуль как сценарий, далее укажем, какой модуль использовать +* `python`: использовать программу под именем `python` +* `-m`: вызывать модуль как скрипт, в следующей инструкции мы укажем, какой модуль вызвать * `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python * `.venv`: создать виртуальное окружение в новой директории `.venv` @@ -86,7 +86,7 @@ $ python -m venv .venv //// tab | `uv` -Если у вас установлен `uv`, вы можете использовать его для создания виртуального окружения. +Если вы установили `uv`, то вы можете использовать его для создания виртуального окружения.
@@ -96,9 +96,9 @@ $ uv venv
-/// tip | Совет +/// tip | Подсказка -По умолчанию `uv` создаст виртуальное окружение в директории под названием `.venv`. +По умолчанию `uv` создаст виртуальное окружение в папке под названием `.venv`. Но вы можете изменить это, передав дополнительный аргумент с именем директории. @@ -106,21 +106,21 @@ $ uv venv //// -Эта команда создаст новое виртуальное окружение в директории `.venv`. +Эта команда создаст новое виртуальное окружение в папке `.venv`. -/// details | `.venv` или другое имя +/// details | `.venv` или другое имя? -Вы можете создать виртуальное окружение в другой директории, но принято называть его `.venv`. +Вы можете создать виртуальное окружение в другой директории, но традиционное (конвенциональное) название — `.venv`. /// ## Активация виртуального окружения -Активируйте новое виртуальное окружение, чтобы любая команда Python, которую вы запускаете, или пакет, который вы устанавливаете, использовала его. +Активируйте виртуальное окружение, чтобы любая запускаемая команда Python или устанавливаемый пакет использовали его. -/// tip | Совет +/// tip | Подсказка -Делайте это **каждый раз**, начиная **новую сессию терминала** для работы над проектом. +Делайте это **каждый раз**, когда начинаете **новую сессию в терминале**, чтобы работать над проектом. /// @@ -150,7 +150,7 @@ $ .venv\Scripts\Activate.ps1 //// tab | Windows Bash -Или если вы используете Bash для Windows (например, Git Bash): +Если вы используете Bash для Windows (например, Git Bash):
@@ -162,29 +162,13 @@ $ source .venv/Scripts/activate //// -/// tip | Совет - -Каждый раз при установке **нового пакета** в эту среду **активируйте** её снова. - -Это гарантирует, что если вы используете **программу терминала (CLI)**, установленную этим пакетом, вы будете использовать её из вашей виртуальной среды, а не любую другую, установленную глобально, вероятно, с другой версией, чем вам нужно. - -/// - -/// tip | Подсказка - -Каждый раз, когда вы устанавливаете **новый пакет** в этой среде, **активируйте** ее снова. - -Это гарантирует, что если вы используете программу из **терминала (CLI)**, установленную этим пакетом, вы используете ту, что в вашем виртуальном окружении, а не ту, что может быть установлена глобально, с другой версией, чем вам нужно. - -/// - ## Проверка активации виртуального окружения -Проверьте, что виртуальное окружение активно (предыдущая команда сработала). +Проверьте, активировано ли виртуальное окружение (то есть, что предыдущая команда сработала). -/// tip | Совет +/// tip | Подсказка -Это **необязательно**, но хороший способ **убедиться**, что все работает как надо и вы используете то виртуальное окружение, которое хотели. +Эта проверка **необязательна**, но это хороший способ **убедиться**, что все работает, как ожидается, и вы используете нужное вам виртуальное окружение. /// @@ -200,7 +184,7 @@ $ which python
-Если путь указывает на бинарный файл `python` в `.venv/bin/python`, внутри вашего проекта (в нашем случае это `awesome-project`), значит все сработало. 🎉 +Если показывается бинарный файл `python` в `.venv/bin/python`, внутри вашего проекта (в данном случае `awesome-project`), это значит, что все сработало. 🎉 //// @@ -216,29 +200,29 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
-Если путь указывает на бинарный файл `python` в `.venv\Scripts\python`, внутри вашего проекта (в нашем случае это `awesome-project`), значит все сработало. 🎉 +Если показывается бинарный файл `python` в `.venv\Scripts\python`, внутри вашего проекта (в данном случае `awesome-project`), это значит, что все сработало. 🎉 //// ## Обновление `pip` -/// tip | Совет +/// tip | Подсказка -Если вы используете `uv` для установки пакетов, вам не нужно обновлять `pip`. 😎 +Если вы используете `uv`, вы должны будете использовать его для установки пакетов вместо `pip`, поэтому обновлять `pip` ненужно. 😎 /// -Если вы используете `pip` для установки пакетов (он идет по умолчанию вместе с Python), для начала обновите его до последней версии. +Если вы используете `pip` для установки пакетов (он устанавливается по умолчанию вместе с Python), обновите его до последней версии. Многие экзотические ошибки при установке пакетов решаются простым обновлением `pip`. -/// tip | Совет +/// tip | Подсказка Обычно это делается **один раз**, сразу после создания виртуального окружения. /// -Убедитесь, что виртуальное окружение активно (с помощью вышеуказанной команды), и затем запустите: +Убедитесь, что виртуальное окружение активно (при помощи команды выше) и запустите:
@@ -252,17 +236,17 @@ $ python -m pip install --upgrade pip ## Добавление `.gitignore` -Если вы используете **Git** (и вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить всё из директории `.venv` из Git. +Если вы используете **Git** (и вам стоит это делать), добавьте файл `.gitignore` и исключите всё в `.venv` из Git. -/// tip | Совет +/// tip | Подсказка -Если вы использовали `uv` для создания виртуального окружения, оно уже это сделало за вас, вы можете пропустить этот шаг. 😎 +Если вы использовали `uv` для создания виртуального окружения, то он уже сделал это за вас, и вы можете пропустить этот шаг. 😎 /// -/// tip | Совет +/// tip | Подсказка -Сделайте это **один раз**, сразу после создания виртуального окружения. +Делайте это **один раз** после создания виртуального окружения. /// @@ -274,15 +258,15 @@ $ echo "*" > .venv/.gitignore
-/// details | Что значит эта команда +/// details | Что делает эта команда? -* `echo "*"`: "выведет" текст `*` в терминал (следующая часть немного это изменит) -* `>`: всё, что печатается командой слева от `>`, не должно быть выведено, а записано в файл справа от `>` +* `echo "*"`: напечатает текст `*` в терминале (следующая часть изменит это) +* `>`: всё, что будет напечатано в терминал командой с левой стороны от `>`, не печатать, а вместо этого записать в файл, который указан справа от `>` * `.gitignore`: имя файла, в который должен быть записан текст -А `*` для Git означает "всё". То есть будут проигнорированы все содержимое директории `.venv`. +А `*` в Git означает "всё". Следовательно, будет проигнорировано всё, что содержится в директории `.venv`. -Эта команда создаст файл `.gitignore` с содержимым: +Эта команда создаст файл `.gitignore` со следующим содержимым: ```gitignore * @@ -292,23 +276,23 @@ $ echo "*" > .venv/.gitignore ## Установка пакетов -После активации окружения вы можете устанавливать в него пакеты. +После активации окружения вы можете установить в него пакеты. -/// tip | Совет +/// tip | Подсказка -Сделайте это **один раз** при установке или обновлении пакетов, нужных вашему проекту. +Сделайте это **один раз**, при установке или обновлении пакетов, необходимых вашему проекту. -Если вам нужно обновить версию пакета или добавить новый пакет, вам нужно будет **сделать это снова**. +Если вам нужно обновить версию или добавить новый пакет, вы должны будете **сделать это снова**. /// ### Установка пакетов напрямую -Если вам срочно нужно и вы не хотите использовать файл для объявления зависимостей пакета вашего проекта, вы можете установить их напрямую. +Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, вы можете установить их напрямую. -/// tip | Совет +/// tip | Подсказка -Очень хорошей идеей будет заносить пакеты и версии, которые нужны вашей программе, в файл (например, `requirements.txt` или `pyproject.toml`). +Очень хорошая идея — указать пакеты и версии, которые нужны вашей программе, в отдельном файле (например, `requirements.txt` или `pyproject.toml`). /// @@ -328,7 +312,7 @@ $ pip install "fastapi[standard]" //// tab | `uv` -Если у вас установлен `uv`: +Если вы используете `uv`:
@@ -360,7 +344,7 @@ $ pip install -r requirements.txt //// tab | `uv` -Если у вас установлен `uv`: +Если вы используете `uv`:
@@ -375,7 +359,7 @@ $ uv pip install -r requirements.txt /// details | `requirements.txt` -`requirements.txt` со списком некоторых пакетов может выглядеть так: +Файл `requirements.txt` с некоторыми пакетами может выглядеть так: ```requirements.txt fastapi[standard]==0.113.0 @@ -386,7 +370,7 @@ pydantic==2.8.0 ## Запуск программы -После активации виртуального окружения вы можете запустить свою программу, и она будет использовать Python из вашего виртуального окружения с установленными там пакетами. +После активации виртуального окружения вы можете запустить свою программу, и она будет использовать версию Python и пакеты, установленные в этом окружении.
@@ -400,22 +384,22 @@ Hello World ## Настройка редактора -Вероятно, вы будете использовать редактор кода; убедитесь, что вы настроили его для использования того же виртуального окружения, которое вы создали (вероятно, он его автоматически обнаружит), чтобы у вас были автозавершение и подсветка ошибок. +Вы, вероятно, будете использовать редактор, убедитесь, что вы настроили его на использование того же виртуального окружения, которое вы создали (скорее всего, он обнаружит это автоматически), чтобы получить автозавершение и выделение ошибок в коде. Например: * VS Code * PyCharm -/// tip | Совет +/// tip | Подсказка -Обычно это делается **один раз**, при создании виртуального окружения. +Обычно это нужно делать только **один раз**, когда вы создаете виртуальное окружение. /// ## Деактивация виртуального окружения -Когда вы завершите работу над проектом, вы можете **деактивировать** виртуальное окружение. +Когда вы закончите работу над проектом, вы можете **деактивировать** виртуальное окружение.
@@ -425,53 +409,55 @@ $ deactivate
-Таким образом, когда вы запускаете `python`, он не будет пытаться запустить его из того виртуального окружения с установленными в нём пакетами. +Итак, при запуске `python` не будет попыток использовать Python из этого виртуального окружения с установленными там пакетами. -## Готовность к работе +## Все готово к работе Теперь вы готовы начать работу над своим проектом. -/// tip | Совет -Хотите понять, что означает все вышеперечисленное? -Продолжайте чтение. 👇🤓 +/// tip | Подсказка + +Хотите понять, что это было выше? + +Продолжайте читать. 👇🤓 /// -## Зачем использовать виртуальные окружения +## Зачем нужно виртуальное окружение Для работы с FastAPI вам нужно установить Python. -После этого вам нужно будет **установить** 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`, например вот так:
@@ -481,7 +467,7 @@ $ pip install "harry==1"
-И тогда у вас будет установлена версия `harry` `1` в вашем глобальном Python. +И тогда у вас будет установлен `harry` версии `1` в вашем глобальном окружении Python. ```mermaid flowchart LR @@ -493,7 +479,7 @@ flowchart LR end ``` -Но если вы хотите запустить `prisoner-of-azkaban`, вам нужно будет удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`). +Но потом, если вы хотите запустить `prisoner-of-azkaban`, вам придется удалить `harry` версии `1` и установить `harry` версии `3` (или установка версии `3` автоматически удалит версию `1`).
@@ -503,9 +489,9 @@ $ pip install "harry==3"
-И затем у вас будет установлена версия `harry` `3` в вашем глобальном Python. +И тогда у вас будет установлен `harry` версии `3` в вашем глобальном окружении Python. -И если вы снова попытаетесь запустить `philosophers-stone`, есть вероятность, что он **не будет работать**, потому что ему нужен `harry` версии `1`. +И если вы попытаетесь снова запустить `philosophers-stone`, существует вероятность, что он **не будет работать**, потому что ему нужен `harry` версии `1`. ```mermaid flowchart LR @@ -522,49 +508,49 @@ flowchart LR end ``` -/// tip | Совет +/// tip | Подсказка -В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новых версиях, но лучше перестраховаться и намеренно устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно. +В пакетах Python очень часто стараются изо всех сил **избегать внесения критических изменений** в **новые версии**, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, всё ли работает правильно. /// -Теперь представьте это с **множеством** других **пакетов**, от которых зависят все ваши **проекты**. Это очень сложно управляемо. И, вероятно, вы будете запускать некоторые проекты с некоторыми **несовместимыми версиями** пакетов и не будете знать, почему что-то не работает. +Теперь представьте, что это происходит с **многими другими** **пакетами**, от которых зависят все ваши **проекты**. Управлять этим очень трудно. И вы, вероятно, в итоге будете запускать некоторые проекты с **несовместимыми версиями** пакетов, и не будете знать, почему что-то не работает. -Кроме того, в зависимости от вашей операционной системы (например, Linux, Windows, macOS), она могла быть поставлена с уже установленным Python. И в этом случае, вероятно, были предустановлены некоторые пакеты с определёнными версиями, **нужными вашей системе**. Если вы устанавливаете пакеты в глобальной среде Python, вы можете **поломать** некоторые из программ, которые поставляются с вашей операционной системой. +Кроме того, в зависимости от используемой вами операционной системы (например, Linux, Windows, macOS), она может поставляться уже с установленным Python. И в этом случае, вероятно, были установлены некоторые системные пакеты с определёнными **версиями**, **необходимыми вашей системе**. Если вы установите пакеты в глобальное окружение Python, вы можете **сломать** некоторые из программ, которые поставлялись вместе с вашей операционной системой. -## Где устанавливаются пакеты +## Куда устанавливаются пакеты -Когда вы устанавливаете Python, это создаёт некоторые директории с файлами на вашем компьютере. +Когда вы устанавливаете Python, он создаёт на вашем компьютере несколько директорий с файлами. -Некоторые из этих директорий предназначены для хранения всех устанавливаемых вами пакетов. +Некоторые из этих директорий ответственны за хранение всех устанавливаемых вами пакетов. -Когда вы запускаете: +Когда вы запустите:
```console -// Не запускайте это сейчас, это просто пример 🤓 +// Не запускайте эту команду сейчас, это просто пример 🤓 $ pip install "fastapi[standard]" ---> 100% ```
-Это скачается как сжатый файл с кодом FastAPI, обычно из PyPI. +Это скачает сжатый файл с кодом FastAPI, обычно с PyPI. Он также **скачает** файлы для других пакетов, от которых зависит FastAPI. -Затем он **извлечёт** все эти файлы и поместит их в директорию на вашем компьютере. +Затем он **извлечёт** все эти файлы и разместит их в директории на вашем компьютере. -По умолчанию, он разместит те загруженные и извлечённые файлы в директории, которая идёт с вашей установкой Python, это ваш **глобальный Python**. +По умолчанию, он поместит эти загруженные и распакованные файлы в директорию установку Python, это и есть **глобальное окружение**. -## Что такое виртуальные окружения? +## Что такое виртуальное окружение -Решением проблем того, что все пакеты находятся в глобальной среде, является использование **виртуального окружения для каждого проекта**, над которым вы работаете. +Решением проблемы размещения всех пакетов в глобальной среде является использование **виртуального окружения для каждого проекта**, над которым вы работаете. -Виртуальное окружение — это **директория**, очень похожая на глобальную, где вы можете устанавливать пакеты для проекта. +Виртуальное окружение — это **директория**, очень похожая на глобальную, в которой вы можете устанавливать пакеты для проекта. -Таким образом, каждый проект будет иметь своё собственное виртуальное окружение (директорию `.venv`) со своими пакетами. +Таким образом, у каждого проекта будет своё виртуальное окружение (директория `.venv`) с собственными пакетами. ```mermaid flowchart TB @@ -583,9 +569,9 @@ flowchart TB stone-project ~~~ azkaban-project ``` -## Что означает активация виртуального окружения? +## Что означает активация виртуального окружения -Когда вы активируете виртуальное окружение, например, с помощью: +Когда вы активируете виртуальное окружение, например: //// tab | Linux, macOS @@ -625,19 +611,19 @@ $ source .venv/Scripts/activate //// -Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для следующих команд. +Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд. -Одна из этих переменных — переменная `PATH`. +Одна из этих переменных называется `PATH`. -/// tip | Совет +/// tip | Подсказка -Вы можете узнать больше о переменной `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}. +Вы можете больше узнать о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}. /// -Активация виртуального окружения добавляет путь его директории `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) в переменную окружения `PATH`. +Активация виртуального окружения добавляет его путь `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) к переменной окружения `PATH`. -Скажем, до активации окружения переменная `PATH` выглядела так: +Предположим, что до активации окружения переменная `PATH` выглядела так: //// tab | Linux, macOS @@ -666,7 +652,7 @@ C:\Windows\System32 //// -После активации виртуального окружения переменная `PATH` будет выглядеть примерно так: +После активации виртуального окружения переменная окружения `PATH` будет выглядеть примерно так: //// tab | Linux, macOS @@ -674,7 +660,7 @@ C:\Windows\System32 /home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin ``` -Это означает, что система теперь начнёт искать программы в: +Это означает, что система теперь будет в первую очередь искать программы в: ```plaintext /home/user/code/awesome-project/.venv/bin @@ -682,13 +668,13 @@ C:\Windows\System32 прежде чем искать в других директориях. -Таким образом, когда вы вводите `python` в терминале, система обнаружит программу Python в +Так что, когда вы вводите `python` в терминале, система найдет программу Python в ```plaintext /home/user/code/awesome-project/.venv/bin/python ``` -и будет использовать её. +и использует именно её. //// @@ -698,7 +684,7 @@ C:\Windows\System32 C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32 ``` -Это означает, что система теперь начнёт искать программы в: +Это означает, что система теперь будет в первую очередь искать программы в: ```plaintext C:\Users\user\code\awesome-project\.venv\Scripts @@ -706,23 +692,23 @@ C:\Users\user\code\awesome-project\.venv\Scripts прежде чем искать в других директориях. -Таким образом, когда вы вводите `python` в терминале, система обнаружит программу Python в +Так что, когда вы вводите `python` в терминале, система найдет программу Python в ```plaintext C:\Users\user\code\awesome-project\.venv\Scripts\python ``` -и будет использовать её. +и использует именно её. //// -Важная деталь заключается в том, что он помещает путь виртуального окружения в **начало** переменной `PATH`. Система обнаружит это **раньше**, чем любой другой Python. Таким образом, когда вы запускаете `python`, он будет использовать Python **из виртуального окружения**, а не любой другой `python` (например, `python` из глобального окружения). +Важная деталь заключается в том, что путь к виртуальному окружению будет помещён в самое **начало** переменной `PATH`. Система найдет его **до** обнаружения любого другого доступного Python. Таким образом, когда вы запускаете `python`, он будет использовать **Python из виртуального окружения**, а не какой-либо другой `python` (например, `python` из глобального окружения). -Активация виртуального окружения также меняет несколько других вещей, но это одна из самых важных функций. +Активация виртуального окружения также изменяет несколько других вещей, но это одна из самых важных вещей, которые она делает. ## Проверка виртуального окружения -Когда вы проверяете, активно ли виртуальное окружение, например, с помощью: +Когда вы проверяете, активировано ли виртуальное окружение, например: //// tab | Linux, macOS, Windows Bash @@ -752,33 +738,33 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python //// -Это означает, что программа `python`, которая будет использоваться, — это программа **из виртуального окружения**. +Это означает, что программа `python`, которая будет использована, — это та, что находится **в виртуальной среде разработки**. Вы используете `which` на Linux и macOS и `Get-Command` на Windows PowerShell. -Работа этой команды заключается в том, что она проверяет переменную окружения `PATH`, проходя по **каждому пути по порядку** в поисках программы под названием `python`. Как только она её находит, она **показывает вам путь** к этой программе. +Способ работы этой команды заключается в том, что она пойдёт и проверит переменную окружения `PATH`, проходя **каждый путь по порядку**, в поисках программы под названием `python`. Как только она её найдет, она **покажет вам путь** к этой программе. -Наиболее важной частью является то, что когда вы вызываете `python`, это тот самый "`python`", который будет запущен. +Самое важное тут в том, что когда вы вызываете `python`, именно этот "`python`" будет выполнен. -Таким образом, вы можете убедиться, что находитесь в правильном виртуальном окружении. +Таким образом, вы можете убедиться, что используете верное виртуальное окружение. -/// tip | Совет +/// tip | Подсказка -Легко активировать одно виртуальное окружение, а затем **перейти к другому проекту**. +Легко активировать одно виртуальное окружение, получить одного Python, а затем **перейти к другому проекту**. -И второй проект **не будет работать**, потому что вы используете **неправильный Python**, из виртуального окружения другого проекта. +И второе проект **не будет работать**, потому что вы используете **неправильный Python** из виртуального окружения для другого проекта. -Полезно уметь проверять, какой `python` используется. 🤓 +Это очень полезно уметь проверять, какой `python` используется. 🤓 /// -## Зачем деактивировать виртуальное окружение? +## Почему деактивировать виртуальное окружение -Например, вы можете работать над проектом `philosophers-stone`, **активировать это виртуальное окружение**, устанавливать пакеты и работать в этой среде. +Например, вы можете работать над проектом `philosophers-stone`, **активировать это виртуальное окружение**, установить пакеты и работать с этой средой. -А затем вы хотите поработать над **другим проектом** `prisoner-of-azkaban`. +И затем вы хотите работать над **другим проектом** `prisoner-of-azkaban`. -Вы переходите в этот проект: +Вы переходите к этому проекту:
@@ -788,7 +774,7 @@ $ cd ~/code/prisoner-of-azkaban
-Если вы не деактивируете виртуальное окружение для `philosophers-stone`, когда вы запускаете `python` в терминале, он попытается использовать Python из `philosophers-stone`. +Если вы не деактивируете виртуальное окружение для `philosophers-stone`, когда вы запускаете `python` в терминале, оно будет пытаться использовать Python из `philosophers-stone`.
@@ -797,7 +783,7 @@ $ cd ~/code/prisoner-of-azkaban $ python main.py -// Ошибка при импорте sirius, он не установлен 😱 +// Ошибка импорта sirius, он не установлен 😱 Traceback (most recent call last): File "main.py", line 1, in import sirius @@ -805,20 +791,20 @@ Traceback (most recent call last):
-Но если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, то, когда вы запускаете `python`, он будет использовать Python из виртуального окружения в `prisoner-of-azkaban`. +Но если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, то когда вы запускаете `python`, он будет использовать Python из виртуального окружения в `prisoner-of-azkaban`.
```console $ cd ~/code/prisoner-of-azkaban -// Вам не нужно находиться в старой директории для деактивации, вы можете сделать это, где угодно, даже после перехода к другому проекту 😎 +// Вам не нужно находиться в старой директории, чтобы деактивировать, вы можете сделать это в любом месте, даже после перехода к другому проекту 😎 $ deactivate -// Активируйте виртуальное окружение в prisoner-of-azkaban/.venv 🚀 +// Активируйте виртуальную среду в prisoner-of-azkaban/.venv 🚀 $ source .venv/bin/activate -// Теперь, когда вы запускаете python, он найдёт пакет sirius, установленный в этой виртуальной среде ✨ +// Теперь, когда вы запускаете python, он найдет пакет sirius, установленный в этом виртуальном окружении ✨ $ python main.py Я торжественно клянусь 🐺 @@ -828,23 +814,23 @@ $ python main.py ## Альтернативы -Это простое руководство, чтобы начать работу и показать, как всё **работает изнутри**. +Это простое руководство поможет вам начать и научит тому, как все работает **изнутри**. -Существует много **альтернатив** для управления виртуальными окружениями, зависимостями пакетов, проектами. +Существует множество **альтернатив** для управления виртуальными окружениями, зависимостями пакетов (requirements), проектами. -Когда вы будете готовы и захотите использовать инструмент для **полного управления проектом**, зависимостями пакетов, виртуальными окружениями и т.д., я бы предложил вам попробовать uv. +Когда вы будете готовы и захотите использовать инструмент для **управления всей проектом**, зависимостями пакетов, виртуальными окружениями и т.д., я рекомендую попробовать uv. -`uv` может сделать множество вещей, он может: +`uv` может делать много вещей, может: -* **Установить Python** для вас, включая разные версии +* **Устанавливать Python** для вас, включая различные версии * Управлять **виртуальным окружением** для ваших проектов * Устанавливать **пакеты** -* Управлять зависимостями пакетов и версиями для вашего проекта -* Гарантировать, что у вас есть **точный** набор пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что вы можете запустить ваш проект в продакшн точно так же, как на вашем компьютере во время разработки, это называется **locking** -* И многие другие вещи +* Управлять **зависимостями и версиями** пакетов для вашего проекта +* Убедиться, что у вас есть **точный** набор пакетов и версий для установки, включая их зависимости, так что вы можете быть уверены, что вы сможете запустить ваш проект в production точно так же, как на вашем компьютере, когда разрабатываете, это называется **locking** +* И многое другое ## Заключение -Если вы прочли и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие разработчики. 🤓 +Если вы прочитали и поняли все это, то теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие другие разработчики. 🤓 -Понимание этих деталей, вероятно, будет полезно в будущем, когда вы будете отлаживать что-то, кажущееся сложным, но вы будете знать, **как всё работает под капотом**. 😎 +Знание этих деталей, скорее всего, будет полезно вам в будущем, когда вы будете отлаживать что-то, что кажется сложным, потому что вы будете знать, **как все работает изнутри**. 😎 From 6dfbce1de354d682420a63aa8ffdcd3cb2114d88 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 31 Jul 2025 15:31:16 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20for?= =?UTF-8?q?mat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ru/docs/help-fastapi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md index 82007e2ac..cf435f041 100644 --- a/docs/ru/docs/help-fastapi.md +++ b/docs/ru/docs/help-fastapi.md @@ -119,7 +119,7 @@ Если они ответят, высока вероятность, что вам удалось решить проблему, поздравляю, **вы - герой**! 🦸 * Если вопрос решен, попросите их: - + * В GitHub Discussions: отметить комментарий как **ответ**. * В GitHub Issues: **закрыть** issue.