mirror of
https://github.com/fastapi/fastapi.git
synced 2026-01-22 12:58:11 -05:00
Compare commits
17 Commits
update-tra
...
fix-instal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d2eb2b4dc | ||
|
|
f1a39cab12 | ||
|
|
509afeb475 | ||
|
|
6e47171e9c | ||
|
|
b9b75ba5f1 | ||
|
|
e0abd210f6 | ||
|
|
2eb978b87a | ||
|
|
50a78bf840 | ||
|
|
2d459e4845 | ||
|
|
7faa7089d6 | ||
|
|
0ab68a762f | ||
|
|
7443bc7a46 | ||
|
|
6afb15c518 | ||
|
|
ad6b2901a6 | ||
|
|
463a3a24d7 | ||
|
|
db5441eba1 | ||
|
|
536a5bafe7 |
@@ -189,7 +189,7 @@ Siehe Abschnitt `### Links` im allgemeinen Prompt in `scripts/translate.py`.
|
||||
|
||||
////
|
||||
|
||||
## HTML „abbr“-Elemente { #html-abbr-elements }
|
||||
## HTML-„abbr“-Elemente { #html-abbr-elements }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
|
||||
@@ -56,19 +56,19 @@ from app.routers import items
|
||||
|
||||
Die gleiche Dateistruktur mit Kommentaren:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # „app“ ist ein Python-Package
|
||||
│ ├── __init__.py # diese Datei macht „app“ zu einem „Python-Package“
|
||||
│ ├── main.py # „main“-Modul, z. B. import app.main
|
||||
│ ├── dependencies.py # „dependencies“-Modul, z. B. import app.dependencies
|
||||
│ └── routers # „routers“ ist ein „Python-Subpackage“
|
||||
│ │ ├── __init__.py # macht „routers“ zu einem „Python-Subpackage“
|
||||
│ │ ├── items.py # „items“-Submodul, z. B. import app.routers.items
|
||||
│ │ └── users.py # „users“-Submodul, z. B. import app.routers.users
|
||||
│ └── internal # „internal“ ist ein „Python-Subpackage“
|
||||
│ ├── __init__.py # macht „internal“ zu einem „Python-Subpackage“
|
||||
│ └── admin.py # „admin“-Submodul, z. B. import app.internal.admin
|
||||
├── app # "app" ist ein Python-Package
|
||||
│ ├── __init__.py # diese Datei macht "app" zu einem "Python-Package"
|
||||
│ ├── main.py # "main"-Modul, z. B. import app.main
|
||||
│ ├── dependencies.py # "dependencies"-Modul, z. B. import app.dependencies
|
||||
│ └── routers # "routers" ist ein "Python-Subpackage"
|
||||
│ │ ├── __init__.py # macht "routers" zu einem "Python-Subpackage"
|
||||
│ │ ├── items.py # "items"-Submodul, z. B. import app.routers.items
|
||||
│ │ └── users.py # "users"-Submodul, z. B. import app.routers.users
|
||||
│ └── internal # "internal" ist ein "Python-Subpackage"
|
||||
│ ├── __init__.py # macht "internal" zu einem "Python-Subpackage"
|
||||
│ └── admin.py # "admin"-Submodul, z. B. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
@@ -479,7 +479,7 @@ $ fastapi dev app/main.py
|
||||
|
||||
</div>
|
||||
|
||||
und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Sie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags:
|
||||
|
||||
|
||||
@@ -65,9 +65,6 @@ bronze:
|
||||
# - url: https://testdriven.io/courses/tdd-fastapi/
|
||||
# title: Learn to build high-quality web apps with best practices
|
||||
# img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
- url: https://lambdatest.com/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: LambdaTest, AI-Powered Cloud-based Test Orchestration Platform
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/lambdatest.png
|
||||
- url: https://requestly.com/fastapi
|
||||
title: All-in-one platform to Test, Mock and Intercept APIs. Built for speed, privacy and offline support.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/requestly.png
|
||||
- url: https://www.testmu.ai/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: TestMu AI. The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testmu.png
|
||||
|
||||
@@ -13,7 +13,7 @@ Create a virtual environment and install the required packages with <a href="htt
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uv sync
|
||||
$ uv sync --extra all
|
||||
|
||||
---> 100%
|
||||
```
|
||||
@@ -32,9 +32,9 @@ That way, you don't have to "install" your local version to be able to test ever
|
||||
|
||||
/// note | Technical Details
|
||||
|
||||
This only happens when you install using `uv sync` instead of running `pip install fastapi` directly.
|
||||
This only happens when you install using `uv sync --extra all` instead of running `pip install fastapi` directly.
|
||||
|
||||
That is because `uv sync` will install the local version of FastAPI in "editable" mode by default.
|
||||
That is because `uv sync --extra all` will install the local version of FastAPI in "editable" mode by default.
|
||||
|
||||
///
|
||||
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/testmu.png
Normal file
BIN
docs/en/docs/img/sponsors/testmu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -18,6 +18,12 @@ hide:
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for de (update-outdated). PR [#14690](https://github.com/fastapi/fastapi/pull/14690) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update LLM prompt for Russian translations. PR [#14733](https://github.com/fastapi/fastapi/pull/14733) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for pt (update-outdated). PR [#14724](https://github.com/fastapi/fastapi/pull/14724) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update Korean LLM prompt. PR [#14740](https://github.com/fastapi/fastapi/pull/14740) by [@hard-coders](https://github.com/hard-coders).
|
||||
* 🌐 Improve LLM prompt for Turkish translations. PR [#14728](https://github.com/fastapi/fastapi/pull/14728) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
|
||||
* 🌐 Update portuguese llm-prompt.md. PR [#14702](https://github.com/fastapi/fastapi/pull/14702) by [@ceb10n](https://github.com/ceb10n).
|
||||
* 🌐 Update LLM prompt instructions file for French. PR [#14618](https://github.com/fastapi/fastapi/pull/14618) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for ko (add-missing). PR [#14699](https://github.com/fastapi/fastapi/pull/14699) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -30,6 +36,8 @@ hide:
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔧 Update sponsors: remove Requestly. PR [#14735](https://github.com/fastapi/fastapi/pull/14735) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, LambdaTest changes to TestMu AI. PR [#14734](https://github.com/fastapi/fastapi/pull/14734) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Bump actions/cache from 4 to 5. PR [#14511](https://github.com/fastapi/fastapi/pull/14511) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/upload-artifact from 5 to 6. PR [#14525](https://github.com/fastapi/fastapi/pull/14525) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/download-artifact from 6 to 7. PR [#14526](https://github.com/fastapi/fastapi/pull/14526) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# 동시성과 async / await { #concurrency-and-async-await }
|
||||
# 동시성과 async / await
|
||||
|
||||
*경로 처리 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경
|
||||
*경로 작동 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경
|
||||
|
||||
## 바쁘신가요? { #in-a-hurry }
|
||||
## 바쁘신 경우
|
||||
|
||||
<abbr title="too long; didn't read - 너무 길어서 읽지 않음"><strong>TL;DR:</strong></abbr>
|
||||
<strong>요약</strong>
|
||||
|
||||
다음과 같이 `await`를 사용해 호출하라고 안내하는 제3자 라이브러리를 사용하는 경우:
|
||||
다음과 같이 `await`를 사용해 호출하는 제3의 라이브러리를 사용하는 경우:
|
||||
|
||||
```Python
|
||||
results = await some_library()
|
||||
```
|
||||
|
||||
다음처럼 *경로 처리 함수*를 `async def`를 사용해 선언하십시오:
|
||||
다음처럼 *경로 작동 함수*를 `async def`를 사용해 선언하십시오:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -29,7 +29,7 @@ async def read_results():
|
||||
|
||||
---
|
||||
|
||||
데이터베이스, API, 파일시스템 등과 의사소통하는 제3자 라이브러리를 사용하고, 그것이 `await` 사용을 지원하지 않는 경우(현재 대부분의 데이터베이스 라이브러리가 그러합니다), *경로 처리 함수*를 일반적인 `def`를 사용해 선언하십시오:
|
||||
데이터베이스, API, 파일시스템 등과 의사소통하는 제3의 라이브러리를 사용하고, 그것이 `await`를 지원하지 않는 경우(현재 거의 모든 데이터베이스 라이브러리가 그러합니다), *경로 작동 함수*를 일반적인 `def`를 사용해 선언하십시오:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -40,23 +40,23 @@ def results():
|
||||
|
||||
---
|
||||
|
||||
만약 여러분의 애플리케이션이 (어째서인지) 다른 어떤 것과도 통신하고 그 응답을 기다릴 필요가 없다면, 내부에서 `await`를 사용할 필요가 없더라도 `async def`를 사용하세요.
|
||||
만약 당신의 응용프로그램이 (어째서인지) 다른 무엇과 의사소통하고 그것이 응답하기를 기다릴 필요가 없다면 `async def`를 사용하십시오.
|
||||
|
||||
---
|
||||
|
||||
잘 모르겠다면, 일반적인 `def`를 사용하세요.
|
||||
모르겠다면, 그냥 `def`를 사용하십시오.
|
||||
|
||||
---
|
||||
|
||||
**참고**: *경로 처리 함수*에서 필요한 만큼 `def`와 `async def`를 혼용할 수 있으며, 각각에 대해 가장 알맞은 옵션을 선택해 정의하면 됩니다. FastAPI가 올바르게 처리합니다.
|
||||
**참고**: *경로 작동 함수*에서 필요한만큼 `def`와 `async def`를 혼용할 수 있고, 가장 알맞은 것을 선택해서 정의할 수 있습니다. FastAPI가 자체적으로 알맞은 작업을 수행할 것입니다.
|
||||
|
||||
어쨌든 위의 어떤 경우에서도 FastAPI는 여전히 비동기적으로 동작하며 매우 빠릅니다.
|
||||
어찌되었든, 상기 어떠한 경우라도, FastAPI는 여전히 비동기적으로 작동하고 매우 빠릅니다.
|
||||
|
||||
하지만 위의 단계를 따르면, 몇 가지 성능 최적화를 할 수 있습니다.
|
||||
그러나 상기 작업을 수행함으로써 어느 정도의 성능 최적화가 가능합니다.
|
||||
|
||||
## 기술적 세부사항 { #technical-details }
|
||||
## 기술적 세부사항
|
||||
|
||||
최신 파이썬 버전은 **`async` 및 `await`** 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
|
||||
최신 파이썬 버전은 `async`와 `await` 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
|
||||
|
||||
아래 섹션들에서 해당 문장을 부분별로 살펴보겠습니다:
|
||||
|
||||
@@ -64,255 +64,223 @@ def results():
|
||||
* **`async`와 `await`**
|
||||
* **코루틴**
|
||||
|
||||
## 비동기 코드 { #asynchronous-code }
|
||||
## 비동기 코드
|
||||
|
||||
비동기 코드는 언어 💬 가 코드의 어느 한 부분에서 컴퓨터/프로그램 🤖 에게, 어느 시점에는 어딘가에서 *다른 무언가*가 끝날 때까지 기다려야 한다고 말할 수 있는 방법이 있다는 의미입니다. 그 *다른 무언가*를 "slow-file" 📝 이라고 해보겠습니다.
|
||||
비동기 코드란 언어 💬 가 코드의 어느 한 부분에서, 컴퓨터 / 프로그램🤖에게 *다른 무언가*가 어딘가에서 끝날 때까지 기다려야한다고 말하는 방식입니다. *다른 무언가*가 “느린-파일" 📝 이라고 불린다고 가정해봅시다.
|
||||
|
||||
따라서 그 시간 동안 컴퓨터는 "slow-file" 📝 이 끝나는 동안 다른 작업을 하러 갈 수 있습니다.
|
||||
따라서 “느린-파일” 📝이 끝날때까지 컴퓨터는 다른 작업을 수행할 수 있습니다.
|
||||
|
||||
그 다음 컴퓨터/프로그램 🤖 은 다시 기다리는 중이기 때문에 기회가 있을 때마다 돌아오거나, 혹은 그 시점에 해야 할 작업을 모두 끝낼 때마다 돌아옵니다. 그리고 기다리던 작업 중 이미 끝난 것이 있는지 확인하면서, 해야 했던 작업을 수행합니다.
|
||||
그 다음 컴퓨터 / 프로그램 🤖 은 다시 기다리고 있기 때문에 기회가 있을 때마다 다시 돌아오거나, 혹은 당시에 수행해야하는 작업들이 완료될 때마다 다시 돌아옵니다. 그리고 그것 🤖 은 기다리고 있던 작업 중 어느 것이 이미 완료되었는지, 그것 🤖 이 해야하는 모든 작업을 수행하면서 확인합니다.
|
||||
|
||||
다음으로, 완료된 첫 번째 작업(우리의 "slow-file" 📝 이라고 해보겠습니다)을 가져와서, 그에 대해 해야 했던 작업을 계속합니다.
|
||||
다음으로, 그것 🤖 은 완료할 첫번째 작업에 착수하고(우리의 "느린-파일" 📝 이라고 가정합시다) 그에 대해 수행해야하는 작업을 계속합니다.
|
||||
|
||||
이 "다른 무언가를 기다리는 것"은 일반적으로 프로세서와 RAM 메모리 속도에 비해 상대적으로 "느린" <abbr title="Input and Output">I/O</abbr> 작업을 의미합니다. 예를 들어 다음을 기다리는 것입니다:
|
||||
"다른 무언가를 기다리는 것"은 일반적으로 비교적 "느린" (프로세서와 RAM 메모리 속도에 비해) <abbr title="Input and Output">I/O</abbr> 작업을 의미합니다. 예를 들면 다음의 것들을 기다리는 것입니다:
|
||||
|
||||
* 네트워크를 통해 클라이언트가 데이터를 보내는 것
|
||||
* 네트워크를 통해 클라이언트가 여러분의 프로그램이 보낸 데이터를 받는 것
|
||||
* 시스템이 디스크의 파일 내용을 읽어서 프로그램에 전달하는 것
|
||||
* 프로그램이 시스템에 전달한 내용을 디스크에 쓰는 것
|
||||
* 네트워크를 통해 클라이언트로부터 전송되는 데이터
|
||||
* 네트워크를 통해 클라이언트가 수신할, 당신의 프로그램으로부터 전송되는 데이터
|
||||
* 시스템이 읽고 프로그램에 전달할 디스크 내의 파일 내용
|
||||
* 당신의 프로그램이 시스템에 전달하는, 디스크에 작성될 내용
|
||||
* 원격 API 작업
|
||||
* 데이터베이스 작업이 완료되는 것
|
||||
* 데이터베이스 쿼리가 결과를 반환하는 것
|
||||
* 기타 등등
|
||||
* 완료될 데이터베이스 작업
|
||||
* 결과를 반환하는 데이터베이스 쿼리
|
||||
* 기타
|
||||
|
||||
실행 시간의 대부분이 <abbr title="Input and Output">I/O</abbr> 작업을 기다리는 데 소비되기 때문에, 이를 "I/O bound" 작업이라고 부릅니다.
|
||||
수행 시간의 대부분이 <abbr title="Input and Output">I/O</abbr> 작업을 기다리는데에 소요되기 때문에, "I/O에 묶인" 작업이라고 불립니다.
|
||||
|
||||
이것은 컴퓨터/프로그램이 느린 작업과 "동기화"되어, 아무것도 하지 않은 채 그 작업이 끝나는 정확한 시점만 기다렸다가 결과를 가져와 일을 계속할 필요가 없기 때문에 "비동기"라고 불립니다.
|
||||
이것은 "비동기"라고 불리는데 컴퓨터 / 프로그램이 작업 결과를 가지고 일을 수행할 수 있도록, 느린 작업에 "동기화"되어 아무것도 하지 않으면서 작업이 완료될 정확한 시점만을 기다릴 필요가 없기 때문입니다.
|
||||
|
||||
대신 "비동기" 시스템에서는, 작업이 끝나면 컴퓨터/프로그램이 하러 갔던 일을 마칠 때까지 잠시(몇 마이크로초) 줄에서 기다렸다가, 다시 돌아와 결과를 받아 이를 사용해 작업을 계속할 수 있습니다.
|
||||
이 대신에, "비동기" 시스템에서는, 작업은 일단 완료되면, 컴퓨터 / 프로그램이 수행하고 있는 일을 완료하고 이후 다시 돌아와서 그것의 결과를 받아 이를 사용해 작업을 지속할 때까지 잠시 (몇 마이크로초) 대기할 수 있습니다.
|
||||
|
||||
"동기"(“비동기”의 반대)는 보통 "순차"라는 용어로도 불리는데, 컴퓨터/프로그램이 다른 작업으로 전환하기 전에 모든 단계를 순서대로 따르기 때문이며, 그 단계들에 기다림이 포함되어 있더라도 마찬가지입니다.
|
||||
"동기"("비동기"의 반대)는 컴퓨터 / 프로그램이 상이한 작업들간 전환을 하기 전에 그것이 대기를 동반하게 될지라도 모든 순서를 따르기 때문에 "순차"라는 용어로도 흔히 불립니다.
|
||||
|
||||
### 동시성과 버거 { #concurrency-and-burgers }
|
||||
### 동시성과 버거
|
||||
|
||||
위에서 설명한 **비동기** 코드에 대한 개념은 때때로 **"동시성"**이라고도 불립니다. 이는 **"병렬성"**과는 다릅니다.
|
||||
위에서 설명한 **비동기** 코드에 대한 개념은 종종 **"동시성"**이라고도 불립니다. 이것은 **"병렬성"**과는 다릅니다.
|
||||
|
||||
**동시성**과 **병렬성**은 모두 "대략 같은 시간에 일어나는 서로 다른 일들"과 관련이 있습니다.
|
||||
**동시성**과 **병렬성**은 모두 "동시에 일어나는 서로 다른 일들"과 관련이 있습니다.
|
||||
|
||||
하지만 *동시성*과 *병렬성*의 세부적인 개념에는 꽤 차이가 있습니다.
|
||||
|
||||
차이를 보기 위해, 다음의 버거 이야기를 상상해보세요:
|
||||
차이를 확인하기 위해, 다음의 버거에 대한 이야기를 상상해보십시오:
|
||||
|
||||
### 동시 버거 { #concurrent-burgers }
|
||||
### 동시 버거
|
||||
|
||||
여러분은 짝사랑 상대와 패스트푸드를 먹으러 갔고, 점원이 여러분 앞 사람들의 주문을 받는 동안 줄을 서서 기다립니다. 😍
|
||||
당신은 짝사랑 상대 😍 와 패스트푸드 🍔 를 먹으러 갔습니다. 당신은 점원 💁 이 당신 앞에 있는 사람들의 주문을 받을 동안 줄을 서서 기다리고 있습니다.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
|
||||
이제 당신의 순서가 되어서, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
|
||||
|
||||
이제 여러분 차례가 되어, 여러분과 짝사랑 상대를 위해 매우 고급스러운 버거 2개를 주문합니다. 🍔🍔
|
||||
당신이 돈을 냅니다 💸.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
|
||||
점원 💁 은 주방 👨🍳 에 요리를 하라고 전달하고, 따라서 그들은 당신의 버거 🍔 를 준비해야한다는 사실을 알게됩니다(그들이 지금은 당신 앞 고객들의 주문을 준비하고 있을지라도 말입니다).
|
||||
|
||||
점원은 주방의 요리사에게 무언가를 말해, (지금은 앞선 손님들의 주문을 준비하고 있더라도) 여러분의 버거를 준비해야 한다는 것을 알게 합니다.
|
||||
점원 💁 은 당신의 순서가 적힌 번호표를 줍니다.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
|
||||
기다리는 동안, 당신은 짝사랑 상대 😍 와 함께 테이블을 고르고, 자리에 앉아 오랫동안 (당신이 주문한 버거는 꽤나 고급스럽기 때문에 준비하는데 시간이 조금 걸립니다 ✨🍔✨) 대화를 나눕니다.
|
||||
|
||||
여러분이 돈을 냅니다. 💸
|
||||
짝사랑 상대 😍 와 테이블에 앉아서 버거 🍔 를 기다리는 동안, 그 사람 😍 이 얼마나 멋지고, 사랑스럽고, 똑똑한지 감탄하며 시간을 보냅니다 ✨😍✨.
|
||||
|
||||
점원은 여러분 차례 번호를 줍니다.
|
||||
짝사랑 상대 😍 와 기다리면서 얘기하는 동안, 때때로, 당신은 당신의 차례가 되었는지 보기 위해 카운터의 번호를 확인합니다.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
|
||||
그러다 어느 순간, 당신의 차례가 됩니다. 카운터에 가서, 버거 🍔 를 받고, 테이블로 다시 돌아옵니다.
|
||||
|
||||
기다리는 동안, 여러분은 짝사랑 상대와 함께 자리를 고르고 앉아 오랫동안 대화를 나눕니다(여러분의 버거는 매우 고급스럽기 때문에 준비하는 데 시간이 좀 걸립니다).
|
||||
|
||||
짝사랑 상대와 테이블에 앉아 버거를 기다리는 동안, 그 사람이 얼마나 멋지고 귀엽고 똑똑한지 감탄하며 시간을 보낼 수 있습니다 ✨😍✨.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
|
||||
|
||||
기다리며 대화하는 동안, 때때로 여러분은 카운터에 표시되는 번호를 확인해 여러분 차례인지 봅니다.
|
||||
|
||||
그러다 어느 순간 마침내 여러분 차례가 됩니다. 여러분은 카운터에 가서 버거를 받고, 테이블로 돌아옵니다.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
|
||||
|
||||
여러분과 짝사랑 상대는 버거를 먹으며 좋은 시간을 보냅니다. ✨
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
|
||||
|
||||
/// info | 정보
|
||||
|
||||
아름다운 일러스트: <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
|
||||
|
||||
///
|
||||
당신과 짝사랑 상대 😍 는 버거 🍔 를 먹으며 좋은 시간을 보냅니다 ✨.
|
||||
|
||||
---
|
||||
|
||||
이 이야기에서 여러분이 컴퓨터/프로그램 🤖 이라고 상상해보세요.
|
||||
당신이 이 이야기에서 컴퓨터 / 프로그램 🤖 이라고 상상해보십시오.
|
||||
|
||||
줄을 서 있는 동안, 여러분은 그냥 쉬고 😴, 차례를 기다리며, 그다지 "생산적인" 일을 하지 않습니다. 하지만 점원은 주문만 받지(음식을 준비하진 않기) 때문에 줄이 빠르게 줄어들어 괜찮습니다.
|
||||
줄을 서서 기다리는 동안, 당신은 아무것도 하지 않고 😴 당신의 차례를 기다리며, 어떠한 "생산적인" 일도 하지 않습니다. 하지만 점원 💁 이 (음식을 준비하지는 않고) 주문을 받기만 하기 때문에 줄이 빨리 줄어들어서 괜찮습니다.
|
||||
|
||||
그 다음 여러분 차례가 되면, 여러분은 실제로 "생산적인" 일을 합니다. 메뉴를 처리하고, 무엇을 먹을지 결정하고, 짝사랑 상대의 선택을 확인하고, 결제하고, 올바른 현금이나 카드를 냈는지 확인하고, 정확히 청구되었는지 확인하고, 주문에 올바른 항목들이 들어갔는지 확인하는 등등을 합니다.
|
||||
그다음, 당신이 차례가 오면, 당신은 실제로 "생산적인" 일 🤓 을 합니다. 당신은 메뉴를 보고, 무엇을 먹을지 결정하고, 짝사랑 상대 😍 의 선택을 묻고, 돈을 내고 💸 , 맞는 카드를 냈는지 확인하고, 비용이 제대로 지불되었는지 확인하고, 주문이 제대로 들어갔는지 확인을 하는 작업 등등을 수행합니다.
|
||||
|
||||
하지만 그 다음에는, 아직 버거를 받지 못했더라도, 버거가 준비될 때까지 기다려야 🕙 하므로 점원과의 작업은 "일시정지" ⏸ 상태입니다.
|
||||
하지만 이후에는, 버거 🍔 를 아직 받지 못했음에도, 버거가 준비될 때까지 기다려야 🕙 하기 때문에 점원 💁 과의 작업은 "일시정지" ⏸ 상태입니다.
|
||||
|
||||
하지만 번호를 들고 카운터에서 벗어나 테이블에 앉으면, 여러분은 짝사랑 상대에게 관심을 전환 🔀 하고, 그에 대한 "작업" ⏯ 🤓 을 할 수 있습니다. 그러면 여러분은 다시 짝사랑 상대에게 작업을 거는 매우 "생산적인" 일을 하게 됩니다 😍.
|
||||
하지만 번호표를 받고 카운터에서 나와 테이블에 앉으면, 당신은 짝사랑 상대 😍 와 그 "작업" ⏯ 🤓 에 번갈아가며 🔀 집중합니다. 그러면 당신은 다시 짝사랑 상대 😍 에게 작업을 거는 매우 "생산적인" 일 🤓 을 합니다.
|
||||
|
||||
그 다음 점원 💁 이 카운터 화면에 여러분 번호를 띄워 "버거를 만들었어요"라고 말하지만, 표시된 번호가 여러분 차례로 바뀌었다고 해서 즉시 미친 듯이 뛰어가지는 않습니다. 여러분은 여러분 번호를 갖고 있고, 다른 사람들은 그들의 번호를 갖고 있으니, 아무도 여러분 버거를 훔쳐갈 수 없다는 것을 알기 때문입니다.
|
||||
점원 💁 이 카운터 화면에 당신의 번호를 표시함으로써 "버거 🍔 가 준비되었습니다"라고 해도, 당신은 즉시 뛰쳐나가지는 않을 것입니다. 당신은 당신의 번호를 갖고있고, 다른 사람들은 그들의 번호를 갖고있기 때문에, 아무도 당신의 버거 🍔 를 훔쳐가지 않는다는 사실을 알기 때문입니다.
|
||||
|
||||
그래서 여러분은 짝사랑 상대가 이야기를 끝낼 때까지 기다린 다음(현재 작업 ⏯ / 처리 중인 작업 🤓 을 끝내고), 부드럽게 미소 지으며 버거를 가지러 가겠다고 말합니다 ⏸.
|
||||
그래서 당신은 짝사랑 상대 😍 가 이야기를 끝낼 때까지 기다린 후 (현재 작업 완료 ⏯ / 진행 중인 작업 처리 🤓 ), 정중하게 미소짓고 버거를 가지러 가겠다고 말합니다 ⏸.
|
||||
|
||||
그 다음 여러분은 카운터로 가서 🔀, 이제 끝난 초기 작업 ⏯ 으로 돌아와 버거를 받고, 감사 인사를 하고, 테이블로 가져옵니다. 이로써 카운터와 상호작용하는 그 단계/작업이 끝납니다 ⏹. 그리고 이는 새로운 작업인 "버거 먹기" 🔀 ⏯ 를 만들지만, 이전 작업인 "버거 받기"는 끝났습니다 ⏹.
|
||||
그다음 당신은 카운터에 가서 🔀 , 초기 작업을 이제 완료하고 ⏯ , 버거 🍔 를 받고, 감사하다고 말하고 테이블로 가져옵니다. 이로써 카운터와의 상호작용 단계 / 작업이 종료됩니다 ⏹.
|
||||
|
||||
### 병렬 버거 { #parallel-burgers }
|
||||
이전 작업인 "버거 받기"가 종료되면 ⏹ "버거 먹기"라는 새로운 작업이 생성됩니다 🔀 ⏯.
|
||||
|
||||
이제 이것이 "동시 버거"가 아니라 "병렬 버거"라고 상상해봅시다.
|
||||
### 병렬 버거
|
||||
|
||||
여러분은 짝사랑 상대와 함께 병렬 패스트푸드를 먹으러 갑니다.
|
||||
이제 "동시 버거"가 아닌 "병렬 버거"를 상상해보십시오.
|
||||
|
||||
여러분은 여러 명(예: 8명)의 점원이 동시에 요리사이기도 하여 여러분 앞 사람들의 주문을 받는 동안 줄을 서 있습니다.
|
||||
당신은 짝사랑 상대 😍 와 함께 병렬 패스트푸드 🍔 를 먹으러 갔습니다.
|
||||
|
||||
여러분 앞의 모든 사람들은, 8명의 점원 각각이 다음 주문을 받기 전에 바로 버거를 준비하러 가기 때문에, 카운터를 떠나지 않고 버거가 준비될 때까지 기다립니다.
|
||||
당신은 여러명(8명이라고 가정합니다)의 점원이 당신 앞 사람들의 주문을 받으며 동시에 요리 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 도 하는 동안 줄을 서서 기다립니다.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
|
||||
당신 앞 모든 사람들이 버거가 준비될 때까지 카운터에서 떠나지 않고 기다립니다 🕙 . 왜냐하면 8명의 직원들이 다음 주문을 받기 전에 버거를 준비하러 가기 때문입니다.
|
||||
|
||||
마침내 여러분 차례가 되어, 여러분과 짝사랑 상대를 위해 매우 고급스러운 버거 2개를 주문합니다.
|
||||
마침내 당신의 차례가 왔고, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
|
||||
|
||||
여러분이 돈을 냅니다 💸.
|
||||
당신이 비용을 지불합니다 💸 .
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
|
||||
점원이 주방에 갑니다 👨🍳 .
|
||||
|
||||
점원은 주방으로 갑니다.
|
||||
당신은 번호표가 없기 때문에 누구도 당신의 버거 🍔 를 대신 가져갈 수 없도록 카운터에 서서 기다립니다 🕙 .
|
||||
|
||||
여러분은 번호표가 없으므로, 다른 사람이 여러분보다 먼저 버거를 가져가지 못하도록 카운터 앞에 서서 기다립니다 🕙.
|
||||
당신과 짝사랑 상대 😍 는 다른 사람이 새치기해서 버거를 가져가지 못하게 하느라 바쁘기 때문에 🕙 , 짝사랑 상대에게 주의를 기울일 수 없습니다 😞 .
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
|
||||
이것은 "동기" 작업이고, 당신은 점원/요리사 👨🍳 와 "동기화" 되었습니다. 당신은 기다리고 🕙 , 점원/요리사 👨🍳 가 버거 🍔 준비를 완료한 후 당신에게 주거나, 누군가가 그것을 가져가는 그 순간에 그 곳에 있어야합니다.
|
||||
|
||||
여러분과 짝사랑 상대는 버거가 나오면 다른 사람이 끼어들어 가져가지 못하게 하느라 바쁘기 때문에, 짝사랑 상대에게 집중할 수 없습니다. 😞
|
||||
카운터 앞에서 오랫동안 기다린 후에 🕙 , 점원/요리사 👨🍳 가 당신의 버거 🍔 를 가지고 돌아옵니다.
|
||||
|
||||
이것은 "동기" 작업이며, 여러분은 점원/요리사 👨🍳 와 "동기화"되어 있습니다. 점원/요리사 👨🍳 가 버거를 완성해 여러분에게 주는 정확한 순간에 그 자리에 있어야 하므로, 여러분은 기다려야 🕙 하고, 그렇지 않으면 다른 사람이 가져갈 수도 있습니다.
|
||||
당신은 버거를 받고 짝사랑 상대와 함께 테이블로 돌아옵니다.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
|
||||
단지 먹기만 하다가, 다 먹었습니다 🍔 ⏹.
|
||||
|
||||
그러다 점원/요리사 👨🍳 가 카운터 앞에서 오랫동안 기다린 🕙 끝에 마침내 버거를 가지고 돌아옵니다.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
|
||||
|
||||
여러분은 버거를 받아 짝사랑 상대와 테이블로 갑니다.
|
||||
|
||||
그냥 먹고, 끝입니다. ⏹
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
|
||||
|
||||
대부분의 시간을 카운터 앞에서 기다리는 데 🕙 썼기 때문에, 대화하거나 작업을 걸 시간은 많지 않았습니다. 😞
|
||||
|
||||
/// info | 정보
|
||||
|
||||
아름다운 일러스트: <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
|
||||
|
||||
///
|
||||
카운터 앞에서 기다리면서 🕙 너무 많은 시간을 허비했기 때문에 대화를 하거나 작업을 걸 시간이 거의 없었습니다 😞 .
|
||||
|
||||
---
|
||||
|
||||
이 병렬 버거 시나리오에서, 여러분은 두 개의 프로세서(여러분과 짝사랑 상대)를 가진 컴퓨터/프로그램 🤖 이며, 둘 다 기다리고 🕙 오랫동안 "카운터에서 기다리기" 🕙 에 주의를 ⏯ 기울입니다.
|
||||
이 병렬 버거 시나리오에서, 당신은 기다리고 🕙 , 오랜 시간동안 "카운터에서 기다리는" 🕙 데에 주의를 기울이는 ⏯ 두 개의 프로세서(당신과 짝사랑 상대😍)를 가진 컴퓨터 / 프로그램 🤖 입니다.
|
||||
|
||||
패스트푸드점에는 8개의 프로세서(점원/요리사)가 있습니다. 동시 버거 가게는 2개(점원 1명, 요리사 1명)만 있었을 것입니다.
|
||||
패스트푸드점에는 8개의 프로세서(점원/요리사) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 가 있습니다. 동시 버거는 단 두 개(한 명의 직원과 한 명의 요리사) 💁 👨🍳 만을 가지고 있었습니다.
|
||||
|
||||
하지만 여전히 최종 경험은 그다지 좋지 않습니다. 😞
|
||||
하지만 여전히, 병렬 버거 예시가 최선은 아닙니다 😞 .
|
||||
|
||||
---
|
||||
|
||||
이것이 버거의 병렬 버전에 해당하는 이야기입니다. 🍔
|
||||
이 예시는 버거🍔 이야기와 결이 같습니다.
|
||||
|
||||
좀 더 "현실적인" 예시로, 은행을 상상해보세요.
|
||||
더 "현실적인" 예시로, 은행을 상상해보십시오.
|
||||
|
||||
최근까지 대부분의 은행에는 여러 은행원 👨💼👨💼👨💼👨💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있었습니다.
|
||||
최근까지, 대다수의 은행에는 다수의 은행원들 👨💼👨💼👨💼👨💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있습니다.
|
||||
|
||||
모든 은행원이 한 고객씩 순서대로 모든 일을 처리합니다 👨💼⏯.
|
||||
모든 은행원들은 한 명 한 명의 고객들을 차례로 상대합니다 👨💼⏯ .
|
||||
|
||||
그리고 여러분은 오랫동안 줄에서 기다려야 🕙 하며, 그렇지 않으면 차례를 잃습니다.
|
||||
그리고 당신은 오랫동안 줄에서 기다려야하고 🕙 , 그렇지 않으면 당신의 차례를 잃게 됩니다.
|
||||
|
||||
아마 은행 🏦 업무를 보러 갈 때 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.
|
||||
아마 당신은 은행 🏦 심부름에 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.
|
||||
|
||||
### 버거 예시의 결론 { #burger-conclusion }
|
||||
### 버거 예시의 결론
|
||||
|
||||
"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서는 기다림 🕙 이 많기 때문에, 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 훨씬 더 합리적입니다.
|
||||
"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서, 오랜 기다림 🕙 이 있기 때문에 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 더 합리적입니다.
|
||||
|
||||
대부분의 웹 애플리케이션이 그렇습니다.
|
||||
대다수의 웹 응용프로그램의 경우가 그러합니다.
|
||||
|
||||
매우 많은 사용자들이 있고, 서버는 그들의 좋지 않은 연결을 통해 요청이 전송되기를 기다립니다 🕙.
|
||||
매우 많은 수의 유저가 있지만, 서버는 그들의 요청을 전송하기 위해 그닥-좋지-않은 연결을 기다려야 합니다 🕙 .
|
||||
|
||||
그리고 응답이 돌아오기를 다시 기다립니다 🕙.
|
||||
그리고 응답이 돌아올 때까지 다시 기다려야 합니다 🕙 .
|
||||
|
||||
이 "기다림" 🕙 은 마이크로초 단위로 측정되지만, 모두 합치면 결국 꽤 많은 대기 시간이 됩니다.
|
||||
이 "기다림" 🕙 은 마이크로초 단위이지만, 모두 더해지면, 결국에는 매우 긴 대기시간이 됩니다.
|
||||
|
||||
그래서 웹 API에는 비동기 ⏸🔀⏯ 코드를 사용하는 것이 매우 합리적입니다.
|
||||
따라서 웹 API를 위해 비동기 ⏸🔀⏯ 코드를 사용하는 것이 합리적입니다.
|
||||
|
||||
이러한 종류의 비동기성은 NodeJS가 인기 있는 이유(비록 NodeJS가 병렬은 아니지만)이자, 프로그래밍 언어로서 Go의 강점입니다.
|
||||
대부분의 존재하는 유명한 파이썬 프레임워크 (Flask와 Django 등)은 새로운 비동기 기능들이 파이썬에 존재하기 전에 만들어졌습니다. 그래서, 그들의 배포 방식은 병렬 실행과 새로운 기능만큼 강력하지는 않은 예전 버전의 비동기 실행을 지원합니다.
|
||||
|
||||
그리고 이것이 **FastAPI**로 얻는 것과 같은 수준의 성능입니다.
|
||||
비동기 웹 파이썬(ASGI)에 대한 주요 명세가 웹소켓을 지원하기 위해 Django에서 개발 되었음에도 그렇습니다.
|
||||
|
||||
또한 병렬성과 비동기성을 동시에 사용할 수 있으므로, 대부분의 테스트된 NodeJS 프레임워크보다 더 높은 성능을 얻고, C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다 <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(모두 Starlette 덕분입니다)</a>.
|
||||
이러한 종류의 비동기성은 (NodeJS는 병렬적이지 않음에도) NodeJS가 사랑받는 이유이고, 프로그래밍 언어로서의 Go의 강점입니다.
|
||||
|
||||
### 동시성이 병렬성보다 더 나은가요? { #is-concurrency-better-than-parallelism }
|
||||
그리고 **FastAPI**를 사용함으로써 동일한 성능을 낼 수 있습니다.
|
||||
|
||||
아니요! 그게 이 이야기의 교훈은 아닙니다.
|
||||
또한 병렬성과 비동기성을 동시에 사용할 수 있기 때문에, 대부분의 테스트가 완료된 NodeJS 프레임워크보다 더 높은 성능을 얻고 C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다<a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(모두 Starlette 덕분입니다)</a>.
|
||||
|
||||
동시성은 병렬성과 다릅니다. 그리고 많은 기다림이 포함되는 **특정한** 시나리오에서는 더 낫습니다. 그 때문에 웹 애플리케이션 개발에서는 일반적으로 병렬성보다 훨씬 더 낫습니다. 하지만 모든 것에 해당하진 않습니다.
|
||||
### 동시성이 병렬성보다 더 나은가?
|
||||
|
||||
그래서 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보세요:
|
||||
그렇지 않습니다! 그것이 이야기의 교훈은 아닙니다.
|
||||
|
||||
> 여러분은 크고 더러운 집을 청소해야 합니다.
|
||||
동시성은 병렬성과 다릅니다. 그리고 그것은 많은 대기를 필요로하는 **특정한** 시나리오에서는 더 낫습니다. 이로 인해, 웹 응용프로그램 개발에서 동시성이 병렬성보다 일반적으로 훨씬 낫습니다. 하지만 모든 경우에 그런 것은 아닙니다.
|
||||
|
||||
따라서, 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보십시오:
|
||||
|
||||
> 당신은 크고, 더러운 집을 청소해야합니다.
|
||||
|
||||
*네, 이게 전부입니다*.
|
||||
|
||||
---
|
||||
|
||||
어디에도 기다림 🕙 은 없고, 집의 여러 장소에서 해야 할 일이 많을 뿐입니다.
|
||||
어디에도 대기 🕙 는 없고, 집안 곳곳에서 해야하는 많은 작업들만 있습니다.
|
||||
|
||||
버거 예시처럼 거실부터, 그 다음은 부엌처럼 순서를 정할 수도 있지만, 어떤 것도 기다리지 🕙 않고 계속 청소만 하기 때문에, 순서는 아무런 영향을 주지 않습니다.
|
||||
버거 예시처럼 처음에는 거실, 그 다음은 부엌과 같은 식으로 순서를 정할 수도 있으나, 무엇도 기다리지 🕙 않고 계속해서 청소 작업만 수행하기 때문에, 순서는 아무런 영향을 미치지 않습니다.
|
||||
|
||||
순서가 있든 없든(동시성) 끝내는 데 걸리는 시간은 같고, 같은 양의 일을 하게 됩니다.
|
||||
순서가 있든 없든 동일한 시간이 소요될 것이고(동시성) 동일한 양의 작업을 하게 될 것입니다.
|
||||
|
||||
하지만 이 경우, 전(前) 점원/요리사이자 현(現) 청소부가 된 8명을 데려올 수 있고, 각자(그리고 여러분)가 집의 구역을 하나씩 맡아 청소한다면, 추가 도움과 함께 모든 일을 **병렬**로 수행하여 훨씬 더 빨리 끝낼 수 있습니다.
|
||||
하지만 이 경우에서, 8명의 전(前)-점원/요리사이면서-현(現)-청소부 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 를 고용할 수 있고, 그들 각자(그리고 당신)가 집의 한 부분씩 맡아 청소를 한다면, 당신은 **병렬적**으로 작업을 수행할 수 있고, 조금의 도움이 있다면, 훨씬 더 빨리 끝낼 수 있습니다.
|
||||
|
||||
이 시나리오에서 (여러분을 포함한) 각 청소부는 프로세서가 되어, 맡은 일을 수행합니다.
|
||||
이 시나리오에서, (당신을 포함한) 각각의 청소부들은 프로세서가 될 것이고, 각자의 역할을 수행합니다.
|
||||
|
||||
그리고 실행 시간의 대부분이 기다림이 아니라 실제 작업에 쓰이고, 컴퓨터에서 작업은 <abbr title="Central Processing Unit">CPU</abbr>가 수행하므로, 이런 문제를 "CPU bound"라고 부릅니다.
|
||||
실행 시간의 대부분이 대기가 아닌 실제 작업에 소요되고, 컴퓨터에서 작업은 <abbr title="Central Processing Unit">CPU</abbr>에서 이루어지므로, 이러한 문제를 "CPU에 묶였"다고 합니다.
|
||||
|
||||
---
|
||||
|
||||
CPU bound 작업의 흔한 예시는 복잡한 수학 처리가 필요한 것들입니다.
|
||||
CPU에 묶인 연산에 관한 흔한 예시는 복잡한 수학 처리를 필요로 하는 경우입니다.
|
||||
|
||||
예를 들어:
|
||||
|
||||
* **오디오** 또는 **이미지** 처리
|
||||
* **컴퓨터 비전**: 이미지는 수백만 개의 픽셀로 구성되며, 각 픽셀은 3개의 값/색을 갖습니다. 보통 그 픽셀들에 대해 동시에 무언가를 계산해야 합니다.
|
||||
* **머신러닝**: 보통 많은 "matrix"와 "vector" 곱셈이 필요합니다. 숫자가 있는 거대한 스프레드시트를 생각하고, 그 모든 수를 동시에 곱한다고 생각해보세요.
|
||||
* **딥러닝**: 머신러닝의 하위 분야이므로 동일하게 적용됩니다. 다만 곱해야 할 숫자가 있는 스프레드시트가 하나가 아니라, 아주 큰 집합이며, 많은 경우 그 모델을 만들고/또는 사용하기 위해 특별한 프로세서를 사용합니다.
|
||||
* **오디오** 또는 **이미지** 처리.
|
||||
* **컴퓨터 비전**: 하나의 이미지는 수백개의 픽셀로 구성되어있고, 각 픽셀은 3개의 값 / 색을 갖고 있으며, 일반적으로 해당 픽셀들에 대해 동시에 무언가를 계산해야하는 처리.
|
||||
* **머신러닝**: 일반적으로 많은 "행렬"과 "벡터" 곱셈이 필요합니다. 거대한 스프레드 시트에 수들이 있고 그 수들을 동시에 곱해야 한다고 생각해보십시오.
|
||||
* **딥러닝**: 머신러닝의 하위영역으로, 동일한 예시가 적용됩니다. 단지 이 경우에는 하나의 스프레드 시트에 곱해야할 수들이 있는 것이 아니라, 거대한 세트의 스프레드 시트들이 있고, 많은 경우에, 이 모델들을 만들고 사용하기 위해 특수한 프로세서를 사용합니다.
|
||||
|
||||
### 동시성 + 병렬성: 웹 + 머신러닝 { #concurrency-parallelism-web-machine-learning }
|
||||
### 동시성 + 병렬성: 웹 + 머신러닝
|
||||
|
||||
**FastAPI**를 사용하면 웹 개발에서 매우 흔한 동시성의 이점을( NodeJS의 주요 매력과 같은) 얻을 수 있습니다.
|
||||
**FastAPI**를 사용하면 웹 개발에서는 매우 흔한 동시성의 이점을 (NodeJS의 주된 매력만큼) 얻을 수 있습니다.
|
||||
|
||||
또한 머신러닝 시스템처럼 **CPU bound** 워크로드에 대해 병렬성과 멀티프로세싱(여러 프로세스를 병렬로 실행)을 활용할 수도 있습니다.
|
||||
뿐만 아니라 머신러닝 시스템과 같이 **CPU에 묶인** 작업을 위해 병렬성과 멀티프로세싱(다수의 프로세스를 병렬적으로 동작시키는 것)을 이용하는 것도 가능합니다.
|
||||
|
||||
이것은 파이썬이 **데이터 사이언스**, 머신러닝, 특히 딥러닝의 주요 언어라는 단순한 사실과 더해져, FastAPI를 데이터 사이언스/머신러닝 웹 API 및 애플리케이션(그 외에도 많은 것들)에 매우 잘 맞는 선택으로 만들어 줍니다.
|
||||
파이썬이 **데이터 사이언스**, 머신러닝과 특히 딥러닝에 의 주된 언어라는 간단한 사실에 더해서, 이것은 FastAPI를 데이터 사이언스 / 머신러닝 웹 API와 응용프로그램에 (다른 것들보다) 좋은 선택지가 되게 합니다.
|
||||
|
||||
프로덕션에서 이 병렬성을 어떻게 달성하는지 보려면 [배포](deployment/index.md){.internal-link target=_blank} 섹션을 참고하세요.
|
||||
배포시 병렬을 어떻게 가능하게 하는지 알고싶다면, [배포](deployment/index.md){.internal-link target=_blank}문서를 참고하십시오.
|
||||
|
||||
## `async`와 `await` { #async-and-await }
|
||||
## `async`와 `await`
|
||||
|
||||
최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이 방법은 이를 평범한 "순차" 코드처럼 보이게 하고, 적절한 순간에 여러분을 위해 "기다림"을 수행합니다.
|
||||
최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이는 이것을 평범한 "순차적" 코드로 보이게 하고, 적절한 순간에 당신을 위해 "대기"합니다.
|
||||
|
||||
결과를 주기 전에 기다림이 필요한 작업이 있고, 이러한 새로운 파이썬 기능을 지원한다면, 다음과 같이 작성할 수 있습니다:
|
||||
연산이 결과를 전달하기 전에 대기를 해야하고 새로운 파이썬 기능들을 지원한다면, 이렇게 코드를 작성할 수 있습니다:
|
||||
|
||||
```Python
|
||||
burgers = await get_burgers(2)
|
||||
```
|
||||
|
||||
여기서 핵심은 `await`입니다. 이는 파이썬에게 `get_burgers(2)`가 그 일을 끝낼 때까지 🕙 기다리도록 ⏸ 말하고, 그 결과를 `burgers`에 저장하기 전에 완료되기를 기다리라고 합니다. 이를 통해 파이썬은 그동안(예: 다른 요청을 받는 것처럼) 다른 일을 하러 갈 수 있다는 것 🔀 ⏯ 을 알게 됩니다.
|
||||
여기서 핵심은 `await`입니다. 이것은 파이썬에게 `burgers` 결과를 저장하기 이전에 `get_burgers(2)`의 작업이 완료되기를 🕙 기다리라고 ⏸ 말합니다. 이로 인해, 파이썬은 그동안 (다른 요청을 받는 것과 같은) 다른 작업을 수행해도 된다는 것을 🔀 ⏯ 알게될 것입니다.
|
||||
|
||||
`await`가 동작하려면, 이 비동기성을 지원하는 함수 내부에 있어야 합니다. 그러려면 `async def`로 선언하기만 하면 됩니다:
|
||||
`await`가 동작하기 위해, 이것은 비동기를 지원하는 함수 내부에 있어야 합니다. 이를 위해서 함수를 `async def`를 사용해 정의하기만 하면 됩니다:
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def get_burgers(number: int):
|
||||
@@ -320,7 +288,7 @@ async def get_burgers(number: int):
|
||||
return burgers
|
||||
```
|
||||
|
||||
...`def` 대신:
|
||||
...`def`를 사용하는 대신:
|
||||
|
||||
```Python hl_lines="2"
|
||||
# This is not asynchronous
|
||||
@@ -329,9 +297,9 @@ def get_sequential_burgers(number: int):
|
||||
return burgers
|
||||
```
|
||||
|
||||
`async def`를 사용하면, 파이썬은 그 함수 내부에서 `await` 표현식에 주의해야 하며, 그 함수의 실행을 "일시정지" ⏸ 하고 다시 돌아오기 전에 다른 일을 하러 갈 수 있다는 것 🔀 을 알게 됩니다.
|
||||
`async def`를 사용하면, 파이썬은 해당 함수 내에서 `await` 표현에 주의해야한다는 사실과, 해당 함수의 실행을 "일시정지"⏸하고 다시 돌아오기 전까지 다른 작업을 수행🔀할 수 있다는 것을 알게됩니다.
|
||||
|
||||
`async def` 함수를 호출하고자 할 때는, 그 함수를 "await" 해야 합니다. 따라서 아래는 동작하지 않습니다:
|
||||
`async def`f 함수를 호출하고자 할 때, "대기"해야합니다. 따라서, 아래는 동작하지 않습니다.
|
||||
|
||||
```Python
|
||||
# This won't work, because get_burgers was defined with: async def
|
||||
@@ -340,7 +308,7 @@ burgers = get_burgers(2)
|
||||
|
||||
---
|
||||
|
||||
따라서, `await`로 호출할 수 있다고 말하는 라이브러리를 사용한다면, 다음과 같이 그것을 사용하는 *경로 처리 함수*를 `async def`로 만들어야 합니다:
|
||||
따라서, `await`f를 사용해서 호출할 수 있는 라이브러리를 사용한다면, 다음과 같이 `async def`를 사용하는 *경로 작동 함수*를 생성해야 합니다:
|
||||
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
@@ -349,96 +317,94 @@ async def read_burgers():
|
||||
return burgers
|
||||
```
|
||||
|
||||
### 더 세부적인 기술적 사항 { #more-technical-details }
|
||||
### 더 세부적인 기술적 사항
|
||||
|
||||
`await`는 `async def`로 정의된 함수 내부에서만 사용할 수 있다는 것을 눈치채셨을 것입니다.
|
||||
`await`가 `async def`를 사용하는 함수 내부에서만 사용이 가능하다는 것을 눈치채셨을 것입니다.
|
||||
|
||||
하지만 동시에, `async def`로 정의된 함수는 "await" 되어야 합니다. 따라서 `async def`를 가진 함수는 `async def`로 정의된 함수 내부에서만 호출될 수 있습니다.
|
||||
하지만 동시에, `async def`로 정의된 함수들은 "대기"되어야만 합니다. 따라서, `async def`를 사용한 함수들은 역시 `async def`를 사용한 함수 내부에서만 호출될 수 있습니다.
|
||||
|
||||
그렇다면, 닭이 먼저냐 달걀이 먼저냐처럼, 첫 번째 `async` 함수는 어떻게 호출할 수 있을까요?
|
||||
그렇다면 닭이 먼저냐, 달걀이 먼저냐, 첫 `async` 함수를 어떻게 호출할 수 있겠습니까?
|
||||
|
||||
**FastAPI**로 작업한다면 걱정할 필요가 없습니다. 그 "첫" 함수는 여러분의 *경로 처리 함수*가 될 것이고, FastAPI는 올바르게 처리하는 방법을 알고 있기 때문입니다.
|
||||
**FastAPI**를 사용해 작업한다면 이것을 걱정하지 않아도 됩니다. 왜냐하면 그 "첫" 함수는 당신의 *경로 작동 함수*가 될 것이고, FastAPI는 어떻게 올바르게 처리할지 알고있기 때문입니다.
|
||||
|
||||
하지만 FastAPI 없이 `async` / `await`를 사용하고 싶다면, 그것도 가능합니다.
|
||||
하지만 FastAPI를 사용하지 않고 `async` / `await`를 사용하고 싶다면, 이 역시 가능합니다.
|
||||
|
||||
### 여러분만의 async 코드 작성하기 { #write-your-own-async-code }
|
||||
### 당신만의 비동기 코드 작성하기
|
||||
|
||||
Starlette(그리고 **FastAPI**)는 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 기반으로 하고 있으며, 파이썬 표준 라이브러리 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a>와 <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a> 모두와 호환됩니다.
|
||||
Starlette(그리고 FastAPI)는 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 기반으로 하고있고, 따라서 파이썬 표준 라이브러리인 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> 및 <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>와 호환됩니다.
|
||||
|
||||
특히, 코드에서 더 고급 패턴이 필요한 고급 동시성 사용 사례에서는 직접 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용할 수 있습니다.
|
||||
특히, 코드에서 고급 패턴이 필요한 고급 동시성을 사용하는 경우 직접적으로 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용할 수 있습니다.
|
||||
|
||||
그리고 FastAPI를 사용하지 않더라도, 높은 호환성을 확보하고 그 이점(예: *structured concurrency*)을 얻기 위해 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>로 여러분만의 async 애플리케이션을 작성할 수도 있습니다.
|
||||
FastAPI를 사용하지 않더라도, 높은 호환성 및 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>의 이점(예: *구조화된 동시성*)을 취하기 위해 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용해 비동기 응용프로그램을 작성할 수 있습니다.
|
||||
|
||||
저는 AnyIO 위에 얇은 레이어로 또 다른 라이브러리를 만들었는데, 타입 어노테이션을 조금 개선하고 더 나은 **자동완성**, **인라인 오류** 등을 얻기 위한 것입니다. 또한 **이해**하고 **여러분만의 async 코드**를 작성하도록 돕는 친절한 소개와 튜토리얼도 제공합니다: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. 특히 **async 코드와 일반**(blocking/동기) 코드를 **결합**해야 한다면 아주 유용합니다.
|
||||
### 비동기 코드의 다른 형태
|
||||
|
||||
### 비동기 코드의 다른 형태 { #other-forms-of-asynchronous-code }
|
||||
파이썬에서 `async`와 `await`를 사용하게 된 것은 비교적 최근의 일입니다.
|
||||
|
||||
`async`와 `await`를 사용하는 이 스타일은 언어에서 비교적 최근에 추가되었습니다.
|
||||
하지만 이로 인해 비동기 코드 작업이 훨씬 간단해졌습니다.
|
||||
|
||||
하지만 비동기 코드를 다루는 일을 훨씬 더 쉽게 만들어 줍니다.
|
||||
같은 (또는 거의 유사한) 문법은 최신 버전의 자바스크립트(브라우저와 NodeJS)에도 추가되었습니다.
|
||||
|
||||
거의 동일한 문법이 최근 브라우저와 NodeJS의 최신 JavaScript에도 포함되었습니다.
|
||||
하지만 그 이전에, 비동기 코드를 처리하는 것은 꽤 복잡하고 어려운 일이었습니다.
|
||||
|
||||
하지만 그 이전에는 비동기 코드를 처리하는 것이 훨씬 더 복잡하고 어려웠습니다.
|
||||
파이썬의 예전 버전이라면, 스레드 또는 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>를 사용할 수 있을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는게 훨씬 복잡합니다.
|
||||
|
||||
이전 버전의 파이썬에서는 스레드 또는 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>를 사용할 수 있었을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는 것이 훨씬 더 복잡합니다.
|
||||
예전 버전의 NodeJS / 브라우저 자바스크립트라면, "콜백 함수"를 사용했을 것입니다. 그리고 이로 인해 "콜백 지옥"에 빠지게 될 수 있습니다.
|
||||
|
||||
이전 버전의 NodeJS/브라우저 JavaScript에서는 "callback"을 사용했을 것입니다. 이는 "callback hell"로 이어집니다.
|
||||
## 코루틴
|
||||
|
||||
## 코루틴 { #coroutines }
|
||||
**코루틴**은 `async def` 함수가 반환하는 것을 칭하는 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 시작되고 어느 시점에서 완료되지만 내부에 `await`가 있을 때마다 내부적으로 일시정지⏸될 수도 있는 함수와 유사한 것이라는 사실을 알고있습니다.
|
||||
|
||||
**코루틴**은 `async def` 함수가 반환하는 것에 대한 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 함수와 비슷한 무언가로서 시작할 수 있고, 어느 시점에 끝나지만, 내부에 `await`가 있을 때마다 내부적으로도 일시정지 ⏸ 될 수 있다는 것을 알고 있습니다.
|
||||
그러나 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능들은 "코루틴"으로 간단히 요약됩니다. 이것은 Go의 주된 핵심 기능인 "고루틴"에 견줄 수 있습니다.
|
||||
|
||||
하지만 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능은 종종 "코루틴"을 사용한다고 요약됩니다. 이는 Go의 주요 핵심 기능인 "Goroutines"에 비견됩니다.
|
||||
## 결론
|
||||
|
||||
## 결론 { #conclusion }
|
||||
|
||||
위의 같은 문장을 다시 봅시다:
|
||||
상기 문장을 다시 한 번 봅시다:
|
||||
|
||||
> 최신 파이썬 버전은 **`async` 및 `await`** 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
|
||||
|
||||
이제 더 이해가 될 것입니다. ✨
|
||||
이제 이 말을 조금 더 이해할 수 있을 것입니다. ✨
|
||||
|
||||
이 모든 것이 FastAPI(Starlette을 통해)를 구동하고, 인상적인 성능을 내게 하는 원동력입니다.
|
||||
이것이 (Starlette을 통해) FastAPI를 강하게 하면서 그것이 인상적인 성능을 낼 수 있게 합니다.
|
||||
|
||||
## 매우 세부적인 기술적 사항 { #very-technical-details }
|
||||
## 매우 세부적인 기술적 사항
|
||||
|
||||
/// warning | 경고
|
||||
|
||||
이 부분은 아마 건너뛰어도 됩니다.
|
||||
이 부분은 넘어가도 됩니다.
|
||||
|
||||
이것들은 **FastAPI**가 내부적으로 어떻게 동작하는지에 대한 매우 세부적인 기술사항입니다.
|
||||
|
||||
코루틴, 스레드, 블로킹 등) 같은 기술 지식이 꽤 있고 FastAPI가 `async def`와 일반 `def`를 어떻게 처리하는지 궁금하다면, 계속 읽어보세요.
|
||||
만약 기술적 지식(코루틴, 스레드, 블록킹 등)이 있고 FastAPI가 어떻게 `async def` vs `def`를 다루는지 궁금하다면, 계속하십시오.
|
||||
|
||||
///
|
||||
|
||||
### 경로 처리 함수 { #path-operation-functions }
|
||||
### 경로 작동 함수
|
||||
|
||||
*경로 처리 함수*를 `async def` 대신 일반적인 `def`로 선언하면, (서버를 블로킹할 수 있으므로 직접 호출하는 대신) 외부 스레드풀에서 실행되고 그 결과를 await 합니다.
|
||||
경로 작동 함수를 `async def` 대신 일반적인 `def`로 선언하는 경우, (서버를 차단하는 것처럼) 그것을 직접 호출하는 대신 대기중인 외부 스레드풀에서 실행됩니다.
|
||||
|
||||
위에서 설명한 방식으로 동작하지 않는 다른 async 프레임워크를 사용해본 적이 있고, 아주 작은 성능 향상(약 100 나노초)을 위해 계산만 하는 사소한 *경로 처리 함수*를 일반 `def`로 정의하곤 했다면, **FastAPI**에서는 그 효과가 정반대가 될 수 있다는 점에 유의하세요. 이런 경우에는 *경로 처리 함수*에서 블로킹 <abbr title="Input/Output: disk reading or writing, network communications. - 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr> 를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.
|
||||
만약 상기에 묘사된대로 동작하지 않는 비동기 프로그램을 사용해왔고 약간의 성능 향상 (약 100 나노초)을 위해 `def`를 사용해서 계산만을 위한 사소한 *경로 작동 함수*를 정의해왔다면, **FastAPI**는 이와는 반대라는 것에 주의하십시오. 이러한 경우에, *경로 작동 함수*가 블로킹 <abbr title="Input/Output: 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr>를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.
|
||||
|
||||
그럼에도 두 경우 모두, **FastAPI**는 이전에 사용하던 프레임워크보다 [여전히 더 빠를](index.md#performance){.internal-link target=_blank} 가능성이 높습니다(또는 최소한 비슷합니다).
|
||||
하지만 두 경우 모두, FastAPI가 당신이 전에 사용하던 프레임워크보다 [더 빠를](index.md#_11){.internal-link target=_blank} (최소한 비견될) 확률이 높습니다.
|
||||
|
||||
### 의존성 { #dependencies }
|
||||
### 의존성
|
||||
|
||||
[의존성](tutorial/dependencies/index.md){.internal-link target=_blank}에도 동일하게 적용됩니다. 의존성이 `async def` 대신 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.
|
||||
의존성에도 동일하게 적용됩니다. 의존성이 `async def`가 아닌 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.
|
||||
|
||||
### 하위 의존성 { #sub-dependencies }
|
||||
### 하위-의존성
|
||||
|
||||
서로를 필요로 하는 여러 의존성과 [하위 의존성](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}을 함수 정의의 매개변수로 가질 수 있으며, 그중 일부는 `async def`로, 다른 일부는 일반 `def`로 생성되었을 수 있습니다. 그래도 정상 동작하며, 일반 `def`로 생성된 것들은 "await"되는 대신 (스레드풀에서) 외부 스레드에서 호출됩니다.
|
||||
함수 정의시 매개변수로 서로를 필요로하는 다수의 의존성과 하위-의존성을 가질 수 있고, 그 중 일부는 `async def`로, 다른 일부는 일반적인 `def`로 생성되었을 수 있습니다. 이것은 여전히 잘 동작하고, 일반적인 `def`로 생성된 것들은 "대기"되는 대신에 (스레드풀로부터) 외부 스레드에서 호출됩니다.
|
||||
|
||||
### 다른 유틸리티 함수 { #other-utility-functions }
|
||||
### 다른 유틸리티 함수
|
||||
|
||||
직접 호출하는 다른 모든 유틸리티 함수는 일반 `def`나 `async def`로 생성될 수 있으며, FastAPI는 호출 방식에 영향을 주지 않습니다.
|
||||
직접 호출되는 다른 모든 유틸리티 함수는 일반적인 `def`나 `async def`로 생성될 수 있고 FastAPI는 이를 호출하는 방식에 영향을 미치지 않습니다.
|
||||
|
||||
이는 FastAPI가 여러분을 위해 호출하는 함수(즉, *경로 처리 함수*와 의존성)와 대비됩니다.
|
||||
이것은 FastAPI가 당신을 위해 호출하는 함수와는 반대입니다: *경로 작동 함수*와 의존성
|
||||
|
||||
유틸리티 함수가 `def`로 만든 일반 함수라면, 스레드풀이 아니라 직접(코드에 작성한 대로) 호출됩니다. 그리고 `async def`로 생성된 함수라면, 코드에서 호출할 때 그 함수를 `await` 해야 합니다.
|
||||
만약 당신의 유틸리티 함수가 `def`를 사용한 일반적인 함수라면, 스레드풀에서가 아니라 직접 호출(당신이 코드에 작성한 대로)될 것이고, `async def`로 생성된 함수라면 코드에서 호출할 때 그 함수를 `await` 해야 합니다.
|
||||
|
||||
---
|
||||
|
||||
다시 말하지만, 이것들은 아마도 이를 찾고 있었던 경우에 유용한 매우 세부적인 기술사항입니다.
|
||||
다시 말하지만, 이것은 당신이 이것에 대해 찾고있던 경우에 한해 유용할 매우 세부적인 기술사항입니다.
|
||||
|
||||
그렇지 않다면, 위 섹션의 가이드라인이면 충분합니다: <a href="#in-a-hurry">바쁘신가요?</a>.
|
||||
그렇지 않은 경우, 상기의 가이드라인만으로도 충분할 것입니다: [바쁘신 경우](#_1).
|
||||
|
||||
@@ -1,75 +1,83 @@
|
||||
# FastAPI CLI { #fastapi-cli }
|
||||
# FastAPI CLI
|
||||
|
||||
**FastAPI CLI**는 FastAPI 앱을 서빙하고, FastAPI 프로젝트를 관리하는 등 다양한 작업에 사용할 수 있는 커맨드 라인 프로그램입니다.
|
||||
**FastAPI CLI**는 FastAPI 애플리케이션을 실행하고, 프로젝트를 관리하는 등 다양한 작업을 수행할 수 있는 커맨드 라인 프로그램입니다.
|
||||
|
||||
FastAPI를 설치할 때(예: `pip install "fastapi[standard]"`), `fastapi-cli`라는 패키지가 포함되며, 이 패키지는 터미널에서 `fastapi` 명령을 제공합니다.
|
||||
FastAPI를 설치할 때 (예: `pip install "fastapi[standard]"` 명령어를 사용할 경우), `fastapi-cli`라는 패키지가 포함됩니다. 이 패키지는 터미널에서 사용할 수 있는 `fastapi` 명령어를 제공합니다.
|
||||
|
||||
개발용으로 FastAPI 앱을 실행하려면 `fastapi dev` 명령을 사용할 수 있습니다:
|
||||
개발용으로 FastAPI 애플리케이션을 실행하려면 다음과 같이 `fastapi dev` 명령어를 사용할 수 있습니다:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:single">main.py</u>
|
||||
<font color="#3465A4">INFO </font> Using path <font color="#3465A4">main.py</font>
|
||||
<font color="#3465A4">INFO </font> Resolved absolute path <font color="#75507B">/home/user/code/awesomeapp/</font><font color="#AD7FA8">main.py</font>
|
||||
<font color="#3465A4">INFO </font> Searching for package file structure from directories with <font color="#3465A4">__init__.py</font> files
|
||||
<font color="#3465A4">INFO </font> Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮
|
||||
│ │
|
||||
│ 🐍 main.py │
|
||||
│ │
|
||||
╰──────────────────────╯
|
||||
|
||||
Searching for package file structure from directories with
|
||||
<font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font>
|
||||
<font color="#3465A4">INFO </font> Found importable FastAPI app
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
╭─ <font color="#8AE234"><b>Importable FastAPI app</b></font> ─╮
|
||||
│ │
|
||||
│ <span style="background-color:#272822"><font color="#FF4689">from</font></span><span style="background-color:#272822"><font color="#F8F8F2"> main </font></span><span style="background-color:#272822"><font color="#FF4689">import</font></span><span style="background-color:#272822"><font color="#F8F8F2"> app</font></span><span style="background-color:#272822"> </span> │
|
||||
│ │
|
||||
╰──────────────────────────╯
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
|
||||
following code:
|
||||
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font>
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">╭────────── FastAPI CLI - Development mode ───────────╮</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ Serving at: http://127.0.0.1:8000 │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ API docs: http://127.0.0.1:8000/docs │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ Running in development mode, for production use: │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ </font></span><span style="background-color:#C4A000"><font color="#555753"><b>fastapi run</b></font></span><span style="background-color:#C4A000"><font color="#2E3436"> │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
|
||||
<span style="background-color:#C4A000"><font color="#2E3436">╰─────────────────────────────────────────────────────╯</font></span>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to
|
||||
quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<font color="#4E9A06">INFO</font>: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
||||
<font color="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
|
||||
<font color="#4E9A06">INFO</font>: Started reloader process [<font color="#34E2E2"><b>2265862</b></font>] using <font color="#34E2E2"><b>WatchFiles</b></font>
|
||||
<font color="#4E9A06">INFO</font>: Started server process [<font color="#06989A">2265873</font>]
|
||||
<font color="#4E9A06">INFO</font>: Waiting for application startup.
|
||||
<font color="#4E9A06">INFO</font>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
`fastapi`라고 불리는 커맨드 라인 프로그램은 **FastAPI CLI**입니다.
|
||||
`fastapi`라고 불리는 명령어 프로그램은 **FastAPI CLI**입니다.
|
||||
|
||||
FastAPI CLI는 Python 프로그램의 경로(예: `main.py`)를 받아 `FastAPI` 인스턴스(일반적으로 `app`으로 이름을 붙임)를 자동으로 감지하고, 올바른 임포트 과정을 결정한 다음 서빙합니다.
|
||||
FastAPI CLI는 Python 프로그램의 경로(예: `main.py`)를 인수로 받아, `FastAPI` 인스턴스(일반적으로 `app`으로 명명)를 자동으로 감지하고 올바른 임포트 과정을 결정한 후 이를 실행합니다.
|
||||
|
||||
프로덕션에서는 대신 `fastapi run`을 사용합니다. 🚀
|
||||
프로덕션 환경에서는 `fastapi run` 명령어를 사용합니다. 🚀
|
||||
|
||||
내부적으로 **FastAPI CLI**는 고성능의, 프로덕션에 적합한 ASGI 서버인 <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>을 사용합니다. 😎
|
||||
내부적으로, **FastAPI CLI**는 고성능의, 프로덕션에 적합한, ASGI 서버인 <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>을 사용합니다. 😎
|
||||
|
||||
## `fastapi dev` { #fastapi-dev }
|
||||
## `fastapi dev`
|
||||
|
||||
`fastapi dev`를 실행하면 개발 모드가 시작됩니다.
|
||||
`fastapi dev` 명령을 실행하면 개발 모드가 시작됩니다.
|
||||
|
||||
기본적으로 **auto-reload**가 활성화되어 코드에 변경이 생기면 서버를 자동으로 다시 로드합니다. 이는 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 개발 환경에서만 사용해야 합니다. 또한 컴퓨터가 자신과만 통신하기 위한(`localhost`) IP인 `127.0.0.1`에서 연결을 대기합니다.
|
||||
기본적으로 **자동 재시작(auto-reload)** 기능이 활성화되어, 코드에 변경이 생기면 서버를 자동으로 다시 시작합니다. 하지만 이 기능은 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 따라서 개발 환경에서만 사용하는 것이 좋습니다. 또한, 서버는 컴퓨터가 자체적으로 통신할 수 있는 IP 주소(`localhost`)인 `127.0.0.1`에서 연결을 대기합니다.
|
||||
|
||||
## `fastapi run` { #fastapi-run }
|
||||
## `fastapi run`
|
||||
|
||||
`fastapi run`을 실행하면 기본적으로 프로덕션 모드로 FastAPI가 시작됩니다.
|
||||
`fastapi run` 명령을 실행하면 기본적으로 프로덕션 모드로 FastAPI가 시작됩니다.
|
||||
|
||||
기본적으로 **auto-reload**는 비활성화되어 있습니다. 또한 사용 가능한 모든 IP 주소를 의미하는 `0.0.0.0`에서 연결을 대기하므로, 해당 컴퓨터와 통신할 수 있는 누구에게나 공개적으로 접근 가능해집니다. 보통 프로덕션에서는 이렇게 실행하며, 예를 들어 컨테이너에서 이런 방식으로 실행합니다.
|
||||
기본적으로 **자동 재시작(auto-reload)** 기능이 비활성화되어 있습니다. 또한, 사용 가능한 모든 IP 주소인 `0.0.0.0`에서 연결을 대기하므로 해당 컴퓨터와 통신할 수 있는 모든 사람이 공개적으로 액세스할 수 있습니다. 이는 일반적으로 컨테이너와 같은 프로덕션 환경에서 실행하는 방법입니다.
|
||||
|
||||
대부분의 경우 위에 "termination proxy"를 두고 HTTPS를 처리하게(그리고 처리해야) 됩니다. 이는 애플리케이션을 배포하는 방식에 따라 달라지며, 제공자가 이 작업을 대신 처리해줄 수도 있고 직접 설정해야 할 수도 있습니다.
|
||||
애플리케이션을 배포하는 방식에 따라 다르지만, 대부분 "종료 프록시(termination proxy)"를 활용해 HTTPS를 처리하는 것이 좋습니다. 배포 서비스 제공자가 이 작업을 대신 처리해줄 수도 있고, 직접 설정해야 할 수도 있습니다.
|
||||
|
||||
/// tip | 팁
|
||||
/// tip
|
||||
|
||||
자세한 내용은 [deployment documentation](deployment/index.md){.internal-link target=_blank}에서 확인할 수 있습니다.
|
||||
자세한 내용은 [deployment documentation](deployment/index.md){.internal-link target=\_blank}에서 확인할 수 있습니다.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
# 기능 { #features }
|
||||
# 기능
|
||||
|
||||
## FastAPI의 기능 { #fastapi-features }
|
||||
## FastAPI의 기능
|
||||
|
||||
**FastAPI**는 다음과 같은 기능을 제공합니다:
|
||||
|
||||
### 개방형 표준을 기반으로 { #based-on-open-standards }
|
||||
### 개방형 표준을 기반으로
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>: <abbr title="also known as: endpoints, routes - 엔드포인트, 라우트로도 알려져 있습니다">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE - POST, GET, PUT, DELETE와 같은 HTTP 메소드로 알려져 있습니다">operations</abbr>, 매개변수, 요청 본문, 보안 등의 선언을 포함하여 API를 생성합니다.
|
||||
* <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a>를 사용한 자동 데이터 모델 문서화(OpenAPI 자체가 JSON Schema를 기반으로 하기 때문입니다).
|
||||
* 단순히 떠올려서 덧붙인 레이어가 아니라, 세심한 검토를 거친 뒤 이러한 표준을 중심으로 설계되었습니다.
|
||||
* 이는 또한 다양한 언어로 자동 **클라이언트 코드 생성**을 사용할 수 있게 해줍니다.
|
||||
* <abbr title="엔드포인트, 라우트로도 알려져 있습니다">경로</abbr><abbr title="POST, GET, PUT, DELETE와 같은 HTTP 메소드로 알려져 있습니다">작동</abbr>, 매개변수, 본문 요청, 보안 그 외의 선언을 포함한 API 생성을 위한 <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>
|
||||
* <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (OpenAPI 자체가 JSON Schema를 기반으로 하고 있습니다)를 사용한 자동 데이터 모델 문서화.
|
||||
* 단순히 떠올려서 덧붙인 기능이 아닙니다. 세심한 검토를 거친 후, 이러한 표준을 기반으로 설계되었습니다.
|
||||
* 이는 또한 다양한 언어로 자동적인 **클라이언트 코드 생성**을 사용할 수 있게 지원합니다.
|
||||
|
||||
### 문서 자동화 { #automatic-docs }
|
||||
### 문서 자동화
|
||||
|
||||
대화형 API 문서와 탐색용 웹 사용자 인터페이스를 제공합니다. 프레임워크가 OpenAPI를 기반으로 하기에 여러 옵션이 있으며, 기본으로 2가지가 포함됩니다.
|
||||
대화형 API 문서와 웹 탐색 유저 인터페이스를 제공합니다. 프레임워크가 OpenAPI를 기반으로 하기에, 2가지 옵션이 기본적으로 들어간 여러 옵션이 존재합니다.
|
||||
|
||||
* 대화형 탐색이 가능한 <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>로 브라우저에서 직접 API를 호출하고 테스트할 수 있습니다.
|
||||
* 대화형 탐색 <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>를 이용해, 브라우저에서 바로 여러분의 API를 호출하거나 테스트할 수 있습니다.
|
||||
|
||||

|
||||
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>을 이용한 대체 API 문서화.
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>을 이용해 API 문서화를 대체할 수 있습니다.
|
||||
|
||||

|
||||
|
||||
### 그저 현대 파이썬 { #just-modern-python }
|
||||
### 그저 현대 파이썬
|
||||
|
||||
( Pydantic 덕분에) 모든 것이 표준 **Python 타입** 선언을 기반으로 합니다. 새로 배울 문법이 없습니다. 그저 표준적인 현대 파이썬입니다.
|
||||
(Pydantic 덕분에) FastAPI는 표준 **파이썬 3.6 타입** 선언에 기반하고 있습니다. 새로 배울 문법이 없습니다. 그저 표준적인 현대 파이썬입니다.
|
||||
|
||||
Python 타입을 어떻게 사용하는지 2분 정도 복습이 필요하다면(FastAPI를 사용하지 않더라도), 다음의 짧은 자습서를 확인하세요: [Python Types](python-types.md){.internal-link target=_blank}.
|
||||
만약 여러분이 파이썬 타입을 어떻게 사용하는지에 대한 2분 정도의 복습이 필요하다면 (비록 여러분이 FastAPI를 사용하지 않는다 하더라도), 다음의 짧은 자습서를 확인하세요: [파이썬 타입](python-types.md){.internal-link target=\_blank}.
|
||||
|
||||
여러분은 타입이 있는 표준 Python을 다음과 같이 작성합니다:
|
||||
여러분은 타입을 이용한 표준 파이썬을 다음과 같이 적을 수 있습니다:
|
||||
|
||||
```Python
|
||||
from datetime import date
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Declare a variable as a str
|
||||
# and get editor support inside the function
|
||||
# 변수를 str로 선언
|
||||
# 그 후 함수 안에서 편집기 지원을 받으세요
|
||||
def main(user_id: str):
|
||||
return user_id
|
||||
|
||||
|
||||
# A Pydantic model
|
||||
# Pydantic 모델
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
joined: date
|
||||
```
|
||||
|
||||
그 다음 다음과 같이 사용할 수 있습니다:
|
||||
위의 코드는 다음과 같이 사용될 수 있습니다:
|
||||
|
||||
```Python
|
||||
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
|
||||
@@ -65,23 +65,23 @@ my_second_user: User = User(**second_user_data)
|
||||
|
||||
/// info | 정보
|
||||
|
||||
`**second_user_data`는 다음을 의미합니다:
|
||||
`**second_user_data`가 뜻하는 것:
|
||||
|
||||
`second_user_data` `dict`의 키와 값을 키-값 인자로서 바로 넘겨주는 것으로, 다음과 동일합니다: `User(id=4, name="Mary", joined="2018-11-30")`
|
||||
`second_user_data` 딕셔너리의 키와 값을 키-값 인자로서 바로 넘겨줍니다. 다음과 동일합니다: `User(id=4, name="Mary", joined="2018-11-30")`
|
||||
|
||||
///
|
||||
|
||||
### 편집기 지원 { #editor-support }
|
||||
### 편집기 지원
|
||||
|
||||
프레임워크 전체는 사용하기 쉽고 직관적으로 설계되었으며, 최고의 개발 경험을 보장하기 위해 개발을 시작하기도 전에 모든 결정은 여러 편집기에서 테스트되었습니다.
|
||||
모든 프레임워크는 사용하기 쉽고 직관적으로 설계되었으며, 좋은 개발 경험을 보장하기 위해 개발을 시작하기도 전에 모든 결정들은 여러 편집기에서 테스트됩니다.
|
||||
|
||||
Python 개발자 설문조사에서 <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">가장 많이 사용되는 기능 중 하나가 "자동 완성"이라는 점</a>이 분명합니다.
|
||||
최근 파이썬 개발자 설문조사에서 <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">"자동 완성"이 가장 많이 사용되는 기능</a>이라는 것이 밝혀졌습니다.
|
||||
|
||||
**FastAPI** 프레임워크 전체는 이를 만족하기 위해 만들어졌습니다. 자동 완성은 어디서나 작동합니다.
|
||||
**FastAPI** 프레임워크의 모든 부분은 이를 충족하기 위해 설계되었습니다. 자동완성은 어느 곳에서나 작동합니다.
|
||||
|
||||
문서로 다시 돌아올 일은 거의 없을 것입니다.
|
||||
여러분은 문서로 다시 돌아올 일이 거의 없을 겁니다.
|
||||
|
||||
편집기가 여러분을 어떻게 도와줄 수 있는지 살펴보세요:
|
||||
다음은 편집기가 어떻게 여러분을 도와주는지 보여줍니다:
|
||||
|
||||
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>에서:
|
||||
|
||||
@@ -91,111 +91,111 @@ Python 개발자 설문조사에서 <a href="https://www.jetbrains.com/research/
|
||||
|
||||

|
||||
|
||||
이전에 불가능하다고 생각했을 코드에서도 자동 완성을 받을 수 있습니다. 예를 들어, 요청에서 전달되는(중첩될 수도 있는) JSON 본문 내부의 `price` 키 같은 경우입니다.
|
||||
여러분이 이전에 불가능하다고 고려했던 코드도 완성할 수 있을 겁니다. 예를 들어, 요청에서 전달되는 (중첩될 수도 있는)JSON 본문 내부에 있는 `price` 키입니다.
|
||||
|
||||
더 이상 잘못된 키 이름을 입력하거나, 문서 사이를 왔다 갔다 하거나, `username`을 썼는지 `user_name`을 썼는지 찾으려고 위아래로 스크롤할 필요가 없습니다.
|
||||
잘못된 키 이름을 적을 일도, 문서를 왔다 갔다할 일도 없으며, 혹은 마지막으로 `username` 또는 `user_name`을 사용했는지 찾기 위해 위 아래로 스크롤할 일도 없습니다.
|
||||
|
||||
### 간결함 { #short }
|
||||
### 토막 정보
|
||||
|
||||
선택적 구성을 어디서나 할 수 있도록 하면서도, 모든 것에 합리적인 **기본값**이 설정되어 있습니다. 모든 매개변수는 필요한 작업을 하거나 필요한 API를 정의하기 위해 미세하게 조정할 수 있습니다.
|
||||
어느 곳에서나 선택적 구성이 가능한 모든 것에 합리적인 기본값이 설정되어 있습니다. 모든 매개변수는 여러분이 필요하거나, 원하는 API를 정의하기 위해 미세하게 조정할 수 있습니다.
|
||||
|
||||
하지만 기본적으로 모든 것이 **"그냥 작동합니다"**.
|
||||
하지만 기본적으로 모든 것이 "그냥 작동합니다".
|
||||
|
||||
### 검증 { #validation }
|
||||
### 검증
|
||||
|
||||
* 다음을 포함해 대부분(혹은 전부?)의 Python **데이터 타입**에 대한 검증:
|
||||
* 다음을 포함한, 대부분의 (혹은 모든?) 파이썬 **데이터 타입** 검증할 수 있습니다:
|
||||
* JSON 객체 (`dict`).
|
||||
* 아이템 타입을 정의하는 JSON 배열 (`list`).
|
||||
* 최소/최대 길이를 정의하는 문자열(`str`) 필드.
|
||||
* 최소/최대 값을 가지는 숫자(`int`, `float`) 등.
|
||||
* 최소 길이와 최대 길이를 정의하는 문자열 (`str`) 필드.
|
||||
* 최솟값과 최댓값을 가지는 숫자 (`int`, `float`), 그 외.
|
||||
|
||||
* 다음과 같은 좀 더 이색적인 타입에 대한 검증:
|
||||
* 다음과 같이 더욱 이색적인 타입에 대해 검증할 수 있습니다:
|
||||
* URL.
|
||||
* Email.
|
||||
* 이메일.
|
||||
* UUID.
|
||||
* ...그 외.
|
||||
* ...다른 것들.
|
||||
|
||||
모든 검증은 잘 확립되어 있고 견고한 **Pydantic**이 처리합니다.
|
||||
모든 검증은 견고하면서 잘 확립된 **Pydantic**에 의해 처리됩니다.
|
||||
|
||||
### 보안과 인증 { #security-and-authentication }
|
||||
### 보안과 인증
|
||||
|
||||
보안과 인증이 통합되어 있습니다. 데이터베이스나 데이터 모델과 타협하지 않습니다.
|
||||
보안과 인증이 통합되어 있습니다. 데이터베이스나 데이터 모델과의 타협없이 사용할 수 있습니다.
|
||||
|
||||
다음을 포함해 OpenAPI에 정의된 모든 보안 스키마:
|
||||
다음을 포함하는, 모든 보안 스키마가 OpenAPI에 정의되어 있습니다.
|
||||
|
||||
* HTTP Basic.
|
||||
* **OAuth2**(**JWT tokens** 또한 포함). [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank} 자습서를 확인해 보세요.
|
||||
* **OAuth2** (**JWT tokens** 또한 포함). [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=\_blank}에 있는 자습서를 확인해 보세요.
|
||||
* 다음에 들어 있는 API 키:
|
||||
* 헤더.
|
||||
* 쿼리 매개변수.
|
||||
* 쿠키 등.
|
||||
* 매개변수.
|
||||
* 쿠키 및 그 외.
|
||||
|
||||
추가로 Starlette의 모든 보안 기능(**세션 쿠키** 포함)도 제공합니다.
|
||||
추가적으로 (**세션 쿠키**를 포함한) 모든 보안 기능은 Starlette에 있습니다.
|
||||
|
||||
모두 재사용 가능한 도구와 컴포넌트로 만들어져 있어, 여러분의 시스템, 데이터 저장소, 관계형 및 NoSQL 데이터베이스 등과 쉽게 통합할 수 있습니다.
|
||||
모두 재사용할 수 있는 도구와 컴포넌트로 만들어져 있어 여러분의 시스템, 데이터 저장소, 관계형 및 NoSQL 데이터베이스 등과 쉽게 통합할 수 있습니다.
|
||||
|
||||
### 의존성 주입 { #dependency-injection }
|
||||
### 의존성 주입
|
||||
|
||||
FastAPI는 사용하기 매우 쉽지만, 매우 강력한 <abbr title='also known as "components", "resources", "services", "providers" - "컴포넌트", "자원", "서비스", "제공자"로도 알려진'><strong>Dependency Injection</strong></abbr> 시스템을 포함하고 있습니다.
|
||||
FastAPI는 사용하기 매우 간편하지만, 엄청난 <abbr title='"컴포넌트", "자원", "서비스", "제공자"로도 알려진'><strong>의존성 주입</strong></abbr>시스템을 포함하고 있습니다.
|
||||
|
||||
* 의존성도 의존성을 가질 수 있어, 의존성의 계층 또는 **의존성의 "그래프"**를 생성합니다.
|
||||
* 모든 것이 프레임워크에 의해 **자동으로 처리됩니다**.
|
||||
* 모든 의존성은 요청에서 데이터를 요구할 수 있으며, **경로 처리** 제약과 자동 문서화를 강화할 수 있습니다.
|
||||
* 의존성에 정의된 *경로 처리* 매개변수에 대해서도 **자동 검증**을 합니다.
|
||||
* 복잡한 사용자 인증 시스템, **데이터베이스 연결** 등을 지원합니다.
|
||||
* 데이터베이스, 프론트엔드 등과 **타협하지 않습니다**. 하지만 모두와 쉽게 통합할 수 있습니다.
|
||||
* 의존성은 의존성을 가질수도 있어, 이를 통해 의존성의 계층이나 **의존성의 "그래프"**를 형성합니다.
|
||||
* 모든 것이 프레임워크에 의해 **자동적으로 처리됩니다**.
|
||||
* 모든 의존성은 요청에서 데이터를 요구하여 자동 문서화와 **경로 작동 제약을 강화할 수 있습니다**.
|
||||
* 의존성에서 정의된 _경로 작동_ 매개변수에 대해서도 **자동 검증**이 이루어 집니다.
|
||||
* 복잡한 사용자의 인증 시스템, **데이터베이스 연결**, 등등을 지원합니다.
|
||||
* 데이터베이스, 프론트엔드 등과 관련되어 **타협하지 않아도 됩니다**. 하지만 그 모든 것과 쉽게 통합이 가능합니다.
|
||||
|
||||
### 제한 없는 "플러그인" { #unlimited-plug-ins }
|
||||
### 제한 없는 "플러그인"
|
||||
|
||||
또 다른 방식으로는, 그것들이 필요 없습니다. 필요한 코드를 임포트해서 사용하면 됩니다.
|
||||
또는 다른 방법으로, 그것들을 사용할 필요 없이 필요한 코드만 임포트할 수 있습니다.
|
||||
|
||||
어떤 통합이든(의존성과 함께) 사용하기 매우 간단하도록 설계되어 있어, *경로 처리*에 사용된 것과 동일한 구조와 문법을 사용해 2줄의 코드로 애플리케이션용 "플러그인"을 만들 수 있습니다.
|
||||
어느 통합도 (의존성과 함께) 사용하기 쉽게 설계되어 있어, *경로 작동*에 사용된 것과 동일한 구조와 문법을 사용하여 2줄의 코드로 여러분의 어플리케이션에 사용할 "플러그인"을 만들 수 있습니다.
|
||||
|
||||
### 테스트됨 { #tested }
|
||||
### 테스트 결과
|
||||
|
||||
* 100% <abbr title="The amount of code that is automatically tested - 자동으로 테스트되는 코드의 양">test coverage</abbr>.
|
||||
* 100% <abbr title="Python type annotations, with this your editor and external tools can give you better support - Python 타입 어노테이션으로, 이를 통해 편집기와 외부 도구가 더 나은 지원을 제공할 수 있습니다">type annotated</abbr> 코드 베이스.
|
||||
* 프로덕션 애플리케이션에서 사용됩니다.
|
||||
* 100% <abbr title="자동적으로 테스트된 코드의 양">테스트 범위</abbr>.
|
||||
* 100% <abbr title="파이썬의 타입 어노테이션, 이를 통해 여러분의 편집기와 외부 도구는 여러분에게 더 나은 지원을 할 수 있습니다">타입이 명시된</abbr> 코드 베이스.
|
||||
* 상용 어플리케이션에서의 사용.
|
||||
|
||||
## Starlette 기능 { #starlette-features }
|
||||
## Starlette 기능
|
||||
|
||||
**FastAPI**는 <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a>와 완전히 호환되며(또한 이를 기반으로 합니다). 따라서 추가로 가지고 있는 Starlette 코드도 모두 동작합니다.
|
||||
**FastAPI**는 <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a>를 기반으로 구축되었으며, 이와 완전히 호환됩니다. 따라서, 여러분이 보유하고 있는 어떤 추가적인 Starlette 코드도 작동할 것입니다.
|
||||
|
||||
`FastAPI`는 실제로 `Starlette`의 하위 클래스입니다. 그래서 Starlette을 이미 알고 있거나 사용하고 있다면, 대부분의 기능이 같은 방식으로 동작할 것입니다.
|
||||
`FastAPI`는 실제로 `Starlette`의 하위 클래스입니다. 그래서, 여러분이 이미 Starlette을 알고 있거나 사용하고 있으면, 대부분의 기능이 같은 방식으로 작동할 것입니다.
|
||||
|
||||
**FastAPI**를 사용하면 **Starlette**의 모든 기능을 얻게 됩니다(FastAPI는 Starlette에 강력한 기능을 더한 것입니다):
|
||||
**FastAPI**를 사용하면 여러분은 **Starlette**의 기능 대부분을 얻게 될 것입니다(FastAPI가 단순히 Starlette를 강화했기 때문입니다):
|
||||
|
||||
* 정말 인상적인 성능. <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">**NodeJS**와 **Go**에 버금가는, 사용 가능한 가장 빠른 Python 프레임워크 중 하나입니다</a>.
|
||||
* 아주 인상적인 성능. 이는 <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">**NodeJS**와 **Go**와 동등하게 사용 가능한 가장 빠른 파이썬 프레임워크 중 하나입니다</a>.
|
||||
* **WebSocket** 지원.
|
||||
* 프로세스 내 백그라운드 작업.
|
||||
* 시작 및 종료 이벤트.
|
||||
* 프로세스 내의 백그라운드 작업.
|
||||
* 시작과 종료 이벤트.
|
||||
* HTTPX 기반 테스트 클라이언트.
|
||||
* **CORS**, GZip, 정적 파일, 스트리밍 응답.
|
||||
* **세션과 쿠키** 지원.
|
||||
* 100% test coverage.
|
||||
* 100% type annotated codebase.
|
||||
* 100% 테스트 범위.
|
||||
* 100% 타입이 명시된 코드 베이스.
|
||||
|
||||
## Pydantic 기능 { #pydantic-features }
|
||||
## Pydantic 기능
|
||||
|
||||
**FastAPI**는 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>과 완벽하게 호환되며(또한 이를 기반으로 합니다). 따라서 추가로 가지고 있는 Pydantic 코드도 모두 동작합니다.
|
||||
**FastAPI**는 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>을 기반으로 하며 Pydantic과 완벽하게 호환됩니다. 그래서 어느 추가적인 Pydantic 코드를 여러분이 가지고 있든 작동할 것입니다.
|
||||
|
||||
데이터베이스를 위한 <abbr title="Object-Relational Mapper">ORM</abbr>, <abbr title="Object-Document Mapper">ODM</abbr>과 같은, Pydantic을 기반으로 하는 외부 라이브러리도 포함합니다.
|
||||
Pydantic을 기반으로 하는, 데이터베이스를 위한 <abbr title="Object-Relational Mapper">ORM</abbr>, <abbr title="Object-Document Mapper">ODM</abbr>을 포함한 외부 라이브러리를 포함합니다.
|
||||
|
||||
이는 모든 것이 자동으로 검증되기 때문에, 많은 경우 요청에서 얻은 동일한 객체를 **직접 데이터베이스로** 넘겨줄 수 있다는 의미이기도 합니다.
|
||||
이는 모든 것이 자동으로 검증되기 때문에, 많은 경우에서 요청을 통해 얻은 동일한 객체를, **직접 데이터베이스로** 넘겨줄 수 있습니다.
|
||||
|
||||
반대로도 마찬가지이며, 많은 경우 데이터베이스에서 얻은 객체를 **직접 클라이언트로** 그대로 넘겨줄 수 있습니다.
|
||||
반대로도 마찬가지이며, 많은 경우에서 여러분은 **직접 클라이언트로** 그저 객체를 넘겨줄 수 있습니다.
|
||||
|
||||
**FastAPI**를 사용하면(모든 데이터 처리를 위해 FastAPI가 Pydantic을 기반으로 하기에) **Pydantic**의 모든 기능을 얻게 됩니다:
|
||||
**FastAPI**를 사용하면 (모든 데이터 처리를 위해 FastAPI가 Pydantic을 기반으로 하기 있기에) **Pydantic**의 모든 기능을 얻게 됩니다:
|
||||
|
||||
* **No brainfuck**:
|
||||
* 새로운 스키마 정의 마이크로 언어를 배울 필요가 없습니다.
|
||||
* Python 타입을 알고 있다면 Pydantic 사용법도 알고 있는 것입니다.
|
||||
* 여러분의 **<abbr title="Integrated Development Environment - 통합 개발 환경: 코드 편집기와 비슷합니다">IDE</abbr>/<abbr title="A program that checks for code errors - 코드 오류를 확인하는 프로그램">linter</abbr>/뇌**와 잘 어울립니다:
|
||||
* pydantic 데이터 구조는 여러분이 정의한 클래스 인스턴스일 뿐이므로, 자동 완성, 린팅, mypy, 그리고 직관까지도 검증된 데이터와 함께 제대로 작동합니다.
|
||||
* **어렵지 않은 언어**:
|
||||
* 새로운 스키마 정의 마이크로 언어를 배우지 않아도 됩니다.
|
||||
* 여러분이 파이썬 타입을 안다면, 여러분은 Pydantic을 어떻게 사용하는지 아는 겁니다.
|
||||
* 여러분의 **<abbr title="통합 개발 환경, 코드 편집기와 비슷합니다">IDE</abbr>/<abbr title="코드 에러를 확인하는 프로그램">린터</abbr>/뇌**와 잘 어울립니다:
|
||||
* Pydantic 데이터 구조는 단순 여러분이 정의한 클래스의 인스턴스이기 때문에, 자동 완성, 린팅, mypy 그리고 여러분의 직관까지 여러분의 검증된 데이터와 올바르게 작동합니다.
|
||||
* **복잡한 구조**를 검증합니다:
|
||||
* 계층적인 Pydantic 모델, Python `typing`의 `List`와 `Dict` 등을 사용합니다.
|
||||
* 그리고 validator는 복잡한 데이터 스키마를 명확하고 쉽게 정의하고, 검사하고, JSON Schema로 문서화할 수 있게 해줍니다.
|
||||
* 깊게 **중첩된 JSON** 객체를 가질 수 있으며, 이를 모두 검증하고 주석을 달 수 있습니다.
|
||||
* **확장 가능**:
|
||||
* Pydantic은 사용자 정의 데이터 타입을 정의할 수 있게 하거나, validator decorator가 붙은 모델 메서드로 검증을 확장할 수 있습니다.
|
||||
* 100% test coverage.
|
||||
* 계층적인 Pydantic 모델, 파이썬 `typing`의 `List`와 `Dict`, 그 외를 사용합니다.
|
||||
* 그리고 검증자는 복잡한 데이터 스키마를 명확하고 쉽게 정의 및 확인하며 JSON 스키마로 문서화합니다.
|
||||
* 여러분은 깊게 **중첩된 JSON** 객체를 가질 수 있으며, 이 객체 모두 검증하고 설명을 붙일 수 있습니다.
|
||||
* **확장 가능성**:
|
||||
* Pydantic은 사용자 정의 데이터 타입을 정의할 수 있게 하거나, 검증자 데코레이터가 붙은 모델의 메소드를 사용하여 검증을 확장할 수 있습니다.
|
||||
* 100% 테스트 범위.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# FastAPI 지원 - 도움 받기 { #help-fastapi-get-help }
|
||||
# FastAPI 지원 - 도움 받기
|
||||
|
||||
**FastAPI** 가 마음에 드시나요?
|
||||
|
||||
@@ -10,9 +10,9 @@ FastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?
|
||||
|
||||
또한 도움을 받을 수 있는 방법도 몇 가지 있습니다.
|
||||
|
||||
## 뉴스레터 구독 { #subscribe-to-the-newsletter }
|
||||
## 뉴스레터 구독
|
||||
|
||||
(자주 발송되지 않는) [**FastAPI and friends** 뉴스레터](newsletter.md){.internal-link target=_blank}를 구독하여 최신 정보를 유지할 수 있습니다:
|
||||
[**FastAPI and friends** 뉴스레터](newsletter.md){.internal-link target=\_blank}를 구독하여 최신 정보를 유지할 수 있습니다:
|
||||
|
||||
* FastAPI and friends에 대한 뉴스 🚀
|
||||
* 가이드 📝
|
||||
@@ -20,65 +20,65 @@ FastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?
|
||||
* 획기적인 변화 🚨
|
||||
* 팁과 요령 ✅
|
||||
|
||||
## X(Twitter)에서 FastAPI 팔로우하기 { #follow-fastapi-on-x-twitter }
|
||||
## 트위터에서 FastAPI 팔로우하기
|
||||
|
||||
<a href="https://x.com/fastapi" class="external-link" target="_blank">**X (Twitter)**의 @fastapi를 팔로우</a>하여 **FastAPI** 에 대한 최신 뉴스를 얻을 수 있습니다. 🐦
|
||||
|
||||
## GitHub에서 **FastAPI**에 Star 주기 { #star-fastapi-in-github }
|
||||
## Star **FastAPI** in GitHub
|
||||
|
||||
GitHub에서 FastAPI에 "star"를 붙일 수 있습니다 (오른쪽 상단의 star 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️
|
||||
|
||||
스타를 늘림으로써, 다른 사용자들이 좀 더 쉽게 찾을 수 있고, 많은 사람들에게 유용한 것임을 나타낼 수 있습니다.
|
||||
|
||||
## 릴리즈 확인을 위해 GitHub 저장소 보기 { #watch-the-github-repository-for-releases }
|
||||
## GitHub 저장소에서 릴리즈 확인
|
||||
|
||||
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 "watch" 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
|
||||
여기서 "Releases only"를 선택할 수 있습니다.
|
||||
여기서 "Releases only"을 선택할 수 있습니다.
|
||||
|
||||
이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 릴리즈(새 버전)가 있을 때마다 (이메일) 통지를 받을 수 있습니다.
|
||||
이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 자료 (최신 버전)이 있을 때마다 (이메일) 통지를 받을 수 있습니다.
|
||||
|
||||
## 개발자와의 연결 { #connect-with-the-author }
|
||||
## 개발자와의 연결
|
||||
|
||||
개발자(작성자)인 <a href="https://tiangolo.com" class="external-link" target="_blank">저(Sebastián Ramírez / `tiangolo`)</a>와 연락을 취할 수 있습니다.
|
||||
<a href="https://tiangolo.com" class="external-link" target="_blank">개발자(Sebastián Ramírez / `tiangolo`)</a>와 연락을 취할 수 있습니다.
|
||||
|
||||
여러분은 할 수 있습니다:
|
||||
|
||||
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">**GitHub**에서 팔로우하기</a>.
|
||||
* 여러분에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.
|
||||
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">**GitHub**에서 팔로우하기.</a>.
|
||||
* 당신에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.
|
||||
* 새로운 오픈소스 프로젝트를 만들었을 때 확인하려면 팔로우 하십시오.
|
||||
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">**X (Twitter)**</a> 또는 <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>에서 팔로우하기.
|
||||
* FastAPI의 사용 용도를 알려주세요 (그것을 듣는 것을 좋아합니다).
|
||||
* 발표나 새로운 툴 출시 소식을 받아보십시오.
|
||||
* <a href="https://x.com/fastapi" class="external-link" target="_blank">X(Twitter)에서 @fastapi를 팔로우</a> (별도 계정에서) 할 수 있습니다.
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">**LinkedIn**에서 팔로우하기</a>.
|
||||
* 새로운 툴의 발표나 출시 소식을 받아보십시오 (단, X (Twitter)를 더 자주 사용합니다 🤷♂).
|
||||
* <a href="https://x.com/fastapi" class="external-link" target="_blank">**X (Twitter)**의 @fastapi를 팔로우</a> (별도 계정에서) 할 수 있습니다.
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">**LinkedIn**에서 팔로우하기.</a>.
|
||||
* 새로운 툴의 발표나 출시 소식을 받아보십시오. (단, X (Twitter)를 더 자주 사용합니다 🤷♂).
|
||||
* <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> 또는 <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>에서 제가 작성한 내용을 읽어 보십시오 (또는 팔로우).
|
||||
* 다른 아이디어와 기사들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.
|
||||
* 새로운 내용을 게시할 때 읽기 위해 팔로우 하십시오.
|
||||
* 다른 기사나 아이디어들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.
|
||||
* 새로운 기사를 읽기 위해 팔로우 하십시오.
|
||||
|
||||
## **FastAPI**에 대해 트윗하기 { #tweet-about-fastapi }
|
||||
## **FastAPI**에 대한 트윗
|
||||
|
||||
<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**에 대해 트윗</a> 하고 저와 다른 사람들에게 FastAPI가 마음에 드는 이유를 알려주세요. 🎉
|
||||
<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**에 대해 트윗</a> 하고 FastAPI가 마음에 드는 이유를 알려주세요. 🎉
|
||||
|
||||
**FastAPI**가 어떻게 사용되고 있는지, 어떤 점이 마음에 들었는지, 어떤 프로젝트/회사에서 사용하고 있는지 등에 대해 듣고 싶습니다.
|
||||
|
||||
## FastAPI에 투표하기 { #vote-for-fastapi }
|
||||
## FastAPI에 투표하기
|
||||
|
||||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Slant에서 **FastAPI** 에 대해 투표하십시오</a>.
|
||||
* <a href="https://alternativeto.net/software/fastapi/about/" class="external-link" target="_blank">AlternativeTo에서 **FastAPI** 에 대해 투표하십시오</a>.
|
||||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">StackShare에서 **FastAPI**를 사용한다고 표시하세요</a>.
|
||||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">StackShare에서 **FastAPI** 에 대해 투표하십시오</a>.
|
||||
|
||||
## GitHub에서 질문으로 다른 사람 돕기 { #help-others-with-questions-in-github }
|
||||
## GitHub의 이슈로 다른사람 돕기
|
||||
|
||||
다른 사람들의 질문에 도움을 줄 수 있습니다:
|
||||
|
||||
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
|
||||
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
|
||||
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub 디스커션</a>
|
||||
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub 이슈</a>
|
||||
|
||||
많은 경우, 여러분은 이미 그 질문에 대한 답을 알고 있을 수도 있습니다. 🤓
|
||||
|
||||
만약 많은 사람들의 질문을 도와준다면, 공식적인 [FastAPI 전문가](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 될 것입니다. 🎉
|
||||
만약 많은 사람들의 문제를 도와준다면, 공식적인 [FastAPI 전문가](fastapi-people.md#fastapi-experts){.internal-link target=\_blank} 가 될 것입니다. 🎉
|
||||
|
||||
가장 중요한 점은: 친절하려고 노력하는 것입니다. 사람들은 좌절감을 안고 오며, 많은 경우 최선의 방식으로 질문하지 않을 수도 있습니다. 하지만 최대한 친절하게 대하려고 노력하세요. 🤗
|
||||
|
||||
@@ -86,170 +86,183 @@ GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 "watch"
|
||||
|
||||
---
|
||||
|
||||
다른 사람들의 질문(디스커션 또는 이슈에서) 해결을 도울 수 있는 방법은 다음과 같습니다.
|
||||
다른 사람들의 질문 (디스커션 또는 이슈에서) 해결을 도울 수 있는 방법은 다음과 같습니다.
|
||||
|
||||
### 질문 이해하기 { #understand-the-question }
|
||||
### 질문 이해하기
|
||||
|
||||
* 질문하는 사람이 가진 **목적**과 사용 사례를 이해할 수 있는지 확인하세요.
|
||||
|
||||
* 그런 다음 질문(대부분은 질문입니다)이 **명확**한지 확인하세요.
|
||||
* 질문 (대부분은 질문입니다)이 **명확**한지 확인하세요.
|
||||
|
||||
* 많은 경우 사용자가 상상한 해결책에 대한 질문을 하지만, 더 **좋은** 해결책이 있을 수 있습니다. 문제와 사용 사례를 더 잘 이해하면 더 나은 **대안적인 해결책**을 제안할 수 있습니다.
|
||||
* 많은 경우, 사용자가 가정한 해결책에 대한 질문을 하지만, 더 **좋은** 해결책이 있을 수 있습니다. 문제와 사용 사례를 더 잘 이해하면 더 나은 **대안적인 해결책**을 제안할 수 있습니다.
|
||||
|
||||
* 질문을 이해할 수 없다면, 더 **자세한 정보**를 요청하세요.
|
||||
|
||||
### 문제 재현하기 { #reproduce-the-problem }
|
||||
### 문제 재현하기
|
||||
|
||||
대부분의 경우 그리고 대부분의 질문에서는 질문자의 **원본 코드**와 관련된 내용이 있습니다.
|
||||
대부분의 경우, 질문은 질문자의 **원본 코드**와 관련이 있습니다.
|
||||
|
||||
많은 경우, 코드의 일부만 복사해서 올리지만, 그것만으로는 **문제를 재현**하기에 충분하지 않습니다.
|
||||
|
||||
* 질문자에게 <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">최소한의 재현 가능한 예제</a>를 제공해달라고 요청할 수 있습니다. 이렇게 하면 코드를 **복사-붙여넣기**하여 로컬에서 실행하고, 질문자가 보고 있는 것과 동일한 오류나 동작을 확인하거나 사용 사례를 더 잘 이해할 수 있습니다.
|
||||
* 질문자에게 <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">최소한의 재현 가능한 예제</a>를 제공해달라고 요청하세요. 이렇게 하면 코드를 **복사-붙여넣기**하여 직접 실행하고, 동일한 오류나 동작을 확인하거나 사용 사례를 더 잘 이해할 수 있습니다.
|
||||
|
||||
* 너그러운 마음이 든다면, 문제 설명만을 기반으로 직접 **예제를 만들어**볼 수도 있습니다. 다만 이는 시간이 많이 걸릴 수 있으므로, 먼저 문제를 명확히 해달라고 요청하는 것이 더 나을 수 있다는 점을 기억하세요.
|
||||
* 너그러운 마음이 든다면, 문제 설명만을 기반으로 직접 **예제를 만들어**볼 수도 있습니다. 하지만, 이는 시간이 많이 걸릴 수 있으므로, 먼저 질문을 명확히 해달라고 요청하는 것이 좋습니다.
|
||||
|
||||
### 해결책 제안하기 { #suggest-solutions }
|
||||
### 해결책 제안하기
|
||||
|
||||
* 질문을 충분히 이해한 후에는 가능한 **답변**을 제공할 수 있습니다.
|
||||
|
||||
* 많은 경우, 질문자의 **근본적인 문제나 사용 사례**를 이해하는 것이 더 좋습니다. 그들이 시도하는 방법보다 더 나은 해결책이 있을 수 있기 때문입니다.
|
||||
* 많은 경우, 질문자의 **근본적인 문제나 사용 사례**를 이해하는 것이 중요합니다. 그들이 시도하는 방법보다 더 나은 해결책이 있을 수 있기 때문입니다.
|
||||
|
||||
### 종료 요청하기 { #ask-to-close }
|
||||
### 해결 요청하기
|
||||
|
||||
질문자가 답변을 하면, 여러분이 문제를 해결했을 가능성이 높습니다. 축하합니다, **여러분은 영웅입니다**! 🦸
|
||||
질문자가 답변을 확인하고 나면, 당신이 문제를 해결했을 가능성이 높습니다. 축하합니다, **당신은 영웅입니다**! 🦸
|
||||
|
||||
* 이제 문제를 해결했다면, 질문자에게 다음을 요청할 수 있습니다.
|
||||
|
||||
* GitHub Discussions에서: 댓글을 **답변**으로 표시하도록 요청하세요.
|
||||
* GitHub Issues에서: 이슈를 **닫아달라고** 요청하세요.
|
||||
* GitHub 디스커션에서: 댓글을 **답변**으로 표시하도록 요청하세요.
|
||||
* GitHub 이슈에서: 이슈를 **닫아달라고** 요청하세요.
|
||||
|
||||
## GitHub 저장소 보기 { #watch-the-github-repository }
|
||||
## GitHub 저장소 보기
|
||||
|
||||
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 "watch" 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
|
||||
"Releases only" 대신 "Watching"을 선택하면 누군가가 새 이슈나 질문을 만들 때 알림을 받게 됩니다. 또한 새 이슈, 디스커션, PR 등만 알림을 받도록 지정할 수도 있습니다.
|
||||
"Releases only" 대신 "Watching"을 선택하면, 새로운 이슈나 질문이 생성될 때 알림을 받을 수 있습니다. 또한, 특정하게 새로운 이슈, 디스커션, PR 등만 알림 받도록 설정할 수도 있습니다.
|
||||
|
||||
그런 다음 이런 질문들을 해결하도록 도와줄 수 있습니다.
|
||||
그런 다음 이런 이슈들을 해결 할 수 있도록 도움을 줄 수 있습니다.
|
||||
|
||||
## 질문하기 { #ask-questions }
|
||||
## 이슈 생성하기
|
||||
|
||||
GitHub 저장소에서 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">새 질문을 생성</a>할 수 있습니다. 예를 들면 다음과 같습니다:
|
||||
GitHub 저장소에 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">새로운 이슈 생성</a>을 할 수 있습니다, 예를들면 다음과 같습니다:
|
||||
|
||||
* **질문**을 하거나 **문제**에 대해 질문합니다.
|
||||
* 새로운 **기능**을 제안 합니다.
|
||||
|
||||
**참고**: 만약 이렇게 한다면, 저는 여러분에게 다른 사람들도 도와달라고 요청할 것입니다. 😉
|
||||
**참고**: 만약 이슈를 생성한다면, 저는 여러분에게 다른 사람들을 도와달라고 부탁할 것입니다. 😉
|
||||
|
||||
## Pull Request 리뷰하기 { #review-pull-requests }
|
||||
## Pull Requests 리뷰하기
|
||||
|
||||
다른 사람들이 만든 pull request를 리뷰하는 데 저를 도와줄 수 있습니다.
|
||||
다른 사람들의 pull request를 리뷰하는 데 도움을 줄 수 있습니다.
|
||||
|
||||
다시 한번 말하지만, 최대한 친절하게 리뷰해 주세요. 🤗
|
||||
|
||||
---
|
||||
|
||||
Pull request를 리뷰할 때 고려해야 할 사항과 방법은 다음과 같습니다:
|
||||
Pull Rrquest를 리뷰할 때 고려해야 할 사항과 방법은 다음과 같습니다:
|
||||
|
||||
### 문제 이해하기 { #understand-the-problem }
|
||||
### 문제 이해하기
|
||||
|
||||
* 먼저, 해당 pull request가 해결하려는 **문제를 이해하는지** 확인하세요. GitHub Discussion 또는 이슈에서 더 긴 논의가 있었을 수도 있습니다.
|
||||
* 먼저, 해당 pull request가 해결하려는 **문제를 이해하는지** 확인하세요. GitHub 디스커션 또는 이슈에서 더 긴 논의가 있었을 수도 있습니다.
|
||||
|
||||
* Pull request가 실제로 필요하지 않을 가능성도 큽니다. 문제가 **다른 방식**으로 해결될 수 있기 때문입니다. 그런 경우 그 방법을 제안하거나 질문할 수 있습니다.
|
||||
* Pull request가 필요하지 않을 가능성도 있습니다. **다른 방식**으로 문제를 해결할 수 있다면, 그 방법을 제안하거나 질문할 수 있습니다.
|
||||
|
||||
### 스타일에 너무 신경 쓰지 않기 { #dont-worry-about-style }
|
||||
### 스타일에 너무 신경 쓰지 않기
|
||||
|
||||
* 커밋 메시지 스타일 같은 것에 너무 신경 쓰지 마세요. 저는 커밋을 수동으로 조정해서 squash and merge를 할 것입니다.
|
||||
* 커밋 메시지 스타일 같은 것에 너무 신경 쓰지 않아도 됩니다. 저는 직접 커밋을 수정하여 squash and merge를 수행할 것입니다.
|
||||
|
||||
* 코드 스타일 규칙도 걱정할 필요 없습니다. 이미 자동화된 도구들이 이를 검사하고 있습니다.
|
||||
|
||||
그리고 다른 스타일이나 일관성 관련 필요 사항이 있다면, 제가 직접 요청하거나 필요한 변경 사항을 위에 커밋으로 추가할 것입니다.
|
||||
스타일이나 일관성 관련 요청이 필요한 경우, 제가 직접 요청하거나 필요한 변경 사항을 추가 커밋으로 수정할 것입니다.
|
||||
|
||||
### 코드 확인하기 { #check-the-code }
|
||||
### 코드 확인하기
|
||||
|
||||
* 코드를 확인하고 읽어서 말이 되는지 보고, **로컬에서 실행**해 실제로 문제가 해결되는지 확인하세요.
|
||||
* 코드를 읽고, **논리적으로 타당**한지 확인한 후 로컬에서 실행하여 문제가 해결되는지 확인하세요.
|
||||
|
||||
* 그런 다음 그렇게 했다고 **댓글**로 남겨 주세요. 그래야 제가 정말로 확인했음을 알 수 있습니다.
|
||||
* 그런 다음, 확인했다고 **댓글**을 남겨 주세요. 그래야 제가 검토했음을 알 수 있습니다.
|
||||
|
||||
/// info | 정보
|
||||
/// info
|
||||
|
||||
불행히도, 제가 단순히 여러 개의 승인만으로 PR을 신뢰할 수는 없습니다.
|
||||
|
||||
여러 번, 설명이 그럴듯해서인지 3개, 5개 이상의 승인이 달린 PR이 있었지만, 제가 확인해보면 실제로는 깨져 있거나, 버그가 있거나, 주장하는 문제를 해결하지 못하는 경우가 있었습니다. 😅
|
||||
3개, 5개 이상의 승인이 달린 PR이 실제로는 깨져 있거나, 버그가 있거나, 주장하는 문제를 해결하지 못하는 경우가 여러 번 있었습니다. 😅
|
||||
|
||||
따라서, 정말로 코드를 읽고 실행한 뒤, 댓글로 확인 내용을 남겨 주는 것이 매우 중요합니다. 🤓
|
||||
|
||||
///
|
||||
|
||||
* PR을 더 단순하게 만들 수 있다면 그렇게 요청할 수 있지만, 너무 까다로울 필요는 없습니다. 주관적인 견해가 많이 있을 수 있기 때문입니다(그리고 저도 제 견해가 있을 거예요 🙈). 따라서 핵심적인 부분에 집중하는 것이 좋습니다.
|
||||
* PR을 더 단순하게 만들 수 있다면 그렇게 요청할 수 있지만, 너무 까다로울 필요는 없습니다. 주관적인 견해가 많이 있을 수 있기 때문입니다 (그리고 저도 제 견해가 있을 거예요 🙈). 따라서 핵심적인 부분에 집중하는 것이 좋습니다.
|
||||
|
||||
### 테스트 { #tests }
|
||||
### 테스트
|
||||
|
||||
* PR에 **테스트**가 포함되어 있는지 확인하는 데 도움을 주세요.
|
||||
|
||||
* PR 전에는 테스트가 **실패**하는지 확인하세요. 🚨
|
||||
* PR을 적용하기 전에 테스트가 **실패**하는지 확인하세요. 🚨
|
||||
|
||||
* 그런 다음 PR 후에는 테스트가 **통과**하는지 확인하세요. ✅
|
||||
* PR을 적용한 후 테스트가 **통과**하는지 확인하세요. ✅
|
||||
|
||||
* 많은 PR에는 테스트가 없습니다. 테스트를 추가하도록 **상기**시켜줄 수도 있고, 직접 테스트를 **제안**할 수도 있습니다. 이는 시간이 가장 많이 드는 것들 중 하나이며, 그 부분을 많이 도와줄 수 있습니다.
|
||||
* 많은 PR에는 테스트가 없습니다. 테스트를 추가하도록 **상기**시켜줄 수도 있고, 직접 테스트를 **제안**할 수도 있습니다. 이는 시간이 많이 소요되는 부분 중 하나이며, 그 부분을 많이 도와줄 수 있습니다.
|
||||
|
||||
* 그리고 시도한 내용을 댓글로 남겨주세요. 그러면 제가 확인했다는 걸 알 수 있습니다. 🤓
|
||||
|
||||
## Pull Request 만들기 { #create-a-pull-request }
|
||||
## Pull Request를 만드십시오
|
||||
|
||||
Pull Requests를 이용하여 소스 코드에 [기여](contributing.md){.internal-link target=_blank}할 수 있습니다. 예를 들면 다음과 같습니다:
|
||||
Pull Requests를 이용하여 소스코드에 [컨트리뷰트](contributing.md){.internal-link target=\_blank} 할 수 있습니다. 예를 들면 다음과 같습니다:
|
||||
|
||||
* 문서에서 발견한 오타를 수정할 때.
|
||||
* FastAPI에 대한 글, 비디오, 팟캐스트를 작성했거나 발견했다면 <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">이 파일을 편집</a>하여 공유할 때.
|
||||
* FastAPI 관련 문서, 비디오 또는 팟캐스트를 작성했거나 발견하여 <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">이 파일을 편집하여</a> 공유할 때.
|
||||
* 해당 섹션의 시작 부분에 링크를 추가해야 합니다.
|
||||
* 여러분의 언어로 [문서 번역에](contributing.md#translations){.internal-link target=_blank} 도움을 줄 때.
|
||||
* 당신의 언어로 [문서 번역하는데](contributing.md#translations){.internal-link target=\_blank} 기여할 때.
|
||||
* 다른 사람이 작성한 번역을 검토하는 것도 도울 수 있습니다.
|
||||
* 새로운 문서 섹션을 제안할 때.
|
||||
* 기존 이슈/버그를 수정할 때.
|
||||
* 새로운 문서의 섹션을 제안할 때.
|
||||
* 기존 문제/버그를 수정할 때.
|
||||
* 테스트를 반드시 추가해야 합니다.
|
||||
* 새로운 기능을 추가할 때.
|
||||
* 새로운 feature를 추가할 때.
|
||||
* 테스트를 반드시 추가해야 합니다.
|
||||
* 관련 문서가 있다면 반드시 추가해야 합니다.
|
||||
* 관련 문서가 필요하다면 반드시 추가해야 합니다.
|
||||
|
||||
## FastAPI 유지 관리 돕기 { #help-maintain-fastapi }
|
||||
## FastAPI 유지 관리에 도움 주기
|
||||
|
||||
**FastAPI** 유지를 도와주세요! 🤓
|
||||
**FastAPI**의 유지 관리를 도와주세요! 🤓
|
||||
|
||||
할 일이 많고, 그중 대부분은 **여러분**이 할 수 있습니다.
|
||||
할 일이 많고, 그 중 대부분은 **여러분**이 할 수 있습니다.
|
||||
|
||||
지금 할 수 있는 주요 작업은:
|
||||
|
||||
* [GitHub에서 질문으로 다른 사람 돕기](#help-others-with-questions-in-github){.internal-link target=_blank} (위의 섹션을 참조하세요).
|
||||
* [Pull Request 리뷰하기](#review-pull-requests){.internal-link target=_blank} (위의 섹션을 참조하세요).
|
||||
* [GitHub에서 다른 사람들의 질문에 도움 주기](#github_1){.internal-link target=_blank} (위의 섹션을 참조하세요).
|
||||
* [Pull Request 리뷰하기](#pull-requests){.internal-link target=_blank} (위의 섹션을 참조하세요).
|
||||
|
||||
이 두 작업이 **가장 많은 시간을 소모**합니다. 이것이 FastAPI를 유지 관리하는 주요 작업입니다.
|
||||
이 두 작업이 **가장 많은 시간을 소모**하는 일입니다. 그것이 FastAPI 유지 관리의 주요 작업입니다.
|
||||
|
||||
이 작업을 도와주신다면, **FastAPI 유지를 돕는 것**이며 FastAPI가 **더 빠르고 더 잘 발전하는 것**을 보장하는 것입니다. 🚀
|
||||
이 작업을 도와주신다면, **FastAPI 유지 관리에 도움을 주는 것**이며 그것이 **더 빠르고 더 잘 발전하는 것**을 보장하는 것입니다. 🚀
|
||||
|
||||
## 채팅에 참여하기 { #join-the-chat }
|
||||
## 채팅에 참여하십시오
|
||||
|
||||
👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord 채팅 서버</a> 👥 에 참여해서 FastAPI 커뮤니티의 다른 사람들과 어울리세요.
|
||||
👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">디스코드 채팅 서버</a> 👥 에 가입하고 FastAPI 커뮤니티에서 다른 사람들과 어울리세요.
|
||||
|
||||
/// tip | 팁
|
||||
/// tip
|
||||
|
||||
질문은 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>에서 하세요. [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank}로부터 도움을 받을 가능성이 훨씬 높습니다.
|
||||
질문이 있는 경우, <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub 디스커션</a> 에서 질문하십시오, [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank} 의 도움을 받을 가능성이 높습니다.
|
||||
|
||||
채팅은 다른 일반적인 대화를 위해서만 사용하세요.
|
||||
다른 일반적인 대화에서만 채팅을 사용하십시오.
|
||||
|
||||
///
|
||||
|
||||
### 질문을 위해 채팅을 사용하지 마세요 { #dont-use-the-chat-for-questions }
|
||||
### 질문을 위해 채팅을 사용하지 마십시오
|
||||
|
||||
채팅은 더 많은 "자유로운 대화"를 허용하기 때문에, 너무 일반적인 질문이나 답하기 어려운 질문을 쉽게 할 수 있어 답변을 받지 못할 수도 있다는 점을 기억하세요.
|
||||
채팅은 더 많은 "자유로운 대화"를 허용하기 때문에, 너무 일반적인 질문이나 대답하기 어려운 질문을 쉽게 질문을 할 수 있으므로, 답변을 받지 못할 수 있습니다.
|
||||
|
||||
GitHub에서는 템플릿이 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나, 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 제가 항상 모든 것에 답하도록 보장할 수 있습니다. 채팅 시스템에서는 제가 개인적으로 그렇게 할 수 없습니다. 😅
|
||||
GitHub 이슈에서의 템플릿은 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 항상 모든 것에 답할 수 있습니다. 채팅 시스템에서는 개인적으로 그렇게 할 수 없습니다. 😅
|
||||
|
||||
채팅 시스템에서의 대화 또한 GitHub만큼 쉽게 검색할 수 없기 때문에, 질문과 답변이 대화 속에서 사라질 수 있습니다. 그리고 GitHub에 있는 것만 [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 되는 것으로 인정되므로, GitHub에서 더 많은 관심을 받게 될 가능성이 큽니다.
|
||||
채팅 시스템에서의 대화 또한 GitHub에서 처럼 쉽게 검색할 수 없기 때문에 대화 중에 질문과 답변이 손실될 수 있습니다. 그리고 GitHub 이슈에 있는 것만 [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 되는 것으로 간주되므로, GitHub 이슈에서 더 많은 관심을 받을 것입니다.
|
||||
|
||||
반면, 채팅 시스템에는 수천 명의 사용자가 있으므로, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄
|
||||
반면, 채팅 시스템에는 수천 명의 사용자가 있기 때문에, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄
|
||||
|
||||
## 개발자 스폰서 되기 { #sponsor-the-author }
|
||||
## 개발자 스폰서가 되십시오
|
||||
|
||||
여러분의 **제품/회사**가 **FastAPI**에 의존하거나 관련되어 있고, FastAPI 사용자를 대상으로 알리고 싶다면 <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>를 통해 개발자(저)를 스폰서할 수 있습니다. 티어에 따라 문서에 배지 같은 추가 혜택을 받을 수도 있습니다. 🎁
|
||||
<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub 스폰서</a> 를 통해 개발자를 경제적으로 지원할 수 있습니다.
|
||||
|
||||
감사하다는 말로 커피를 ☕️ 한잔 사줄 수 있습니다. 😄
|
||||
|
||||
또한 FastAPI의 실버 또는 골드 스폰서가 될 수 있습니다. 🏅🎉
|
||||
|
||||
## FastAPI를 강화하는 도구의 스폰서가 되십시오
|
||||
|
||||
문서에서 보았듯이, FastAPI는 Starlette과 Pydantic 라는 거인의 어깨에 타고 있습니다.
|
||||
|
||||
다음의 스폰서가 될 수 있습니다
|
||||
|
||||
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
|
||||
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,79 +1,81 @@
|
||||
# 역사, 디자인 그리고 미래 { #history-design-and-future }
|
||||
# 역사, 디자인 그리고 미래
|
||||
|
||||
얼마 전, <a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">한 **FastAPI** 사용자가 이렇게 물었습니다</a>:
|
||||
어느 날, [한 FastAPI 사용자](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920)가 이렇게 물었습니다:
|
||||
|
||||
> 이 프로젝트의 역사는 무엇인가요? 몇 주 만에 아무 데서도 갑자기 나타나 엄청나게 좋아진 것처럼 보이네요 [...]
|
||||
> 이 프로젝트의 역사를 알려 주실 수 있나요? 몇 주 만에 멋진 결과를 낸 것 같아요. [...]
|
||||
|
||||
여기서 그 역사에 대해 간단히 설명하겠습니다.
|
||||
|
||||
## 대안 { #alternatives }
|
||||
---
|
||||
|
||||
저는 여러 해 동안 복잡한 요구사항(머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 등)을 가진 API를 만들면서 여러 개발 팀을 이끌어 왔습니다.
|
||||
## 대안
|
||||
|
||||
그 과정에서 많은 대안을 조사하고, 테스트하고, 사용해야 했습니다.
|
||||
저는 여러 해 동안 머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 같은 복잡한 요구사항을 가진 API를 개발하며 여러 팀을 이끌어 왔습니다.
|
||||
|
||||
**FastAPI**의 역사는 상당 부분 그 이전에 있던 도구들의 역사입니다.
|
||||
이 과정에서 많은 대안을 조사하고, 테스트하며, 사용해야 했습니다. **FastAPI**의 역사는 그 이전에 나왔던 여러 도구의 역사와 밀접하게 연관되어 있습니다.
|
||||
|
||||
[대안](alternatives.md){.internal-link target=_blank} 섹션에서 언급된 것처럼:
|
||||
|
||||
<blockquote markdown="1">
|
||||
> **FastAPI**는 이전에 나왔던 많은 도구들의 노력 없이는 존재하지 않았을 것입니다.
|
||||
>
|
||||
> 이전에 개발된 여러 도구들이 이 프로젝트에 영감을 주었습니다.
|
||||
>
|
||||
> 저는 오랫동안 새로운 프레임워크를 만드는 것을 피하고자 했습니다. 처음에는 **FastAPI**가 제공하는 기능들을 다양한 프레임워크와 플러그인, 도구들을 조합해 해결하려 했습니다.
|
||||
>
|
||||
> 하지만 결국에는 이 모든 기능을 통합하는 도구가 필요해졌습니다. 이전 도구들로부터 최고의 아이디어들을 모으고, 이를 최적의 방식으로 조합해야만 했습니다. 이는 :term:Python 3.6+ 타입 힌트 <type hints>와 같은, 이전에는 사용할 수 없었던 언어 기능이 가능했기 때문입니다.
|
||||
|
||||
**FastAPI**는 다른 사람들이 이전에 해온 작업이 없었다면 존재하지 않았을 것입니다.
|
||||
---
|
||||
|
||||
그 전에 만들어진 많은 도구들이 이것의 탄생에 영감을 주었습니다.
|
||||
## 조사
|
||||
|
||||
저는 여러 해 동안 새로운 프레임워크를 만드는 것을 피하고 있었습니다. 처음에는 **FastAPI**가 다루는 모든 기능을 여러 다른 프레임워크, 플러그인, 도구들을 사용해 해결하려고 했습니다.
|
||||
여러 대안을 사용해 보며 다양한 도구에서 배운 점들을 모아 저와 개발팀에게 가장 적합한 방식을 찾았습니다.
|
||||
|
||||
하지만 어느 시점에는, 이전 도구들의 최고의 아이디어를 가져와 가능한 한 최선의 방식으로 조합하고, 이전에는 존재하지 않았던 언어 기능(Python 3.6+ type hints)을 사용해 이 모든 기능을 제공하는 무언가를 만드는 것 외에는 다른 선택지가 없었습니다.
|
||||
예를 들어, 표준 :term:Python 타입 힌트 <type hints>에 기반하는 것이 이상적이라는 점이 명확했습니다.
|
||||
|
||||
</blockquote>
|
||||
또한, 이미 존재하는 표준을 활용하는 것이 가장 좋은 접근법이라 판단했습니다.
|
||||
|
||||
## 조사 { #investigation }
|
||||
그래서 **FastAPI**의 코드를 작성하기 전에 몇 달 동안 OpenAPI, JSON Schema, OAuth2 명세를 연구하며 이들의 관계와 겹치는 부분, 차이점을 이해했습니다.
|
||||
|
||||
이전의 모든 대안을 사용해 보면서, 각 도구로부터 배울 기회를 얻었고, 아이디어를 가져와 제가 일해온 개발 팀들과 저 자신에게 가장 적합하다고 찾은 방식으로 조합할 수 있었습니다.
|
||||
---
|
||||
|
||||
예를 들어, 이상적으로는 표준 Python 타입 힌트에 기반해야 한다는 점이 분명했습니다.
|
||||
## 디자인
|
||||
|
||||
또한, 가장 좋은 접근법은 이미 존재하는 표준을 사용하는 것이었습니다.
|
||||
그 후, **FastAPI** 사용자가 될 개발자로서 사용하고 싶은 개발자 "API"를 디자인했습니다.
|
||||
|
||||
그래서 **FastAPI**의 코딩을 시작하기도 전에, OpenAPI, JSON Schema, OAuth2 등과 같은 명세를 몇 달 동안 공부했습니다. 이들의 관계, 겹치는 부분, 차이점을 이해하기 위해서였습니다.
|
||||
[Python Developer Survey](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)에 따르면 약 80%의 Python 개발자가 PyCharm, VS Code, Jedi 기반 편집기 등에서 개발합니다. 이 과정에서 여러 아이디어를 테스트했습니다.
|
||||
|
||||
## 디자인 { #design }
|
||||
대부분의 다른 편집기도 유사하게 동작하기 때문에, **FastAPI**의 이점은 거의 모든 편집기에서 누릴 수 있습니다.
|
||||
|
||||
그 다음에는 (FastAPI를 사용하는 개발자로서) 사용자로서 갖고 싶었던 개발자 "API"를 디자인하는 데 시간을 썼습니다.
|
||||
이 과정을 통해 코드 중복을 최소화하고, 모든 곳에서 자동 완성, 타입 검사, 에러 확인 기능이 제공되는 최적의 방식을 찾아냈습니다.
|
||||
|
||||
가장 인기 있는 Python 편집기들: PyCharm, VS Code, Jedi 기반 편집기에서 여러 아이디어를 테스트했습니다.
|
||||
이 모든 것은 개발자들에게 최고의 개발 경험을 제공하기 위해 설계되었습니다.
|
||||
|
||||
약 80%의 사용자를 포함하는 최근 <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">Python Developer Survey</a>에 따르면 그렇습니다.
|
||||
---
|
||||
|
||||
즉, **FastAPI**는 Python 개발자의 80%가 사용하는 편집기들로 특별히 테스트되었습니다. 그리고 대부분의 다른 편집기도 유사하게 동작하는 경향이 있으므로, 그 모든 이점은 사실상 모든 편집기에서 동작해야 합니다.
|
||||
## 필요조건
|
||||
|
||||
그렇게 해서 코드 중복을 가능한 한 많이 줄이고, 어디서나 자동 완성, 타입 및 에러 검사 등을 제공하는 최선의 방법을 찾을 수 있었습니다.
|
||||
여러 대안을 테스트한 후, [Pydantic](https://docs.pydantic.dev/)을 사용하기로 결정했습니다.
|
||||
|
||||
모든 개발자에게 최고의 개발 경험을 제공하는 방식으로 말입니다.
|
||||
이후 저는 **Pydantic**이 JSON Schema와 완벽히 호환되도록 개선하고, 다양한 제약 조건 선언을 지원하며, 여러 편집기에서의 자동 완성과 타입 검사 기능을 향상하기 위해 기여했습니다.
|
||||
|
||||
## 필요조건 { #requirements }
|
||||
또한, 또 다른 주요 필요조건이었던 [Starlette](https://www.starlette.dev/)에도 기여했습니다.
|
||||
|
||||
여러 대안을 테스트한 후, 장점 때문에 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">**Pydantic**</a>을 사용하기로 결정했습니다.
|
||||
---
|
||||
|
||||
그 후, JSON Schema를 완전히 준수하도록 하고, 제약 조건 선언을 정의하는 다양한 방식을 지원하며, 여러 편집기에서의 테스트를 바탕으로 편집기 지원(타입 검사, 자동 완성)을 개선하기 위해 기여했습니다.
|
||||
## 개발
|
||||
|
||||
개발 과정에서, 또 다른 핵심 필요조건인 <a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>에도 기여했습니다.
|
||||
**FastAPI**를 개발하기 시작할 즈음에는 대부분의 준비가 이미 완료된 상태였습니다. 설계가 정의되었고, 필요조건과 도구가 준비되었으며, 표준과 명세에 대한 지식도 충분했습니다.
|
||||
|
||||
## 개발 { #development }
|
||||
---
|
||||
|
||||
**FastAPI** 자체를 만들기 시작했을 때쯤에는, 대부분의 조각들이 이미 갖춰져 있었고, 디자인은 정의되어 있었으며, 필요조건과 도구는 준비되어 있었고, 표준과 명세에 대한 지식도 명확하고 최신 상태였습니다.
|
||||
## 미래
|
||||
|
||||
## 미래 { #future }
|
||||
현시점에서 **FastAPI**가 많은 사람들에게 유용하다는 것이 명백해졌습니다.
|
||||
|
||||
이 시점에는, **FastAPI**가 그 아이디어와 함께 많은 사람들에게 유용하다는 것이 이미 분명합니다.
|
||||
여러 용도에 더 적합한 도구로서 기존 대안보다 선호되고 있습니다.
|
||||
이미 많은 개발자와 팀들이 **FastAPI**에 의존해 프로젝트를 진행 중입니다 (저와 제 팀도 마찬가지입니다).
|
||||
|
||||
많은 사용 사례에 더 잘 맞기 때문에 이전 대안들보다 선택되고 있습니다.
|
||||
|
||||
많은 개발자와 팀이 이미 자신의 프로젝트를 위해 **FastAPI**에 의존하고 있습니다(저와 제 팀도 포함해서요).
|
||||
|
||||
하지만 여전히, 앞으로 나올 개선 사항과 기능들이 많이 있습니다.
|
||||
|
||||
**FastAPI**의 미래는 밝습니다.
|
||||
하지만 여전히 개선해야 할 점과 추가할 기능들이 많이 남아 있습니다.
|
||||
|
||||
**FastAPI**는 밝은 미래로 나아가고 있습니다.
|
||||
그리고 [여러분의 도움](help-fastapi.md){.internal-link target=_blank}은 큰 힘이 됩니다.
|
||||
|
||||
@@ -8,6 +8,7 @@ Language code: ko.
|
||||
|
||||
- Use polite, instructional Korean (e.g. 합니다/하세요 style).
|
||||
- Keep the tone consistent with the existing Korean FastAPI docs.
|
||||
- Do not translate “You” literally as “당신”. Use “여러분” where appropriate, or omit the subject if it sounds more natural in Korean.
|
||||
|
||||
### Headings
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Arquivo de teste de LLM { #llm-test-file }
|
||||
|
||||
Este documento testa se o <abbr title="Large Language Model – Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
|
||||
Este documento testa se o <abbr title="Large Language Model - Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
|
||||
|
||||
Os testes adicionados aqui serão vistos por todos os autores dos prompts específicos de idioma.
|
||||
Os testes adicionados aqui serão vistos por todos os designers dos prompts específicos de idioma.
|
||||
|
||||
Use da seguinte forma:
|
||||
|
||||
@@ -23,7 +23,7 @@ Este é um trecho de código: `foo`. E este é outro trecho de código: `bar`. E
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O conteúdo dos trechos de código deve ser deixado como está.
|
||||
|
||||
@@ -45,9 +45,9 @@ O LLM provavelmente vai traduzir isso errado. O interessante é apenas se ele ma
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O autor do prompt pode escolher se deseja converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
|
||||
O designer do prompt pode escolher se quer converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
|
||||
|
||||
Veja, por exemplo, a seção `### Quotes` em `docs/de/llm-prompt.md`.
|
||||
|
||||
@@ -67,7 +67,7 @@ Pesado: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you ha
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
... No entanto, as aspas dentro de trechos de código devem permanecer como estão.
|
||||
|
||||
@@ -95,24 +95,24 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
|
||||
...e outro exemplo de código de console...
|
||||
|
||||
```console
|
||||
// Crie um diretório "Code"
|
||||
// Criar um diretório "Code"
|
||||
$ mkdir code
|
||||
// Entre nesse diretório
|
||||
// Mudar para esse diretório
|
||||
$ cd code
|
||||
```
|
||||
|
||||
...e um exemplo de código Python...
|
||||
|
||||
```Python
|
||||
wont_work() # Isto não vai funcionar 😱
|
||||
works(foo="bar") # Isto funciona 🎉
|
||||
wont_work() # This won't work 😱
|
||||
works(foo="bar") # This works 🎉
|
||||
```
|
||||
|
||||
...e é isso.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O código em blocos de código não deve ser modificado, com exceção dos comentários.
|
||||
|
||||
@@ -154,7 +154,7 @@ Algum texto
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Abas e blocos `Info`/`Note`/`Warning`/etc. devem ter a tradução do seu título adicionada após uma barra vertical (`|`).
|
||||
|
||||
@@ -181,7 +181,7 @@ O texto do link deve ser traduzido, o endereço do link deve apontar para a trad
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Os links devem ser traduzidos, mas seus endereços devem permanecer inalterados. Uma exceção são links absolutos para páginas da documentação do FastAPI. Nesse caso, devem apontar para a tradução.
|
||||
|
||||
@@ -197,10 +197,10 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done">GTD</abbr>
|
||||
* <abbr title="less than - menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
|
||||
### O abbr fornece uma explicação { #the-abbr-gives-an-explanation }
|
||||
|
||||
@@ -209,12 +209,12 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output – Entrada/Saída: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
* <abbr title="Mozilla Developer Network: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Os atributos "title" dos elementos "abbr" são traduzidos seguindo algumas instruções específicas.
|
||||
|
||||
@@ -228,7 +228,7 @@ Veja a seção `### HTML abbr elements` no prompt geral em `scripts/translate.py
|
||||
|
||||
//// tab | Teste
|
||||
|
||||
### Desenvolver uma aplicação web - um tutorial { #develop-a-webapp-a-tutorial }
|
||||
### Desenvolver uma webapp - um tutorial { #develop-a-webapp-a-tutorial }
|
||||
|
||||
Olá.
|
||||
|
||||
@@ -242,7 +242,7 @@ Olá novamente.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
A única regra rígida para títulos é que o LLM deixe a parte do hash dentro de chaves inalterada, o que garante que os links não quebrem.
|
||||
|
||||
@@ -494,9 +494,9 @@ Para algumas instruções específicas do idioma, veja, por exemplo, a seção `
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o autor do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
|
||||
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o designer do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
|
||||
|
||||
Veja, por exemplo, a seção `### List of English terms and their preferred German translations` em `docs/de/llm-prompt.md`.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Se você não é um "especialista" no OpenAPI, você provavelmente não precisa
|
||||
|
||||
Você pode definir o `operationId` do OpenAPI que será utilizado na sua *operação de rota* com o parâmetro `operation_id`.
|
||||
|
||||
Você precisa ter certeza que ele é único para cada operação.
|
||||
Você deveria ter certeza que ele é único para cada operação.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
|
||||
@@ -18,13 +18,13 @@ Você precisa ter certeza que ele é único para cada operação.
|
||||
|
||||
Se você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` em cada *operação de rota* utilizando o `APIRoute.name` dela.
|
||||
|
||||
Você deve fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
Você deveria fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você chamar `app.openapi()` manualmente, os `operationId`s devem ser atualizados antes dessa chamada.
|
||||
Se você chamar `app.openapi()` manualmente, você deveria atualizar os `operationId`s antes dessa chamada.
|
||||
|
||||
///
|
||||
|
||||
@@ -44,11 +44,11 @@ Para excluir uma *operação de rota* do esquema OpenAPI gerado (e por consequê
|
||||
|
||||
## Descrição avançada a partir de docstring { #advanced-description-from-docstring }
|
||||
|
||||
Você pode limitar as linhas utilizadas a partir de uma docstring de uma *função de operação de rota* para o OpenAPI.
|
||||
Você pode limitar as linhas utilizadas a partir da docstring de uma *função de operação de rota* para o OpenAPI.
|
||||
|
||||
Adicionar um `\f` (um caractere de escape para alimentação de formulário) faz com que o **FastAPI** restrinja a saída utilizada pelo OpenAPI até esse ponto.
|
||||
Adicionar um `\f` (um caractere de escape para "form feed") faz com que o **FastAPI** trunque a saída usada para o OpenAPI até esse ponto.
|
||||
|
||||
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto do texto.
|
||||
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
@@ -131,70 +131,38 @@ E se você olhar o esquema OpenAPI resultante (na rota `/openapi.json` da sua AP
|
||||
|
||||
### Esquema de *operação de rota* do OpenAPI personalizado { #custom-openapi-path-operation-schema }
|
||||
|
||||
O dicionário em `openapi_extra` vai ter todos os seus níveis mesclados dentro do esquema OpenAPI gerado automaticamente para a *operação de rota*.
|
||||
O dicionário em `openapi_extra` vai ser mesclado profundamente com o esquema OpenAPI gerado automaticamente para a *operação de rota*.
|
||||
|
||||
Então, você pode adicionar dados extras para o esquema gerado automaticamente.
|
||||
Então, você pode adicionar dados extras ao esquema gerado automaticamente.
|
||||
|
||||
Por exemplo, você poderia optar por ler e validar a requisição com seu próprio código, sem utilizar funcionalidades automatizadas do FastAPI com o Pydantic, mas você ainda pode quere definir a requisição no esquema OpenAPI.
|
||||
Por exemplo, você poderia decidir ler e validar a requisição com seu próprio código, sem usar as funcionalidades automáticas do FastAPI com o Pydantic, mas ainda assim querer definir a requisição no esquema OpenAPI.
|
||||
|
||||
Você pode fazer isso com `openapi_extra`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
|
||||
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="convertido de um formato plano, como bytes, para objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes` e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
|
||||
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="converted from some plain format, like bytes, into Python objects - convertido de algum formato simples, como bytes, em objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
|
||||
|
||||
De toda forma, nós podemos declarar o esquema esperado para o corpo da requisição.
|
||||
|
||||
### Tipo de conteúdo do OpenAPI personalizado { #custom-openapi-content-type }
|
||||
|
||||
Utilizando esse mesmo truque, você pode utilizar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
|
||||
Utilizando esse mesmo truque, você pode usar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
|
||||
|
||||
E você pode fazer isso até mesmo quando os dados da requisição não seguem o formato JSON.
|
||||
E você pode fazer isso até mesmo quando o tipo de dados na requisição não é JSON.
|
||||
|
||||
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática do JSON. Na verdade, estamos declarando o tipo do conteúdo da requisição como YAML, em vez de JSON:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática para JSON. Na verdade, estamos declarando o tipo de conteúdo da requisição como YAML, em vez de JSON:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber em YAML.
|
||||
|
||||
//// tab | Pydantic v1
|
||||
Então utilizamos a requisição diretamente e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o payload da requisição como JSON.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic, o método para obter o JSON Schema de um modelo é `Item.schema()`, na versão 2 do Pydantic, o método é `Item.model_json_schema()`.
|
||||
|
||||
///
|
||||
|
||||
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber no formato YAML.
|
||||
|
||||
Então utilizamos a requisição diretamente, e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o corpo da requisição como JSON.
|
||||
|
||||
E então no nosso código, nós analisamos o conteúdo YAML diretamente, e estamos utilizando o mesmo modelo Pydantic para validar o conteúdo YAML:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
E então no nosso código, nós analisamos o conteúdo YAML diretamente e, em seguida, estamos usando novamente o mesmo modelo Pydantic para validar o conteúdo YAML:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic, o método para analisar e validar um objeto era `Item.parse_obj()`, na versão 2 do Pydantic, o método é chamado de `Item.model_validate()`.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Aqui reutilizamos o mesmo modelo do Pydantic.
|
||||
|
||||
@@ -46,12 +46,6 @@ $ pip install "fastapi[all]"
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 ele vinha incluído no pacote principal. Agora é distribuído como um pacote independente para que você possa optar por instalá-lo ou não, caso não precise dessa funcionalidade.
|
||||
|
||||
///
|
||||
|
||||
### Criar o objeto `Settings` { #create-the-settings-object }
|
||||
|
||||
Importe `BaseSettings` do Pydantic e crie uma subclasse, muito parecido com um modelo do Pydantic.
|
||||
@@ -60,24 +54,8 @@ Da mesma forma que com modelos do Pydantic, você declara atributos de classe co
|
||||
|
||||
Você pode usar as mesmas funcionalidades e ferramentas de validação que usa em modelos do Pydantic, como diferentes tipos de dados e validações adicionais com `Field()`.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 você importaria `BaseSettings` diretamente de `pydantic` em vez de `pydantic_settings`.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você quer algo rápido para copiar e colar, não use este exemplo, use o último abaixo.
|
||||
@@ -215,8 +193,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
E então atualizar seu `config.py` com:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
|
||||
|
||||
/// tip | Dica
|
||||
@@ -225,26 +201,6 @@ O atributo `model_config` é usado apenas para configuração do Pydantic. Você
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
A classe `Config` é usada apenas para configuração do Pydantic. Você pode ler mais em <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic a configuração era feita em uma classe interna `Config`, na versão 2 do Pydantic é feita em um atributo `model_config`. Esse atributo recebe um `dict`, e para ter autocompletar e erros inline você pode importar e usar `SettingsConfigDict` para definir esse `dict`.
|
||||
|
||||
///
|
||||
|
||||
Aqui definimos a configuração `env_file` dentro da sua classe `Settings` do Pydantic e definimos o valor como o nome do arquivo dotenv que queremos usar.
|
||||
|
||||
### Criando o `Settings` apenas uma vez com `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
Se você tem uma aplicação FastAPI antiga, pode estar usando o Pydantic versão 1.
|
||||
|
||||
O FastAPI tem suporte ao Pydantic v1 ou v2 desde a versão 0.100.0.
|
||||
O FastAPI versão 0.100.0 tinha suporte ao Pydantic v1 ou v2. Ele usaria aquele que você tivesse instalado.
|
||||
|
||||
Se você tiver o Pydantic v2 instalado, ele será utilizado. Se, em vez disso, tiver o Pydantic v1, será ele que será utilizado.
|
||||
O FastAPI versão 0.119.0 introduziu suporte parcial ao Pydantic v1 a partir de dentro do Pydantic v2 (como `pydantic.v1`), para facilitar a migração para o v2.
|
||||
|
||||
O Pydantic v1 está agora descontinuado e o suporte a ele será removido nas próximas versões do FastAPI, você deveria migrar para o Pydantic v2. Assim, você terá as funcionalidades, melhorias e correções mais recentes.
|
||||
O FastAPI 0.126.0 removeu o suporte ao Pydantic v1, enquanto ainda oferece suporte a `pydantic.v1` por mais algum tempo.
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
Além disso, a equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
A equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
|
||||
Isso inclui `pydantic.v1`, que não é mais suportado no Python 3.14 e superiores.
|
||||
|
||||
Se quiser usar as funcionalidades mais recentes do Python, você precisará garantir que usa o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2 e as **novas funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
|
||||
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2, e as **funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
|
||||
|
||||
## Guia oficial { #official-guide }
|
||||
|
||||
@@ -44,7 +46,7 @@ Depois disso, você pode rodar os testes e verificar se tudo funciona. Se funcio
|
||||
|
||||
## Pydantic v1 no v2 { #pydantic-v1-in-v2 }
|
||||
|
||||
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`.
|
||||
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`. Mas isso não é mais suportado em versões acima do Python 3.13.
|
||||
|
||||
Isso significa que você pode instalar a versão mais recente do Pydantic v2 e importar e usar os componentes antigos do Pydantic v1 a partir desse submódulo, como se tivesse o Pydantic v1 antigo instalado.
|
||||
|
||||
@@ -66,7 +68,7 @@ Tenha em mente que, como a equipe do Pydantic não oferece mais suporte ao Pydan
|
||||
|
||||
### Pydantic v1 e v2 na mesma aplicação { #pydantic-v1-and-v2-on-the-same-app }
|
||||
|
||||
Não é suportado pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.
|
||||
Não é **suportado** pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -86,7 +88,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
...but, you can have separated models using Pydantic v1 and v2 in the same app.
|
||||
...mas, você pode ter modelos separados usando Pydantic v1 e v2 na mesma aplicação.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -106,7 +108,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma operação de rota na sua aplicação FastAPI:
|
||||
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma **operação de rota** na sua aplicação FastAPI:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
@@ -122,7 +124,7 @@ Se você precisar usar algumas das ferramentas específicas do FastAPI para par
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Primeiro tente com o `bump-pydantic`; se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
|
||||
Primeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
Ao usar **Pydantic v2**, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
Desde que o **Pydantic v2** foi lançado, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
|
||||
Inclusive, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
De fato, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
|
||||
Vamos ver como isso funciona e como alterar se for necessário.
|
||||
|
||||
@@ -95,10 +95,8 @@ O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.
|
||||
|
||||
### Mesmo Esquema para Modelos de Entrada e Saída na Documentação { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e `description` **não será obrigatório**:
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e ele terá `description` como **não obrigatório**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
|
||||
Esse é o mesmo comportamento do Pydantic v1. 🤓
|
||||
|
||||
@@ -40,8 +40,8 @@ Os recursos chave são:
|
||||
* **Rápido**: alta performance, equivalente a **NodeJS** e **Go** (graças ao Starlette e Pydantic). [Um dos frameworks mais rápidos disponíveis](#performance).
|
||||
* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *
|
||||
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
|
||||
* **Intuitivo**: Grande suporte a _IDEs_. <abbr title="também conhecido como autocompletar, preenchimento automático, IntelliSense">Preenchimento automático</abbr> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo documentação.
|
||||
* **Intuitivo**: Grande suporte a editores. <abbr title="também conhecido como auto-complete, autocompletion, IntelliSense">Completação</abbr> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.
|
||||
* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.
|
||||
* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.
|
||||
* **Baseado em padrões**: Baseado em (e totalmente compatível com) os padrões abertos para APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (anteriormente conhecido como Swagger) e <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
@@ -73,7 +73,7 @@ Os recursos chave são:
|
||||
|
||||
## Opiniões { #opinions }
|
||||
|
||||
"*[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços _Machine Learning_ na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**.*"
|
||||
"_[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços ML na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
@@ -91,39 +91,45 @@ Os recursos chave são:
|
||||
|
||||
---
|
||||
|
||||
"*Estou extremamente entusiasmado com o **FastAPI**. É tão divertido!*"
|
||||
"_Estou muito entusiasmado com o **FastAPI**. É tão divertido!_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcaster</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> apresentador do podcast</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"*Honestamente, o que você construiu parece super sólido e rebuscado. De muitas formas, eu queria que o **Hug** fosse assim - é realmente inspirador ver alguém que construiu ele.*"
|
||||
"_Honestamente, o que você construiu parece super sólido e refinado. De muitas formas, é o que eu queria que o **Hug** fosse - é realmente inspirador ver alguém construir isso._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong>criador do<a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"*Se você está procurando aprender um **_framework_ moderno** para construir aplicações _REST_, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]*"
|
||||
"_Se você está procurando aprender um **framework moderno** para construir APIs REST, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]_"
|
||||
|
||||
"*Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que vocês gostarão dele [...]*"
|
||||
"_Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que você gostará dele [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>fundadores da <a href="https://explosion.ai" target="_blank">Explosion AI</a> - criadores da <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**. Ele se tornou um **componente chave** para a nossa estratégia API first de desenvolvimento e está impulsionando diversas automações e serviços, como o nosso Virtual TAC Engineer._"
|
||||
"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**, e se tornou um **componente chave** para a nossa estratégia de desenvolvimento API first, impulsionando diversas automações e serviços, como o nosso Virtual TAC Engineer._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## Mini documentário do FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
Há um <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentário do FastAPI</a> lançado no fim de 2025, você pode assisti-lo online:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## **Typer**, o FastAPI das interfaces de linhas de comando { #typer-the-fastapi-of-clis }
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
|
||||
Se você estiver construindo uma aplicação <abbr title="Command Line Interface – Interface de Linha de Comando">CLI</abbr> para ser utilizada em um terminal ao invés de uma aplicação web, dê uma olhada no <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
Se você estiver construindo uma aplicação <abbr title="Command Line Interface - Interface de Linha de Comando">CLI</abbr> para ser utilizada no terminal ao invés de uma API web, dê uma olhada no <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
|
||||
**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das _CLIs_**. ⌨️ 🚀
|
||||
**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das CLIs**. ⌨️ 🚀
|
||||
|
||||
## Requisitos { #requirements }
|
||||
|
||||
@@ -255,10 +261,10 @@ Você verá a resposta JSON como:
|
||||
|
||||
Você acabou de criar uma API que:
|
||||
|
||||
* Recebe requisições HTTP nas _rotas_ `/` e `/items/{item_id}`.
|
||||
* Ambas _rotas_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
|
||||
* A _rota_ `/items/{item_id}` tem um _parâmetro de rota_ `item_id` que deve ser um `int`.
|
||||
* A _rota_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
|
||||
* Recebe requisições HTTP nos _paths_ `/` e `/items/{item_id}`.
|
||||
* Ambos _paths_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
|
||||
* O _path_ `/items/{item_id}` tem um _parâmetro de path_ `item_id` que deve ser um `int`.
|
||||
* O _path_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
|
||||
|
||||
### Documentação Interativa da API { #interactive-api-docs }
|
||||
|
||||
@@ -278,7 +284,7 @@ Você verá a documentação automática alternativa (fornecida por <a href="htt
|
||||
|
||||
## Evoluindo o Exemplo { #example-upgrade }
|
||||
|
||||
Agora modifique o arquivo `main.py` para receber um corpo para uma requisição `PUT`.
|
||||
Agora modifique o arquivo `main.py` para receber um corpo de uma requisição `PUT`.
|
||||
|
||||
Declare o corpo utilizando tipos padrão Python, graças ao Pydantic.
|
||||
|
||||
@@ -334,7 +340,7 @@ Agora vá para <a href="http://127.0.0.1:8000/docs" class="external-link" target
|
||||
|
||||
E agora, vá para <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* A documentação alternativa também irá refletir o novo parâmetro da _query_ e o corpo:
|
||||
* A documentação alternativa também irá refletir o novo parâmetro query e o corpo:
|
||||
|
||||

|
||||
|
||||
@@ -368,15 +374,15 @@ item: Item
|
||||
* Validação de dados:
|
||||
* Erros automáticos e claros quando o dado é inválido.
|
||||
* Validação até para objetos JSON profundamente aninhados.
|
||||
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
|
||||
* <abbr title="também conhecido como: serialization, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
|
||||
* JSON.
|
||||
* Parâmetros de rota.
|
||||
* Parâmetros de _query_ .
|
||||
* _Cookies_.
|
||||
* Parâmetros de path.
|
||||
* Parâmetros query.
|
||||
* Cookies.
|
||||
* Cabeçalhos.
|
||||
* Formulários.
|
||||
* Arquivos.
|
||||
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de saída de tipos e dados Python para dados de rede (como JSON):
|
||||
* <abbr title="também conhecido como: serialization, parsing, marshalling">Conversão</abbr> de dados de saída: convertendo de tipos e dados Python para dados de rede (como JSON):
|
||||
* Converte tipos Python (`str`, `int`, `float`, `bool`, `list` etc).
|
||||
* Objetos `datetime`.
|
||||
* Objetos `UUID`.
|
||||
@@ -390,17 +396,17 @@ item: Item
|
||||
|
||||
Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
|
||||
* Validar que existe um `item_id` na rota para requisições `GET` e `PUT`.
|
||||
* Validar que existe um `item_id` no path para requisições `GET` e `PUT`.
|
||||
* Validar que `item_id` é do tipo `int` para requisições `GET` e `PUT`.
|
||||
* Se não é validado, o cliente verá um útil, claro erro.
|
||||
* Verificar se existe um parâmetro de _query_ opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
|
||||
* Se não for, o cliente verá um erro útil e claro.
|
||||
* Verificar se existe um parâmetro query opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
|
||||
* Como o parâmetro `q` é declarado com `= None`, ele é opcional.
|
||||
* Sem o `None` ele poderia ser obrigatório (como o corpo no caso de `PUT`).
|
||||
* Sem o `None` ele seria obrigatório (como o corpo no caso de `PUT`).
|
||||
* Para requisições `PUT` para `/items/{item_id}`, lerá o corpo como JSON:
|
||||
* Verifica que tem um atributo obrigatório `name` que deve ser `str`.
|
||||
* Verifica que tem um atributo obrigatório `price` que deve ser `float`.
|
||||
* Verifica que tem an atributo opcional `is_offer`, que deve ser `bool`, se presente.
|
||||
* Tudo isso também funciona para objetos JSON profundamente aninhados.
|
||||
* Verifica que tem um atributo obrigatório `price` que tem que ser um `float`.
|
||||
* Verifica que tem um atributo opcional `is_offer`, que deve ser um `bool`, se presente.
|
||||
* Tudo isso também funcionaria para objetos JSON profundamente aninhados.
|
||||
* Converter de e para JSON automaticamente.
|
||||
* Documentar tudo com OpenAPI, que poderá ser usado por:
|
||||
* Sistemas de documentação interativos.
|
||||
@@ -409,7 +415,7 @@ Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
|
||||
---
|
||||
|
||||
Nós apenas arranhamos a superfície, mas você já tem idéia de como tudo funciona.
|
||||
Nós apenas arranhamos a superfície, mas você já tem ideia de como tudo funciona.
|
||||
|
||||
Experimente mudar a seguinte linha:
|
||||
|
||||
@@ -437,22 +443,22 @@ Para um exemplo mais completo incluindo mais recursos, veja <a href="https://fas
|
||||
|
||||
**Alerta de Spoiler**: o tutorial - guia do usuário inclui:
|
||||
|
||||
* Declaração de **parâmetetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.
|
||||
* Como configurar **Limitações de Validação** como `maximum_length` ou `regex`.
|
||||
* Um poderoso e fácil de usar sistema de **<abbr title="também conhecido como componentes, recursos, fornecedores, serviços, injetáveis">Injeção de Dependência</abbr>**.
|
||||
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação **JWT tokens** e **HTTP Basic**.
|
||||
* Declaração de **parâmetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.
|
||||
* Como configurar **limitações de validação** como `maximum_length` ou `regex`.
|
||||
* Um poderoso e fácil de usar sistema de **<abbr title="também conhecido como components, resources, providers, services, injectables">Injeção de Dependência</abbr>**.
|
||||
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação com **JWT tokens** e **HTTP Basic**.
|
||||
* Técnicas mais avançadas (mas igualmente fáceis) para declaração de **modelos JSON profundamente aninhados** (graças ao Pydantic).
|
||||
* Integrações **GraphQL** com o <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> e outras bibliotecas.
|
||||
* Muitos recursos extras (graças ao Starlette) como:
|
||||
* **WebSockets**
|
||||
* testes extrememamente fáceis baseados em HTTPX e `pytest`
|
||||
* testes extremamente fáceis baseados em HTTPX e `pytest`
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...e mais.
|
||||
|
||||
### Implemente sua aplicação (opcional) { #deploy-your-app-optional }
|
||||
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, inscreva-se na lista de espera se ainda não o fez. 🚀
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, vá e entre na lista de espera se ainda não o fez. 🚀
|
||||
|
||||
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode implantar sua aplicação com um único comando.
|
||||
|
||||
@@ -506,7 +512,7 @@ Siga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI c
|
||||
|
||||
Testes de performance da _Independent TechEmpower_ mostram aplicações **FastAPI** rodando sob Uvicorn como <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">um dos _frameworks_ Python mais rápidos disponíveis</a>, somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)
|
||||
|
||||
Para entender mais sobre performance, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
Para entender mais sobre isso, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
|
||||
## Dependências { #dependencies }
|
||||
|
||||
@@ -514,7 +520,7 @@ O FastAPI depende do Pydantic e do Starlette.
|
||||
|
||||
### Dependências `standard` { #standard-dependencies }
|
||||
|
||||
Quando você instala o FastAPI com `pip install "fastapi[standard]"`, ele vêm com o grupo `standard` (padrão) de dependências opcionais:
|
||||
Quando você instala o FastAPI com `pip install "fastapi[standard]"`, ele vem com o grupo `standard` de dependências opcionais:
|
||||
|
||||
Utilizado pelo Pydantic:
|
||||
|
||||
@@ -524,7 +530,7 @@ Utilizado pelo Starlette:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obrigatório caso você queira utilizar o `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obrigatório se você quer utilizar a configuração padrão de templates.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="converting the string that comes from an HTTP request into Python data - convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||
|
||||
Utilizado pelo FastAPI:
|
||||
|
||||
@@ -547,7 +553,7 @@ Existem algumas dependências adicionais que você pode querer instalar.
|
||||
Dependências opcionais adicionais do Pydantic:
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - para gerenciamento de configurações.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - tipos extras para serem utilizados com o Pydantic.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - para tipos extras a serem utilizados com o Pydantic.
|
||||
|
||||
Dependências opcionais adicionais do FastAPI:
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Digamos que você tenha uma estrutura de arquivos como esta:
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Existem vários arquivos `__init__.py` presentes em cada diretório ou subdiretório.
|
||||
Existem vários arquivos `__init__.py`: um em cada diretório ou subdiretório.
|
||||
|
||||
Isso permite a importação de código de um arquivo para outro.
|
||||
|
||||
@@ -43,32 +43,32 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
* O diretório `app` contém todo o código da aplicação. Ele possui um arquivo `app/__init__.py` vazio, o que o torna um "pacote Python" (uma coleção de "módulos Python"): `app`.
|
||||
* Dentro dele, o arquivo `app/main.py` está localizado em um pacote Python (diretório com `__init__.py`). Portanto, ele é um "módulo" desse pacote: `app.main`.
|
||||
* Existem também um arquivo `app/dependencies.py`, assim como o `app/main.py`, ele é um "módulo": `app.dependencies`.
|
||||
* O diretório `app` contém tudo. E possui um arquivo vazio `app/__init__.py`, então ele é um "pacote Python" (uma coleção de "módulos Python"): `app`.
|
||||
* Ele contém um arquivo `app/main.py`. Como está dentro de um pacote Python (um diretório com um arquivo `__init__.py`), ele é um "módulo" desse pacote: `app.main`.
|
||||
* Existe também um arquivo `app/dependencies.py`, assim como `app/main.py`, ele é um "módulo": `app.dependencies`.
|
||||
* Há um subdiretório `app/routers/` com outro arquivo `__init__.py`, então ele é um "subpacote Python": `app.routers`.
|
||||
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto, é um "submódulo": `app.routers.items`.
|
||||
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
|
||||
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python":`app.internal`.
|
||||
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto é um submódulo: `app.routers.items`.
|
||||
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
|
||||
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python": `app.internal`.
|
||||
* E o arquivo `app/internal/admin.py` é outro submódulo: `app.internal.admin`.
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
A mesma estrutura de arquivos com comentários:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # "app" é um pacote Python
|
||||
│ ├── __init__.py # este arquivo torna "app" um "pacote Python"
|
||||
│ ├── main.py # "main" módulo, e.g. import app.main
|
||||
│ ├── dependencies.py # "dependencies" módulo, e.g. import app.dependencies
|
||||
│ └── routers # "routers" é um "subpacote Python"
|
||||
│ │ ├── __init__.py # torna "routers" um "subpacote Python"
|
||||
│ │ ├── items.py # "items" submódulo, e.g. import app.routers.items
|
||||
│ │ └── users.py # "users" submódulo, e.g. import app.routers.users
|
||||
│ └── internal # "internal" é um "subpacote Python"
|
||||
│ ├── __init__.py # torna "internal" um "subpacote Python"
|
||||
│ └── admin.py # "admin" submódulo, e.g. import app.internal.admin
|
||||
├── app # "app" is a Python package
|
||||
│ ├── __init__.py # this file makes "app" a "Python package"
|
||||
│ ├── main.py # "main" module, e.g. import app.main
|
||||
│ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies
|
||||
│ └── routers # "routers" is a "Python subpackage"
|
||||
│ │ ├── __init__.py # makes "routers" a "Python subpackage"
|
||||
│ │ ├── items.py # "items" submodule, e.g. import app.routers.items
|
||||
│ │ └── users.py # "users" submodule, e.g. import app.routers.users
|
||||
│ └── internal # "internal" is a "Python subpackage"
|
||||
│ ├── __init__.py # makes "internal" a "Python subpackage"
|
||||
│ └── admin.py # "admin" submodule, e.g. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
@@ -79,11 +79,11 @@ Você quer manter as *operações de rota* relacionadas aos seus usuários separ
|
||||
|
||||
Mas ele ainda faz parte da mesma aplicação/web API **FastAPI** (faz parte do mesmo "pacote Python").
|
||||
|
||||
Você pode criar as *operações de rotas* para esse módulo usando o `APIRouter`.
|
||||
Você pode criar as *operações de rota* para esse módulo usando o `APIRouter`.
|
||||
|
||||
### Importe `APIRouter` { #import-apirouter }
|
||||
|
||||
você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
|
||||
Você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
@@ -91,7 +91,7 @@ você o importa e cria uma "instância" da mesma maneira que faria com a classe
|
||||
|
||||
E então você o utiliza para declarar suas *operações de rota*.
|
||||
|
||||
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
|
||||
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
@@ -151,7 +151,7 @@ Então, em vez de adicionar tudo isso a cada *operação de rota*, podemos adici
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Como o caminho de cada *operação de rota* deve começar com `/`, como em:
|
||||
Como o path de cada *operação de rota* tem que começar com `/`, como em:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
@@ -163,9 +163,9 @@ async def read_item(item_id: str):
|
||||
|
||||
Então, o prefixo neste caso é `/items`.
|
||||
|
||||
Também podemos adicionar uma lista de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste roteador.
|
||||
Também podemos adicionar uma list de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste router.
|
||||
|
||||
E podemos adicionar uma lista de `dependencies` que serão adicionadas a todas as *operações de rota* no roteador e serão executadas/resolvidas para cada request feita a elas.
|
||||
E podemos adicionar uma list de `dependencies` que serão adicionadas a todas as *operações de rota* no router e serão executadas/resolvidas para cada request feita a elas.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -173,7 +173,7 @@ Observe que, assim como [dependências em *decoradores de operação de rota*](d
|
||||
|
||||
///
|
||||
|
||||
O resultado final é que os caminhos dos itens agora são:
|
||||
O resultado final é que os paths dos itens agora são:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
@@ -183,9 +183,9 @@ O resultado final é que os caminhos dos itens agora são:
|
||||
* Elas serão marcadas com uma lista de tags que contêm uma única string `"items"`.
|
||||
* Essas "tags" são especialmente úteis para os sistemas de documentação interativa automática (usando OpenAPI).
|
||||
* Todas elas incluirão as `responses` predefinidas.
|
||||
* Todas essas *operações de rota* terão a lista de `dependencies` avaliada/executada antes delas.
|
||||
* Todas essas *operações de rota* terão a list de `dependencies` avaliada/executada antes delas.
|
||||
* Se você também declarar dependências em uma *operação de rota* específica, **elas também serão executadas**.
|
||||
* As dependências do roteador são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
|
||||
* As dependências do router são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
|
||||
* Você também pode adicionar [dependências de `Segurança` com `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Dica
|
||||
@@ -246,7 +246,7 @@ from ..dependencies import get_token_header
|
||||
|
||||
significa:
|
||||
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) reside (o diretório `app/routers/`)...
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...
|
||||
* vá para o pacote pai (o diretório `app/`)...
|
||||
* e lá, encontre o módulo `dependencies` (o arquivo em `app/dependencies.py`)...
|
||||
* e dele, importe a função `get_token_header`.
|
||||
@@ -283,9 +283,9 @@ Mas ainda podemos adicionar _mais_ `tags` que serão aplicadas a uma *operação
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Esta última operação de caminho terá a combinação de tags: `["items", "custom"]`.
|
||||
Esta última operação de rota terá a combinação de tags: `["items", "custom"]`.
|
||||
|
||||
E também terá ambas as respostas na documentação, uma para `404` e uma para `403`.
|
||||
E também terá ambas as responses na documentação, uma para `404` e uma para `403`.
|
||||
|
||||
///
|
||||
|
||||
@@ -325,7 +325,7 @@ from .routers import items, users
|
||||
|
||||
significa:
|
||||
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) reside (o diretório `app/`)...
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) vive (o diretório `app/`)...
|
||||
* procure o subpacote `routers` (o diretório em `app/routers/`)...
|
||||
* e dele, importe o submódulo `items` (o arquivo em `app/routers/items.py`) e `users` (o arquivo em `app/routers/users.py`)...
|
||||
|
||||
@@ -376,7 +376,7 @@ Então, para poder usar ambos no mesmo arquivo, importamos os submódulos direta
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### Inclua os `APIRouter`s para `usuários` e `itens` { #include-the-apirouters-for-users-and-items }
|
||||
### Inclua os `APIRouter`s para `users` e `items` { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Agora, vamos incluir os `router`s dos submódulos `users` e `items`:
|
||||
|
||||
@@ -392,7 +392,7 @@ E `items.router` contém o `APIRouter` dentro do arquivo `app/routers/items.py`.
|
||||
|
||||
Com `app.include_router()` podemos adicionar cada `APIRouter` ao aplicativo principal `FastAPI`.
|
||||
|
||||
Ele incluirá todas as rotas daquele roteador como parte dele.
|
||||
Ele incluirá todas as rotas daquele router como parte dele.
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
@@ -404,7 +404,7 @@ Então, nos bastidores, ele realmente funcionará como se tudo fosse o mesmo apl
|
||||
|
||||
/// check | Verifique
|
||||
|
||||
Você não precisa se preocupar com desempenho ao incluir roteadores.
|
||||
Você não precisa se preocupar com desempenho ao incluir routers.
|
||||
|
||||
Isso levará microssegundos e só acontecerá na inicialização.
|
||||
|
||||
@@ -453,7 +453,7 @@ e funcionará corretamente, junto com todas as outras *operações de rota* adic
|
||||
|
||||
/// note | Detalhes Técnicos Avançados
|
||||
|
||||
**Observação**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
|
||||
**Nota**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
|
||||
|
||||
---
|
||||
|
||||
@@ -479,15 +479,15 @@ $ fastapi dev app/main.py
|
||||
|
||||
</div>
|
||||
|
||||
E abra os documentos em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
E abra a documentação em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Você verá a documentação automática da API, incluindo os caminhos de todos os submódulos, usando os caminhos (e prefixos) corretos e as tags corretas:
|
||||
Você verá a documentação automática da API, incluindo os paths de todos os submódulos, usando os paths (e prefixos) corretos e as tags corretas:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## Inclua o mesmo roteador várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
## Inclua o mesmo router várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
Você também pode usar `.include_router()` várias vezes com o *mesmo* roteador usando prefixos diferentes.
|
||||
Você também pode usar `.include_router()` várias vezes com o *mesmo* router usando prefixos diferentes.
|
||||
|
||||
Isso pode ser útil, por exemplo, para expor a mesma API sob prefixos diferentes, por exemplo, `/api/v1` e `/api/latest`.
|
||||
|
||||
@@ -495,10 +495,10 @@ Esse é um uso avançado que você pode não precisar, mas está lá caso precis
|
||||
|
||||
## Inclua um `APIRouter` em outro { #include-an-apirouter-in-another }
|
||||
|
||||
Da mesma forma que você pode incluir um `APIRouter` em um aplicativo `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
|
||||
Da mesma forma que você pode incluir um `APIRouter` em uma aplicação `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Certifique-se de fazer isso antes de incluir `router` no aplicativo `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
Certifique-se de fazer isso antes de incluir `router` na aplicação `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Corpo - Atualizações { #body-updates }
|
||||
|
||||
## Atualização de dados existentes com `PUT` { #update-replacing-with-put }
|
||||
## Atualização substituindo com `PUT` { #update-replacing-with-put }
|
||||
|
||||
Para atualizar um item, você pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
|
||||
@@ -22,13 +22,13 @@ Isso significa que, se você quiser atualizar o item `bar` usando `PUT` com um c
|
||||
}
|
||||
```
|
||||
|
||||
Como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
|
||||
como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
|
||||
|
||||
E os dados seriam salvos com esse "novo" `tax` de `10.5`.
|
||||
|
||||
## Atualizações parciais com `PATCH` { #partial-updates-with-patch }
|
||||
|
||||
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar parcialmente os dados.
|
||||
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar dados *parcialmente*.
|
||||
|
||||
Isso significa que você pode enviar apenas os dados que deseja atualizar, deixando o restante intacto.
|
||||
|
||||
@@ -40,25 +40,17 @@ E muitas equipes usam apenas `PUT`, mesmo para atualizações parciais.
|
||||
|
||||
Você é **livre** para usá-los como preferir, **FastAPI** não impõe restrições.
|
||||
|
||||
Mas este guia te dá uma ideia de como eles são destinados a serem usados.
|
||||
Mas este guia mostra, mais ou menos, como eles são destinados a serem usados.
|
||||
|
||||
///
|
||||
|
||||
### Usando o parâmetro `exclude_unset` do Pydantic { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no método `.model_dump()` do modelo do Pydantic.
|
||||
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no `.model_dump()` do modelo do Pydantic.
|
||||
|
||||
Como `item.model_dump(exclude_unset=True)`.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método que era chamado `.dict()` e foi descontinuado (mas ainda suportado) no Pydantic v2. Agora, deve-se usar o método `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` a partir do Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Isso gera um `dict` com apenas os dados definidos ao criar o modelo `item`, excluindo os valores padrão.
|
||||
Isso geraria um `dict` com apenas os dados que foram definidos ao criar o modelo `item`, excluindo os valores padrão.
|
||||
|
||||
Então, você pode usar isso para gerar um `dict` com apenas os dados definidos (enviados na solicitação), omitindo valores padrão:
|
||||
|
||||
@@ -68,31 +60,23 @@ Então, você pode usar isso para gerar um `dict` com apenas os dados definidos
|
||||
|
||||
Agora, você pode criar uma cópia do modelo existente usando `.model_copy()`, e passar o parâmetro `update` com um `dict` contendo os dados para atualizar.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método era chamado `.copy()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2, e renomeado para `.model_copy()`.
|
||||
|
||||
Os exemplos aqui usam `.copy()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_copy()` com o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Como `stored_item_model.model_copy(update=update_data)`:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
|
||||
### Recapitulando as atualizações parciais { #partial-updates-recap }
|
||||
|
||||
Resumindo, para aplicar atualizações parciais você pode:
|
||||
Resumindo, para aplicar atualizações parciais você deveria:
|
||||
|
||||
* (Opcionalmente) usar `PATCH` em vez de `PUT`.
|
||||
* Recuperar os dados armazenados.
|
||||
* Colocar esses dados em um modelo do Pydantic.
|
||||
* Gerar um `dict` sem valores padrão a partir do modelo de entrada (usando `exclude_unset`).
|
||||
* Dessa forma, você pode atualizar apenas os valores definidos pelo usuário, em vez de substituir os valores já armazenados com valores padrão em seu modelo.
|
||||
* Dessa forma, você pode atualizar apenas os valores realmente definidos pelo usuário, em vez de substituir valores já armazenados por valores padrão do modelo.
|
||||
* Criar uma cópia do modelo armazenado, atualizando seus atributos com as atualizações parciais recebidas (usando o parâmetro `update`).
|
||||
* Converter o modelo copiado em algo que possa ser armazenado no seu banco de dados (por exemplo, usando o `jsonable_encoder`).
|
||||
* Isso é comparável ao uso do método `.model_dump()`, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
|
||||
* Salvar os dados no seu banco de dados.
|
||||
* Converter o modelo copiado em algo que possa ser armazenado no seu BD (por exemplo, usando o `jsonable_encoder`).
|
||||
* Isso é comparável a usar o método `.model_dump()` do modelo novamente, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
|
||||
* Salvar os dados no seu BD.
|
||||
* Retornar o modelo atualizado.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
|
||||
@@ -109,8 +93,8 @@ Mas o exemplo aqui usa `PATCH` porque foi criado para esses casos de uso.
|
||||
|
||||
Observe que o modelo de entrada ainda é validado.
|
||||
|
||||
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, precisará ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
|
||||
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, você precisa ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
|
||||
|
||||
Para distinguir os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
|
||||
Para distinguir entre os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -10,11 +10,11 @@ Para declarar um corpo da **requisição**, você utiliza os modelos do <a href=
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Para enviar dados, você deve usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
Para enviar dados, você deveria usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.
|
||||
|
||||
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição para um `GET`, e proxies que intermediarem podem não suportar o corpo da requisição.
|
||||
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição ao usar `GET`, e proxies intermediários podem não suportá-lo.
|
||||
|
||||
///
|
||||
|
||||
@@ -32,7 +32,8 @@ Utilize os tipos Python padrão para todos os atributos:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional.
|
||||
|
||||
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele não é obrigatório. Caso contrário, é obrigatório. Use `None` para torná-lo apenas opcional.
|
||||
|
||||
Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse:
|
||||
|
||||
@@ -66,7 +67,7 @@ Para adicioná-lo à sua *operação de rota*, declare-o da mesma maneira que vo
|
||||
|
||||
Apenas com essa declaração de tipos do Python, o **FastAPI** irá:
|
||||
|
||||
* Ler o corpo da requisição como um JSON.
|
||||
* Ler o corpo da requisição como JSON.
|
||||
* Converter os tipos correspondentes (se necessário).
|
||||
* Validar os dados.
|
||||
* Se algum dado for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que estava incorreto.
|
||||
@@ -127,14 +128,6 @@ Dentro da função, você pode acessar todos os atributos do objeto do modelo di
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2, e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
## Corpo da requisição + parâmetros de rota { #request-body-path-parameters }
|
||||
|
||||
Você pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo.
|
||||
@@ -143,6 +136,7 @@ O **FastAPI** irá reconhecer que os parâmetros da função que combinam com pa
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Corpo da requisição + parâmetros de rota + parâmetros de consulta { #request-body-path-query-parameters }
|
||||
|
||||
Você também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo.
|
||||
|
||||
@@ -22,21 +22,13 @@ Aqui está uma ideia geral de como os modelos poderiam parecer com seus campos d
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
/// info | Informação
|
||||
### Sobre `**user_in.model_dump()` { #about-user-in-model-dump }
|
||||
|
||||
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` por compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
### Sobre `**user_in.dict()` { #about-user-in-dict }
|
||||
|
||||
#### O `.dict()` do Pydantic { #pydantics-dict }
|
||||
#### O `.model_dump()` do Pydantic { #pydantics-model-dump }
|
||||
|
||||
`user_in` é um modelo Pydantic da classe `UserIn`.
|
||||
|
||||
Os modelos Pydantic possuem um método `.dict()` que retorna um `dict` com os dados do modelo.
|
||||
Os modelos Pydantic possuem um método `.model_dump()` que retorna um `dict` com os dados do modelo.
|
||||
|
||||
Então, se criarmos um objeto Pydantic `user_in` como:
|
||||
|
||||
@@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
e depois chamarmos:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
agora temos um `dict` com os dados na variável `user_dict` (é um `dict` em vez de um objeto de modelo Pydantic).
|
||||
@@ -103,20 +95,20 @@ UserInDB(
|
||||
|
||||
#### Um modelo Pydantic a partir do conteúdo de outro { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.dict()`, este código:
|
||||
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.model_dump()`, este código:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
seria equivalente a:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...porque `user_in.dict()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
|
||||
...porque `user_in.model_dump()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
|
||||
|
||||
Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
|
||||
|
||||
@@ -125,7 +117,7 @@ Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
|
||||
E, então, adicionando o argumento de palavra-chave extra `hashed_password=hashed_password`, como em:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...acaba sendo como:
|
||||
|
||||
@@ -33,7 +33,7 @@ Para isso, primeiro importe:
|
||||
|
||||
O FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.
|
||||
|
||||
Se você tiver uma versão mais antiga, terá erros ao tentar usar `Annotated`.
|
||||
Se você tiver uma versão mais antiga, teria erros ao tentar usar `Annotated`.
|
||||
|
||||
Certifique-se de [Atualizar a versão do FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} para pelo menos 0.95.1 antes de usar `Annotated`.
|
||||
|
||||
@@ -109,7 +109,7 @@ Agora o FastAPI vai:
|
||||
|
||||
## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }
|
||||
|
||||
Versões anteriores do FastAPI (antes de <abbr title="antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`. É muito provável que você veja código assim por aí, então vou te explicar.
|
||||
Versões anteriores do FastAPI (antes de <abbr title="before 2023-03 - antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, há uma grande chance de você ver código usando isso por aí, então vou explicar.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -192,7 +192,7 @@ Você também pode adicionar um parâmetro `min_length`:
|
||||
|
||||
## Adicione expressões regulares { #add-regular-expressions }
|
||||
|
||||
Você pode definir um `pattern` de <abbr title="Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</abbr> que o parâmetro deve corresponder:
|
||||
Você pode definir um `pattern` de <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings. - Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</abbr> que o parâmetro deve corresponder:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -206,20 +206,6 @@ Se você se sentir perdido com essas ideias de **"expressão regular"**, não se
|
||||
|
||||
Agora você sabe que, sempre que precisar delas, pode usá-las no **FastAPI**.
|
||||
|
||||
### Pydantic v1 `regex` em vez de `pattern` { #pydantic-v1-regex-instead-of-pattern }
|
||||
|
||||
Antes da versão 2 do Pydantic e antes do FastAPI 0.100.0, o parâmetro se chamava `regex` em vez de `pattern`, mas agora está descontinuado.
|
||||
|
||||
Você ainda pode ver algum código usando isso:
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
|
||||
|
||||
////
|
||||
|
||||
Mas saiba que isso está descontinuado e deve ser atualizado para usar o novo parâmetro `pattern`. 🤓
|
||||
|
||||
## Valores padrão { #default-values }
|
||||
|
||||
Você pode, claro, usar valores padrão diferentes de `None`.
|
||||
@@ -280,7 +266,7 @@ Então, com uma URL como:
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
você receberá os múltiplos valores do *parâmetro de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
você receberia os múltiplos valores dos *parâmetros de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
|
||||
Assim, a resposta para essa URL seria:
|
||||
|
||||
@@ -350,7 +336,7 @@ Essas informações serão incluídas no OpenAPI gerado e usadas pelas interface
|
||||
|
||||
Tenha em mente que ferramentas diferentes podem ter níveis diferentes de suporte ao OpenAPI.
|
||||
|
||||
Algumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos o recurso ausente já esteja planejado para desenvolvimento.
|
||||
Algumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos a funcionalidade ausente já esteja planejada para desenvolvimento.
|
||||
|
||||
///
|
||||
|
||||
@@ -386,7 +372,7 @@ Então você pode declarar um `alias`, e esse alias será usado para encontrar o
|
||||
|
||||
Agora digamos que você não gosta mais desse parâmetro.
|
||||
|
||||
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsoleto, recomenda-se não usá-lo">descontinuado</abbr>.
|
||||
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsolete, recommended not to use it - obsoleto, recomenda-se não usá-lo">deprecated</abbr>.
|
||||
|
||||
Então passe o parâmetro `deprecated=True` para `Query`:
|
||||
|
||||
@@ -416,7 +402,7 @@ O Pydantic também tem <a href="https://docs.pydantic.dev/latest/concepts/valida
|
||||
|
||||
///
|
||||
|
||||
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
|
||||
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN means International Standard Book Number - ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -428,7 +414,7 @@ Isso está disponível com a versão 2 do Pydantic ou superior. 😎
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deve usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
|
||||
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deveria usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
|
||||
|
||||
Esses validadores personalizados são para coisas que podem ser verificadas **apenas** com os **mesmos dados** fornecidos na requisição.
|
||||
|
||||
@@ -440,7 +426,7 @@ O ponto importante é apenas usar **`AfterValidator` com uma função dentro de
|
||||
|
||||
---
|
||||
|
||||
Mas se você está curioso sobre este exemplo específico e ainda entretido, aqui vão alguns detalhes extras.
|
||||
Mas se você estiver curioso sobre este exemplo de código específico e ainda entretido, aqui vão alguns detalhes extras.
|
||||
|
||||
#### String com `value.startswith()` { #string-with-value-startswith }
|
||||
|
||||
@@ -450,7 +436,7 @@ Percebeu? Uma string usando `value.startswith()` pode receber uma tupla, e verif
|
||||
|
||||
#### Um item aleatório { #a-random-item }
|
||||
|
||||
Com `data.items()` obtemos um <abbr title="Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</abbr> com tuplas contendo a chave e o valor de cada item do dicionário.
|
||||
Com `data.items()` obtemos um <abbr title="Something we can iterate on with a for loop, like a list, set, etc. - Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</abbr> com tuplas contendo a chave e o valor de cada item do dicionário.
|
||||
|
||||
Convertimos esse objeto iterável em uma `list` adequada com `list(data.items())`.
|
||||
|
||||
|
||||
@@ -252,20 +252,6 @@ Então, se você enviar uma solicitação para essa *operação de rota* para o
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método era chamado `.dict()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com Pydantic v1, mas você deve usar `.model_dump()` em vez disso se puder usar Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
|
||||
O FastAPI usa `.dict()` do modelo Pydantic com <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">seu parâmetro `exclude_unset`</a> para chegar a isso.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Você também pode usar:
|
||||
|
||||
* `response_model_exclude_defaults=True`
|
||||
|
||||
@@ -8,39 +8,17 @@ Aqui estão várias maneiras de fazer isso.
|
||||
|
||||
Você pode declarar `examples` para um modelo Pydantic que serão adicionados ao JSON Schema gerado.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
|
||||
|
||||
////
|
||||
|
||||
Essas informações extras serão adicionadas como estão ao **JSON Schema** de saída para esse modelo e serão usadas na documentação da API.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
Na versão 2 do Pydantic, você usaria o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
|
||||
Você pode usar o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
|
||||
|
||||
Você pode definir `"json_schema_extra"` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
Na versão 1 do Pydantic, você usaria uma classe interna `Config` e `schema_extra`, conforme descrito na <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">documentação do Pydantic: Schema customization</a>.
|
||||
|
||||
Você pode definir `schema_extra` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
////
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Você pode usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
|
||||
Você poderia usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
|
||||
|
||||
Por exemplo, você poderia usá-la para adicionar metadados para uma interface de usuário de front-end, etc.
|
||||
|
||||
@@ -50,7 +28,7 @@ Por exemplo, você poderia usá-la para adicionar metadados para uma interface d
|
||||
|
||||
O OpenAPI 3.1.0 (usado desde o FastAPI 0.99.0) adicionou suporte a `examples`, que faz parte do padrão **JSON Schema**.
|
||||
|
||||
Antes disso, ele suportava apenas a palavra‑chave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, é recomendado migrar de `example` para `examples`. 🤓
|
||||
Antes disso, ele suportava apenas a palavra‑chave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, você é incentivado a migrar de `example` para `examples`. 🤓
|
||||
|
||||
Você pode ler mais no final desta página.
|
||||
|
||||
@@ -102,7 +80,7 @@ No entanto, <abbr title="2023-08-26">no momento em que isto foi escrito</abbr>,
|
||||
|
||||
Antes do **JSON Schema** suportar `examples`, o OpenAPI já tinha suporte para um campo diferente também chamado `examples`.
|
||||
|
||||
Esse `examples` específico do OpenAPI vai em outra seção da especificação. Ele fica nos **detalhes de cada função de operação de rota**, não dentro de cada JSON Schema.
|
||||
Esse `examples` **específico do OpenAPI** vai em outra seção da especificação OpenAPI. Ele fica nos **detalhes de cada *operação de rota***, não dentro de cada JSON Schema.
|
||||
|
||||
E o Swagger UI tem suportado esse campo `examples` particular há algum tempo. Então, você pode usá-lo para **mostrar** diferentes **exemplos na UI da documentação**.
|
||||
|
||||
@@ -189,9 +167,9 @@ Depois, o JSON Schema adicionou um campo <a href="https://json-schema.org/draft/
|
||||
|
||||
E então o novo OpenAPI 3.1.0 passou a se basear na versão mais recente (JSON Schema 2020-12), que incluiu esse novo campo `examples`.
|
||||
|
||||
Agora, esse novo campo `examples` tem precedência sobre o antigo (e customizado) campo único `example`, que agora está descontinuado.
|
||||
E agora esse novo campo `examples` tem precedência sobre o antigo campo único (e customizado) `example`, que agora está descontinuado.
|
||||
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um `dict` com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um dict com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
|
||||
/// info | Informação
|
||||
|
||||
@@ -213,7 +191,7 @@ Mas agora que o FastAPI 0.99.0 e superiores usam o OpenAPI 3.1.0, que usa o JSON
|
||||
|
||||
### Swagger UI e `examples` específicos do OpenAPI { #swagger-ui-and-openapi-specific-examples }
|
||||
|
||||
Como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
|
||||
Agora, como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
|
||||
|
||||
Para resolver isso, o FastAPI `0.103.0` **adicionou suporte** para declarar o mesmo antigo campo **específico do OpenAPI** `examples` com o novo parâmetro `openapi_examples`. 🤓
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Тестовый файл LLM { #llm-test-file }
|
||||
|
||||
Этот документ проверяет, понимает ли <abbr title="Large Language Model – Большая языковая модель">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.
|
||||
Этот документ проверяет, понимает ли <abbr title="Large Language Model - Большая языковая модель">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.
|
||||
|
||||
Тесты, добавленные здесь, увидят все создатели языковых промптов.
|
||||
Тесты, добавленные здесь, увидят все создатели языковых специфичных промптов.
|
||||
|
||||
Использование:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Проверьте, всё ли в порядке в переводе.
|
||||
* При необходимости улучшите ваш языковой специфичный промпт, общий промпт или английский документ.
|
||||
* Затем вручную исправьте оставшиеся проблемы в переводе, чтобы он был хорошим.
|
||||
* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт максимально хороши (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM — недетерминированные алгоритмы</a>).
|
||||
* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт настолько хороши, насколько это возможно (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM — недетерминированные алгоритмы</a>).
|
||||
|
||||
Тесты:
|
||||
|
||||
@@ -197,10 +197,10 @@ works(foo="bar") # Это работает 🎉
|
||||
|
||||
### abbr даёт полную расшифровку { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Как привести дела в порядок">GTD</abbr>
|
||||
* <abbr title="less than – меньше чем"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – XML веб‑токен">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Параллельный серверный интерфейс шлюза">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done - Как привести дела в порядок">GTD</abbr>
|
||||
* <abbr title="less than - меньше чем"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - XML веб‑токен">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Параллельный серверный интерфейс шлюза">PSGI</abbr>
|
||||
|
||||
### abbr даёт объяснение { #the-abbr-gives-an-explanation }
|
||||
|
||||
@@ -209,8 +209,8 @@ works(foo="bar") # Это работает 🎉
|
||||
|
||||
### abbr даёт полную расшифровку и объяснение { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output – Ввод/Вывод: чтение или запись на диск, сетевое взаимодействие.">I/O</abbr>.
|
||||
* <abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output - Ввод/Вывод: чтение или запись на диск, сетевое взаимодействие.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
|
||||
### Использование имени функции-обработчика пути как operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
Если вы хотите использовать имена функций ваших API в качестве `operationId`, вы можете пройти по всем из них и переопределить `operation_id` каждой *операции пути* с помощью их `APIRoute.name`.
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
## Исключить из OpenAPI { #exclude-from-openapi }
|
||||
|
||||
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматической документации), используйте параметр `include_in_schema` и установите его в `False`:
|
||||
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
Добавление `\f` (экранированного символа «form feed») заставит **FastAPI** обрезать текст, используемый для OpenAPI, в этой точке.
|
||||
|
||||
Эта часть не попадёт в документацию, но другие инструменты (например, Sphinx) смогут использовать остальное.
|
||||
Это не отобразится в документации, но другие инструменты (например, Sphinx) смогут использовать остальное.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
Вы, вероятно, уже видели, как объявлять `response_model` и `status_code` для *операции пути*.
|
||||
|
||||
Это определяет метаданные об основном ответе *операции пути*.
|
||||
Это определяет метаданные об основном HTTP-ответе *операции пути*.
|
||||
|
||||
Также можно объявлять дополнительные ответы с их моделями, статус-кодами и т.д.
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
Там есть `tags`, `parameters`, `requestBody`, `responses` и т.д.
|
||||
|
||||
Эта спецификация OpenAPI, специфичная для *операции пути*, обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.
|
||||
Эта специфичная для *операции пути* схема OpenAPI обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
@@ -129,13 +129,13 @@
|
||||
}
|
||||
```
|
||||
|
||||
### Пользовательская схема OpenAPI для операции пути { #custom-openapi-path-operation-schema }
|
||||
### Пользовательская схема OpenAPI для *операции пути* { #custom-openapi-path-operation-schema }
|
||||
|
||||
Словарь в `openapi_extra` будет объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.
|
||||
Словарь в `openapi_extra` будет глубоко объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.
|
||||
|
||||
Таким образом, вы можете добавить дополнительные данные к автоматически сгенерированной схеме.
|
||||
|
||||
Например, вы можете решить читать и валидировать запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать запрос в схеме OpenAPI.
|
||||
Например, вы можете решить читать и валидировать HTTP-запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать HTTP-запрос в схеме OpenAPI.
|
||||
|
||||
Это можно сделать с помощью `openapi_extra`:
|
||||
|
||||
@@ -149,52 +149,20 @@
|
||||
|
||||
Используя тот же приём, вы можете воспользоваться Pydantic-моделью, чтобы определить JSON Schema, которая затем будет включена в пользовательский раздел схемы OpenAPI для *операции пути*.
|
||||
|
||||
И вы можете сделать это, даже если тип данных в запросе — не JSON.
|
||||
И вы можете сделать это, даже если тип данных в HTTP-запросе — не JSON.
|
||||
|
||||
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого запроса как YAML, а не JSON:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic версии 1 метод для получения JSON Schema модели назывался `Item.schema()`, в Pydantic версии 2 метод называется `Item.model_json_schema()`.
|
||||
|
||||
///
|
||||
|
||||
Тем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML.
|
||||
|
||||
Затем мы работаем с запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку запроса как JSON.
|
||||
Затем мы работаем с HTTP-запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку HTTP-запроса как JSON.
|
||||
|
||||
А затем в нашем коде мы напрямую парсим этот YAML и снова используем ту же Pydantic-модель для валидации YAML-содержимого:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
А затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic версии 1 метод для парсинга и валидации объекта назывался `Item.parse_obj()`, в Pydantic версии 2 метод называется `Item.model_validate()`.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Здесь мы переиспользуем ту же Pydantic-модель.
|
||||
|
||||
@@ -46,12 +46,6 @@ $ pip install "fastapi[all]"
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 он входил в основной пакет. Теперь он распространяется как отдельный пакет, чтобы вы могли установить его только при необходимости.
|
||||
|
||||
///
|
||||
|
||||
### Создание объекта `Settings` { #create-the-settings-object }
|
||||
|
||||
Импортируйте `BaseSettings` из Pydantic и создайте подкласс, очень похожий на Pydantic‑модель.
|
||||
@@ -60,24 +54,8 @@ $ pip install "fastapi[all]"
|
||||
|
||||
Вы можете использовать все те же возможности валидации и инструменты, что и для Pydantic‑моделей, например разные типы данных и дополнительную валидацию через `Field()`.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 вы бы импортировали `BaseSettings` напрямую из `pydantic`, а не из `pydantic_settings`.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Если вам нужно что-то быстро скопировать и вставить, не используйте этот пример — воспользуйтесь последним ниже.
|
||||
@@ -215,8 +193,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
Затем обновите ваш `config.py` так:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
|
||||
|
||||
/// tip | Совет
|
||||
@@ -225,26 +201,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Класс `Config` используется только для конфигурации Pydantic. Подробнее см. <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic версии 1 конфигурация задавалась во внутреннем классе `Config`, в Pydantic версии 2 — в атрибуте `model_config`. Этот атрибут принимает `dict`, и чтобы получить автозавершение и ошибки «на лету», вы можете импортировать и использовать `SettingsConfigDict` для описания этого `dict`.
|
||||
|
||||
///
|
||||
|
||||
Здесь мы задаем параметр конфигурации `env_file` внутри вашего класса Pydantic `Settings` и устанавливаем значение равным имени файла dotenv, который хотим использовать.
|
||||
|
||||
### Создание `Settings` только один раз с помощью `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
Если у вас старое приложение FastAPI, возможно, вы используете Pydantic версии 1.
|
||||
|
||||
FastAPI поддерживает и Pydantic v1, и v2 начиная с версии 0.100.0.
|
||||
FastAPI версии 0.100.0 поддерживал либо Pydantic v1, либо v2. Он использовал ту версию, которая была установлена.
|
||||
|
||||
Если у вас был установлен Pydantic v2, использовался он. Если вместо этого был установлен Pydantic v1 — использовался он.
|
||||
FastAPI версии 0.119.0 добавил частичную поддержку Pydantic v1 изнутри Pydantic v2 (как `pydantic.v1`), чтобы упростить миграцию на v2.
|
||||
|
||||
Сейчас Pydantic v1 объявлен устаревшим, и поддержка его будет удалена в следующих версиях FastAPI, поэтому вам следует **перейти на Pydantic v2**. Так вы получите последние возможности, улучшения и исправления.
|
||||
FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать `pydantic.v1`.
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Кроме того, команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
|
||||
Команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
|
||||
|
||||
Это включает `pydantic.v1`, который больше не поддерживается в Python 3.14 и выше.
|
||||
|
||||
Если вы хотите использовать последние возможности Python, вам нужно убедиться, что вы используете Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Если у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **новые возможности в FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.
|
||||
Если у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **возможности FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.
|
||||
|
||||
## Официальное руководство { #official-guide }
|
||||
|
||||
@@ -38,13 +40,13 @@ FastAPI поддерживает и Pydantic v1, и v2 начиная с вер
|
||||
|
||||
Вы можете использовать <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> от той же команды Pydantic.
|
||||
|
||||
Этот инструмент поможет автоматически внести большую часть необходимых изменений в код.
|
||||
Этот инструмент поможет автоматически изменить большую часть кода, который нужно изменить.
|
||||
|
||||
После этого запустите тесты и проверьте, что всё работает. Если да — на этом всё. 😎
|
||||
После этого вы можете запустить тесты и проверить, что всё работает. Если да — на этом всё. 😎
|
||||
|
||||
## Pydantic v1 в v2 { #pydantic-v1-in-v2 }
|
||||
|
||||
Pydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`.
|
||||
Pydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`. Но это больше не поддерживается в версиях Python выше 3.13.
|
||||
|
||||
Это означает, что вы можете установить последнюю версию Pydantic v2 и импортировать и использовать старые компоненты Pydantic v1 из этого подмодуля так, как если бы у вас был установлен старый Pydantic v1.
|
||||
|
||||
@@ -52,7 +54,7 @@ Pydantic v2 включает всё из Pydantic v1 как подмодуль `
|
||||
|
||||
### Поддержка FastAPI для Pydantic v1 внутри v2 { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 в составе Pydantic v2, чтобы упростить миграцию на v2.
|
||||
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 изнутри Pydantic v2, чтобы упростить миграцию на v2.
|
||||
|
||||
Таким образом, вы можете обновить Pydantic до последней версии 2 и сменить импорты на подмодуль `pydantic.v1` — во многих случаях всё просто заработает.
|
||||
|
||||
@@ -106,7 +108,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же операции пути (обработчике пути) вашего приложения FastAPI:
|
||||
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же **операции пути** (обработчике пути) вашего приложения FastAPI:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
@@ -122,12 +124,12 @@ graph TB
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Сначала попробуйте `bump-pydantic`. Если тесты проходят и всё работает, вы справились одной командой. ✨
|
||||
Сначала попробуйте `bump-pydantic`: если тесты проходят и всё работает, вы справились одной командой. ✨
|
||||
|
||||
///
|
||||
|
||||
Если `bump-pydantic` не подходит для вашего случая, вы можете использовать поддержку одновременной работы моделей Pydantic v1 и v2 в одном приложении, чтобы мигрировать на Pydantic v2 постепенно.
|
||||
|
||||
Сначала обновите Pydantic до последней 2-й версии и измените импорты так, чтобы все ваши модели использовали `pydantic.v1`.
|
||||
Сначала вы можете обновить Pydantic до последней 2-й версии и изменить импорты так, чтобы все ваши модели использовали `pydantic.v1`.
|
||||
|
||||
Затем начните мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶
|
||||
Затем вы можете начать мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
При использовании **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
|
||||
|
||||
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
|
||||
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON-схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
|
||||
|
||||
Посмотрим, как это работает, и как это изменить при необходимости.
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
|
||||
|
||||
…то, поскольку у `description` есть значение по умолчанию, даже если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.
|
||||
…то, поскольку у `description` есть значение по умолчанию, если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.
|
||||
|
||||
### Модель для данных ответа { #model-for-output-response-data }
|
||||
|
||||
@@ -46,13 +46,13 @@
|
||||
|
||||
Это означает, что у него **всегда будет какое‑то значение**, просто иногда это значение может быть `None` (или `null` в JSON).
|
||||
|
||||
Следовательно, клиентам, использующим ваш API, не нужно проверять наличие этого значения: они могут **исходить из того, что поле всегда присутствует**, а в некоторых случаях имеет значение по умолчанию `None`.
|
||||
Это означает, что клиентам, использующим ваш API, не нужно проверять, существует ли это значение или нет: они могут **исходить из того, что поле всегда присутствует**, но в некоторых случаях оно будет иметь значение по умолчанию `None`.
|
||||
|
||||
В OpenAPI это описывается тем, что поле помечается как **обязательное**, поскольку оно всегда присутствует.
|
||||
|
||||
Из‑за этого JSON Schema для модели может отличаться в зависимости от использования для **входа** или **выхода**:
|
||||
|
||||
* для **входа** `description` не будет обязательным
|
||||
* для **входа** `description` **не будет обязательным**
|
||||
* для **выхода** оно будет **обязательным** (и при этом может быть `None`, или, в терминах JSON, `null`)
|
||||
|
||||
### Выходная модель в документации { #model-for-output-in-docs }
|
||||
@@ -81,9 +81,9 @@
|
||||
|
||||
Однако бывают случаи, когда вы хотите иметь **одну и ту же схему для входа и выхода**.
|
||||
|
||||
Главный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый код/SDK (рано или поздно вы это сделаете, но не сейчас).
|
||||
Главный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый клиентский код/SDK, вероятно, вы захотите сделать это в какой-то момент, но, возможно, не прямо сейчас.
|
||||
|
||||
В таком случае вы можете отключить эту функциональность в FastAPI с помощью параметра `separate_input_output_schemas=False`.
|
||||
В таком случае вы можете отключить эту функциональность в **FastAPI** с помощью параметра `separate_input_output_schemas=False`.
|
||||
|
||||
/// info | Информация
|
||||
|
||||
@@ -95,10 +95,8 @@
|
||||
|
||||
### Одна и та же схема для входной и выходной моделей в документации { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
Теперь для этой модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:
|
||||
И теперь для модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
|
||||
Это то же поведение, что и в Pydantic v1. 🤓
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
</style>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
<a href="https://fastapi.tiangolo.com/ru"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>Фреймворк FastAPI: высокая производительность, прост в изучении, быстрый в разработке, готов к продакшн</em>
|
||||
<em>Фреймворк FastAPI: высокая производительность, прост в изучении, позволяет быстро писать код, готов к продакшн</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
||||
@@ -40,7 +40,7 @@ FastAPI — это современный, быстрый (высокопрои
|
||||
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).
|
||||
* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200–300%. *
|
||||
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
|
||||
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
|
||||
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, автозавершение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
|
||||
* **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
|
||||
* **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок.
|
||||
* **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией.
|
||||
@@ -117,6 +117,12 @@ FastAPI — это современный, быстрый (высокопрои
|
||||
|
||||
---
|
||||
|
||||
## Мини-документальный фильм о FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
В конце 2025 года вышел <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">мини-документальный фильм о FastAPI</a>, вы можете посмотреть его онлайн:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## **Typer**, FastAPI для CLI { #typer-the-fastapi-of-clis }
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
@@ -257,7 +263,7 @@ INFO: Application startup complete.
|
||||
|
||||
* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.
|
||||
* Оба _пути_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
|
||||
* _Путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
|
||||
* _Путь_ `/items/{item_id}` имеет _path-параметр_ `item_id`, который должен быть `int`.
|
||||
* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
|
||||
|
||||
### Интерактивная документация API { #interactive-api-docs }
|
||||
@@ -278,9 +284,9 @@ INFO: Application startup complete.
|
||||
|
||||
## Пример обновления { #example-upgrade }
|
||||
|
||||
Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` запроса.
|
||||
Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` HTTP-запроса.
|
||||
|
||||
Объявите тело, используя стандартные типы Python, спасибо Pydantic.
|
||||
Объявите тело запроса, используя стандартные типы Python, спасибо Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
@@ -318,7 +324,7 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
Перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* Интерактивная документация API будет автоматически обновлена, включая новое тело:
|
||||
* Интерактивная документация API будет автоматически обновлена, включая новое тело запроса:
|
||||
|
||||

|
||||
|
||||
@@ -334,13 +340,13 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
Теперь откройте <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* Альтернативная документация также отразит новый параметр запроса и тело:
|
||||
* Альтернативная документация также отразит новый параметр запроса и тело запроса:
|
||||
|
||||

|
||||
|
||||
### Подведём итоги { #recap }
|
||||
|
||||
Итак, вы объявляете **один раз** типы параметров, тела запроса и т.д. как параметры функции.
|
||||
Итак, вы объявляете **один раз** типы параметров, тело запроса и т.д. как параметры функции.
|
||||
|
||||
Вы делаете это с помощью стандартных современных типов Python.
|
||||
|
||||
@@ -390,13 +396,13 @@ item: Item
|
||||
|
||||
Возвращаясь к предыдущему примеру кода, **FastAPI** будет:
|
||||
|
||||
* Валидировать наличие `item_id` в пути для `GET` и `PUT` запросов.
|
||||
* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` запросов.
|
||||
* Валидировать наличие `item_id` в пути для `GET` и `PUT` HTTP-запросов.
|
||||
* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` HTTP-запросов.
|
||||
* Если это не так, клиент увидит полезную понятную ошибку.
|
||||
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` запросов.
|
||||
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` HTTP-запросов.
|
||||
* Поскольку параметр `q` объявлен с `= None`, он необязателен.
|
||||
* Без `None` он был бы обязательным (как тело запроса в случае с `PUT`).
|
||||
* Для `PUT` запросов к `/items/{item_id}` читать тело запроса как JSON:
|
||||
* Для `PUT` HTTP-запросов к `/items/{item_id}` читать тело запроса как JSON:
|
||||
* Проверять, что есть обязательный атрибут `name`, который должен быть `str`.
|
||||
* Проверять, что есть обязательный атрибут `price`, который должен быть `float`.
|
||||
* Проверять, что есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.
|
||||
@@ -435,11 +441,11 @@ item: Item
|
||||
|
||||
Более полный пример с дополнительными возможностями см. в <a href="https://fastapi.tiangolo.com/ru/tutorial/">Учебник - Руководство пользователя</a>.
|
||||
|
||||
**Осторожно, спойлер**: учебник - руководство включает:
|
||||
**Осторожно, спойлер**: учебник - руководство пользователя включает:
|
||||
|
||||
* Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.
|
||||
* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.
|
||||
* Очень мощную и простую в использовании систему **<abbr title="также известная как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
|
||||
* Очень мощную и простую в использовании систему **<abbr title="также известна как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
|
||||
* Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию.
|
||||
* Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic).
|
||||
* Интеграцию **GraphQL** с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
|
||||
@@ -524,11 +530,11 @@ FastAPI зависит от Pydantic и Starlette.
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> — обязателен, если вы хотите использовать `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> — обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
|
||||
|
||||
Используется FastAPI:
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> — сервер, который загружает и обслуживает ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> — сервер, который загружает и «отдаёт» ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.
|
||||
* `fastapi-cli[standard]` — чтобы предоставить команду `fastapi`.
|
||||
* Включает `fastapi-cloud-cli`, который позволяет развернуть ваше приложение FastAPI в <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Большие приложения, в которых много файлов { #bigger-applications-multiple-files }
|
||||
# Большие приложения — несколько файлов { #bigger-applications-multiple-files }
|
||||
|
||||
При построении приложения или веб-API нам редко удается поместить всё в один файл.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Обратите внимание, что в каждом каталоге и подкаталоге имеется файл `__init__.py`
|
||||
Есть несколько файлов `__init__.py`: по одному в каждом каталоге или подкаталоге.
|
||||
|
||||
Это как раз то, что позволяет импортировать код из одного файла в другой.
|
||||
|
||||
@@ -43,61 +43,63 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является "Python-пакетом" (коллекцией модулей Python).
|
||||
* Он содержит файл `app/main.py`. Данный файл является частью пакета (т.е. находится внутри каталога, содержащего файл `__init__.py`), и, соответственно, он является модулем пакета: `app.main`.
|
||||
* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является "Python-пакетом" (коллекцией "Python-модулей"): `app`.
|
||||
* Он содержит файл `app/main.py`. Данный файл является частью Python-пакета (т.е. находится внутри каталога, содержащего файл `__init__.py`), и, соответственно, он является модулем этого пакета: `app.main`.
|
||||
* Он также содержит файл `app/dependencies.py`, который также, как и `app/main.py`, является модулем: `app.dependencies`.
|
||||
* Здесь также находится подкаталог `app/routers/`, содержащий `__init__.py`. Он является суб-пакетом: `app.routers`.
|
||||
* Файл `app/routers/items.py` находится внутри пакета `app/routers/`. Таким образом, он является суб-модулем: `app.routers.items`.
|
||||
* Точно также `app/routers/users.py` является ещё одним суб-модулем: `app.routers.users`.
|
||||
* Подкаталог `app/internal/`, содержащий файл `__init__.py`, является ещё одним суб-пакетом: `app.internal`.
|
||||
* А файл `app/internal/admin.py` является ещё одним суб-модулем: `app.internal.admin`.
|
||||
* Здесь также находится подкаталог `app/routers/`, содержащий `__init__.py`. Он является Python-подпакетом: `app.routers`.
|
||||
* Файл `app/routers/items.py` находится внутри пакета `app/routers/`. Таким образом, он является подмодулем: `app.routers.items`.
|
||||
* Точно так же `app/routers/users.py` является ещё одним подмодулем: `app.routers.users`.
|
||||
* Подкаталог `app/internal/`, содержащий файл `__init__.py`, является ещё одним Python-подпакетом: `app.internal`.
|
||||
* А файл `app/internal/admin.py` является ещё одним подмодулем: `app.internal.admin`.
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
Та же самая файловая структура приложения, но с комментариями:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # "app" пакет
|
||||
│ ├── __init__.py # этот файл превращает "app" в "Python-пакет"
|
||||
│ ├── main.py # модуль "main", напр.: import app.main
|
||||
│ ├── dependencies.py # модуль "dependencies", напр.: import app.dependencies
|
||||
│ └── routers # суб-пакет "routers"
|
||||
│ │ ├── __init__.py # превращает "routers" в суб-пакет
|
||||
│ │ ├── items.py # суб-модуль "items", напр.: import app.routers.items
|
||||
│ │ └── users.py # суб-модуль "users", напр.: import app.routers.users
|
||||
│ └── internal # суб-пакет "internal"
|
||||
│ ├── __init__.py # превращает "internal" в суб-пакет
|
||||
│ └── admin.py # суб-модуль "admin", напр.: import app.internal.admin
|
||||
│ └── routers # подпакет "routers"
|
||||
│ │ ├── __init__.py # превращает "routers" в подпакет
|
||||
│ │ ├── items.py # подмодуль "items", напр.: import app.routers.items
|
||||
│ │ └── users.py # подмодуль "users", напр.: import app.routers.users
|
||||
│ └── internal # подпакет "internal"
|
||||
│ ├── __init__.py # превращает "internal" в подпакет
|
||||
│ └── admin.py # подмодуль "admin", напр.: import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
|
||||
Давайте предположим, что для работы с пользователями используется отдельный файл (суб-модуль) `/app/routers/users.py`.
|
||||
Давайте предположим, что для работы с пользователями используется отдельный файл (подмодуль) `/app/routers/users.py`.
|
||||
|
||||
Для лучшей организации приложения, вы хотите отделить операции пути, связанные с пользователями, от остального кода.
|
||||
Вы хотите отделить *операции пути*, связанные с пользователями, от остального кода, чтобы сохранить порядок.
|
||||
|
||||
Но так, чтобы эти операции по-прежнему оставались частью **FastAPI** приложения/веб-API (частью одного пакета)
|
||||
Но это всё равно часть того же приложения/веб-API на **FastAPI** (часть того же «Python-пакета»).
|
||||
|
||||
С помощью `APIRouter` вы можете создать *операции пути* (*эндпоинты*) для данного модуля.
|
||||
С помощью `APIRouter` вы можете создать *операции пути* для этого модуля.
|
||||
|
||||
### Импорт `APIRouter` { #import-apirouter }
|
||||
|
||||
Точно также, как и в случае с классом `FastAPI`, вам нужно импортировать и создать объект класса `APIRouter`.
|
||||
Точно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
### Создание *эндпоинтов* с помощью `APIRouter` { #path-operations-with-apirouter }
|
||||
### *Операции пути* с `APIRouter` { #path-operations-with-apirouter }
|
||||
|
||||
В дальнейшем используйте `APIRouter` для объявления *эндпоинтов*, точно также, как вы используете класс `FastAPI`:
|
||||
И затем вы используете его, чтобы объявить ваши *операции пути*.
|
||||
|
||||
Используйте его так же, как вы использовали бы класс `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
Вы можете думать об `APIRouter` как об "уменьшенной версии" класса FastAPI`.
|
||||
Вы можете думать об `APIRouter` как об «мини-классе `FastAPI`».
|
||||
|
||||
`APIRouter` поддерживает все те же самые опции.
|
||||
Поддерживаются все те же опции.
|
||||
|
||||
`APIRouter` поддерживает все те же самые параметры, такие как `parameters`, `responses`, `dependencies`, `tags`, и т. д.
|
||||
Все те же `parameters`, `responses`, `dependencies`, `tags` и т.д.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
@@ -105,21 +107,21 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и создадим ещё один модуль с `APIRouter`.
|
||||
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и ещё один `APIRouter`.
|
||||
|
||||
## Зависимости { #dependencies }
|
||||
|
||||
Нам понадобятся некоторые зависимости, которые мы будем использовать в разных местах нашего приложения.
|
||||
Мы видим, что нам понадобятся некоторые зависимости, которые будут использоваться в нескольких местах приложения.
|
||||
|
||||
Мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).
|
||||
Поэтому мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).
|
||||
|
||||
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомизированный `X-Token` из заголовка:
|
||||
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Для простоты мы воспользовались неким воображаемым заголовоком.
|
||||
Для простоты мы воспользовались выдуманным заголовком.
|
||||
|
||||
В реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -127,30 +129,29 @@ from app.routers import items
|
||||
|
||||
## Ещё один модуль с `APIRouter` { #another-module-with-apirouter }
|
||||
|
||||
Давайте также предположим, что у вас есть *эндпоинты*, отвечающие за обработку "items", и они находятся в модуле `app/routers/items.py`.
|
||||
Давайте также предположим, что у вас есть эндпоинты, отвечающие за обработку «items» в вашем приложении, и они находятся в модуле `app/routers/items.py`.
|
||||
|
||||
У вас определены следующие *операции пути* (*эндпоинты*):
|
||||
У вас определены *операции пути* для:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
Тут всё точно также, как и в ситуации с `app/routers/users.py`.
|
||||
Тут всё та же структура, как и в случае с `app/routers/users.py`.
|
||||
|
||||
Но теперь мы хотим поступить немного умнее и слегка упростить код.
|
||||
Но мы хотим поступить умнее и слегка упростить код.
|
||||
|
||||
Мы знаем, что все *эндпоинты* данного модуля имеют некоторые общие свойства:
|
||||
Мы знаем, что все *операции пути* этого модуля имеют одинаковые:
|
||||
|
||||
* Префикс пути: `/items`.
|
||||
* Теги: (один единственный тег: `items`).
|
||||
* Дополнительные ответы (responses)
|
||||
* Зависимости: использование созданной нами зависимости `X-token`
|
||||
* `prefix` пути: `/items`.
|
||||
* `tags`: (один единственный тег: `items`).
|
||||
* Дополнительные `responses`.
|
||||
* `dependencies`: всем им нужна та зависимость `X-Token`, которую мы создали.
|
||||
|
||||
Таким образом, вместо того чтобы добавлять все эти свойства в функцию каждого отдельного *эндпоинта*,
|
||||
мы добавим их в `APIRouter`.
|
||||
Таким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`.
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Так как каждый *эндпоинт* начинается с символа `/`:
|
||||
Так как путь каждой *операции пути* должен начинаться с `/`, как здесь:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
@@ -162,73 +163,74 @@ async def read_item(item_id: str):
|
||||
|
||||
В нашем случае префиксом является `/items`.
|
||||
|
||||
Мы также можем добавить в наш маршрутизатор (router) список `тегов` (`tags`) и дополнительных `ответов` (`responses`), которые являются общими для каждого *эндпоинта*.
|
||||
Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот маршрутизатор.
|
||||
|
||||
И ещё мы можем добавить в наш маршрутизатор список `зависимостей`, которые должны вызываться при каждом обращении к *эндпоинтам*.
|
||||
И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в маршрутизаторе и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Обратите внимание, что также, как и в случае с зависимостями в декораторах *эндпоинтов* ([зависимости в декораторах операций пути](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), никакого значения в *функцию эндпоинта* передано не будет.
|
||||
Обратите внимание, что так же, как и в случае с [зависимостями в декораторах *операций пути*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, никакое значение не будет передано в вашу *функцию-обработчик пути*.
|
||||
|
||||
///
|
||||
|
||||
В результате мы получим следующие эндпоинты:
|
||||
В результате пути для items теперь такие:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
...как мы и планировали.
|
||||
|
||||
* Они будут помечены тегами из заданного списка, в нашем случае это `"items"`.
|
||||
* Эти теги особенно полезны для системы автоматической интерактивной документации (с использованием OpenAPI).
|
||||
* Каждый из них будет включать предопределенные ответы `responses`.
|
||||
* Каждый *эндпоинт* будет иметь список зависимостей (`dependencies`), исполняемых перед вызовом *эндпоинта*.
|
||||
* Если вы определили зависимости в самой операции пути, **то она также будет выполнена**.
|
||||
* Сначала выполняются зависимости маршрутизатора, затем вызываются [зависимости в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и, наконец, обычные параметрические зависимости.
|
||||
* Вы также можете добавить [зависимости `Security` с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
* Они будут помечены списком тегов, содержащим одну строку `"items"`.
|
||||
* Эти «теги» особенно полезны для систем автоматической интерактивной документации (с использованием OpenAPI).
|
||||
* Все они будут включать предопределённые `responses`.
|
||||
* Все эти *операции пути* будут иметь список `dependencies`, вычисляемых/выполняемых перед ними.
|
||||
* Если вы также объявите зависимости в конкретной *операции пути*, **они тоже будут выполнены**.
|
||||
* Сначала выполняются зависимости маршрутизатора, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и затем обычные параметрические зависимости.
|
||||
* Вы также можете добавить [`Security`-зависимости с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Например, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *эндпоинтов*, не указывая зависимости для каждой отдельной функции *эндпоинта*.
|
||||
Например, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *операций пути*. Даже если зависимости не добавляются по отдельности к каждой из них.
|
||||
|
||||
///
|
||||
|
||||
/// check | Заметка
|
||||
|
||||
Параметры `prefix`, `tags`, `responses` и `dependencies` относятся к функционалу **FastAPI**, помогающему избежать дублирования кода.
|
||||
Параметры `prefix`, `tags`, `responses` и `dependencies` — это (как и во многих других случаях) просто возможность **FastAPI**, помогающая избежать дублирования кода.
|
||||
|
||||
///
|
||||
|
||||
### Импорт зависимостей { #import-the-dependencies }
|
||||
|
||||
Наш код находится в модуле `app.routers.items` (файл `app/routers/items.py`).
|
||||
Этот код находится в модуле `app.routers.items`, в файле `app/routers/items.py`.
|
||||
|
||||
И нам нужно вызвать функцию зависимости из модуля `app.dependencies` (файл `app/dependencies.py`).
|
||||
И нам нужно получить функцию зависимости из модуля `app.dependencies`, файла `app/dependencies.py`.
|
||||
|
||||
Мы используем операцию относительного импорта `..` для импорта зависимости:
|
||||
Поэтому мы используем относительный импорт с `..` для зависимостей:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
|
||||
|
||||
#### Как работает относительный импорт? { #how-relative-imports-work }
|
||||
#### Как работает относительный импорт { #how-relative-imports-work }
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Если вы прекрасно знаете, как работает импорт в Python, то переходите к следующему разделу.
|
||||
Если вы прекрасно знаете, как работает импорт, переходите к следующему разделу ниже.
|
||||
|
||||
///
|
||||
|
||||
Одна точка `.`, как в данном примере:
|
||||
Одна точка `.`, как здесь:
|
||||
|
||||
```Python
|
||||
from .dependencies import get_token_header
|
||||
```
|
||||
|
||||
означает:
|
||||
|
||||
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` расположен в каталоге `app/routers/`)...
|
||||
* ... найдите модуль `dependencies` (файл `app/routers/dependencies.py`)...
|
||||
* ... и импортируйте из него функцию `get_token_header`.
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
|
||||
* найти модуль `dependencies` (воображаемый файл `app/routers/dependencies.py`)...
|
||||
* и импортировать из него функцию `get_token_header`.
|
||||
|
||||
К сожалению, такого файла не существует, и наши зависимости находятся в файле `app/dependencies.py`.
|
||||
Но такого файла не существует, наши зависимости находятся в файле `app/dependencies.py`.
|
||||
|
||||
Вспомните, как выглядит файловая структура нашего приложения:
|
||||
|
||||
@@ -236,7 +238,7 @@ from .dependencies import get_token_header
|
||||
|
||||
---
|
||||
|
||||
Две точки `..`, как в данном примере:
|
||||
Две точки `..`, как здесь:
|
||||
|
||||
```Python
|
||||
from ..dependencies import get_token_header
|
||||
@@ -244,12 +246,12 @@ from ..dependencies import get_token_header
|
||||
|
||||
означают:
|
||||
|
||||
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` находится в каталоге `app/routers/`)...
|
||||
* ... перейдите в родительский пакет (каталог `app/`)...
|
||||
* ... найдите в нём модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* ... и импортируйте из него функцию `get_token_header`.
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
|
||||
* перейти в родительский пакет (каталог `app/`)...
|
||||
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* и импортировать из него функцию `get_token_header`.
|
||||
|
||||
Это работает верно! 🎉
|
||||
Это работает корректно! 🎉
|
||||
|
||||
---
|
||||
|
||||
@@ -261,29 +263,29 @@ from ...dependencies import get_token_header
|
||||
|
||||
то это бы означало:
|
||||
|
||||
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` находится в каталоге `app/routers/`)...
|
||||
* ... перейдите в родительский пакет (каталог `app/`)...
|
||||
* ... затем перейдите в родительский пакет текущего пакета (такого пакета не существует, `app` находится на самом верхнем уровне 😱)...
|
||||
* ... найдите в нём модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* ... и импортируйте из него функцию `get_token_header`.
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) расположен в (каталоге `app/routers/`)...
|
||||
* перейти в родительский пакет (каталог `app/`)...
|
||||
* затем перейти в родительский пакет этого пакета (родительского пакета нет, `app` — верхний уровень 😱)...
|
||||
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* и импортировать из него функцию `get_token_header`.
|
||||
|
||||
Это будет относиться к некоторому пакету, находящемуся на один уровень выше чем `app/` и содержащему свой собственный файл `__init__.py`. Но ничего такого у нас нет. Поэтому это приведет к ошибке в нашем примере. 🚨
|
||||
Это ссылалось бы на какой-то пакет выше `app/`, со своим файлом `__init__.py` и т.п. Но у нас такого нет. Поэтому это вызвало бы ошибку в нашем примере. 🚨
|
||||
|
||||
Теперь вы знаете, как работает импорт в Python, и сможете использовать относительное импортирование в своих собственных приложениях любого уровня сложности. 🤓
|
||||
Но теперь вы знаете, как это работает, так что можете использовать относительные импорты в своих приложениях, независимо от того, насколько они сложные. 🤓
|
||||
|
||||
### Добавление пользовательских тегов (`tags`), ответов (`responses`) и зависимостей (`dependencies`) { #add-some-custom-tags-responses-and-dependencies }
|
||||
### Добавление пользовательских `tags`, `responses` и `dependencies` { #add-some-custom-tags-responses-and-dependencies }
|
||||
|
||||
Мы не будем добавлять префикс `/items` и список тегов `tags=["items"]` для каждого *эндпоинта*, т.к. мы уже их добавили с помощью `APIRouter`.
|
||||
Мы не добавляем префикс `/items` и `tags=["items"]` к каждой *операции пути*, потому что мы добавили их в `APIRouter`.
|
||||
|
||||
Но помимо этого мы можем добавить новые теги для каждого отдельного *эндпоинта*, а также некоторые дополнительные ответы (`responses`), характерные для данного *эндпоинта*:
|
||||
Но мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Последний *эндпоинт* будет иметь следующую комбинацию тегов: `["items", "custom"]`.
|
||||
Эта последняя операция пути будет иметь комбинацию тегов: `["items", "custom"]`.
|
||||
|
||||
А также в его документации будут содержаться оба ответа: один для `404` и другой для `403`.
|
||||
И в документации у неё будут оба ответа: один для `404` и один для `403`.
|
||||
|
||||
///
|
||||
|
||||
@@ -293,29 +295,29 @@ from ...dependencies import get_token_header
|
||||
|
||||
Именно сюда вы импортируете и именно здесь вы используете класс `FastAPI`.
|
||||
|
||||
Это основной файл вашего приложения, который объединяет всё в одно целое.
|
||||
Это основной файл вашего приложения, который связывает всё воедино.
|
||||
|
||||
И теперь, когда большая часть логики приложения разделена на отдельные модули, основной файл `app/main.py` будет достаточно простым.
|
||||
И так как большая часть вашей логики теперь будет находиться в отдельных специфичных модулях, основной файл будет довольно простым.
|
||||
|
||||
### Импорт `FastAPI` { #import-fastapi }
|
||||
|
||||
Вы импортируете и создаете класс `FastAPI` как обычно.
|
||||
Вы импортируете и создаёте класс `FastAPI` как обычно.
|
||||
|
||||
Мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого отдельного маршрутизатора:
|
||||
И мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
|
||||
|
||||
### Импорт `APIRouter` { #import-the-apirouter }
|
||||
|
||||
Теперь мы импортируем другие суб-модули, содержащие `APIRouter`:
|
||||
Теперь мы импортируем другие подмодули, содержащие `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
|
||||
|
||||
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются суб-модулями одного и того же Python-пакета `app`, то мы сможем их импортировать, воспользовавшись операцией относительного импорта `.`.
|
||||
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты».
|
||||
|
||||
### Как работает импорт? { #how-the-importing-works }
|
||||
### Как работает импорт { #how-the-importing-works }
|
||||
|
||||
Данная строка кода:
|
||||
Этот фрагмент:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
@@ -323,15 +325,15 @@ from .routers import items, users
|
||||
|
||||
означает:
|
||||
|
||||
* Начните с пакета, в котором содержится данный модуль (файл `app/main.py` содержится в каталоге `app/`)...
|
||||
* ... найдите суб-пакет `routers` (каталог `app/routers/`)...
|
||||
* ... и из него импортируйте суб-модули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) расположен в (каталоге `app/`)...
|
||||
* найти подпакет `routers` (каталог `app/routers/`)...
|
||||
* и импортировать из него подмодули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
|
||||
|
||||
В модуле `items` содержится переменная `router` (`items.router`), та самая, которую мы создали в файле `app/routers/items.py`, она является объектом класса `APIRouter`.
|
||||
В модуле `items` будет переменная `router` (`items.router`). Это та же самая, которую мы создали в файле `app/routers/items.py`, это объект `APIRouter`.
|
||||
|
||||
И затем мы сделаем то же самое для модуля `users`.
|
||||
И затем мы делаем то же самое для модуля `users`.
|
||||
|
||||
Мы также могли бы импортировать и другим методом:
|
||||
Мы также могли бы импортировать их так:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
@@ -339,44 +341,44 @@ from app.routers import items, users
|
||||
|
||||
/// info | Примечание
|
||||
|
||||
Первая версия является примером относительного импорта:
|
||||
Первая версия — это «относительный импорт»:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
```
|
||||
|
||||
Вторая версия является примером абсолютного импорта:
|
||||
Вторая версия — это «абсолютный импорт»:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
```
|
||||
|
||||
Узнать больше о пакетах и модулях в Python вы можете из <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">официальной документации Python о модулях</a>
|
||||
Чтобы узнать больше о Python-пакетах и модулях, прочитайте <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">официальную документацию Python о модулях</a>.
|
||||
|
||||
///
|
||||
|
||||
### Избегайте конфликтов имен { #avoid-name-collisions }
|
||||
### Избегайте конфликтов имён { #avoid-name-collisions }
|
||||
|
||||
Вместо того чтобы импортировать только переменную `router`, мы импортируем непосредственно суб-модуль `items`.
|
||||
Мы импортируем подмодуль `items` напрямую, вместо того чтобы импортировать только его переменную `router`.
|
||||
|
||||
Мы делаем это потому, что у нас есть ещё одна переменная `router` в суб-модуле `users`.
|
||||
Это потому, что у нас также есть другая переменная с именем `router` в подмодуле `users`.
|
||||
|
||||
Если бы мы импортировали их одну за другой, как показано в примере:
|
||||
Если бы мы импортировали их одну за другой, как здесь:
|
||||
|
||||
```Python
|
||||
from .routers.items import router
|
||||
from .routers.users import router
|
||||
```
|
||||
|
||||
то переменная `router` из `users` переписал бы переменную `router` из `items`, и у нас не было бы возможности использовать их одновременно.
|
||||
то `router` из `users` перезаписал бы `router` из `items`, и мы не смогли бы использовать их одновременно.
|
||||
|
||||
Поэтому, для того чтобы использовать обе эти переменные в одном файле, мы импортировали соответствующие суб-модули:
|
||||
Поэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### Подключение маршрутизаторов (`APIRouter`) для `users` и для `items` { #include-the-apirouters-for-users-and-items }
|
||||
### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Давайте подключим маршрутизаторы (`router`) из суб-модулей `users` и `items`:
|
||||
Теперь давайте подключим `router` из подмодулей `users` и `items`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
|
||||
|
||||
@@ -388,79 +390,78 @@ from .routers.users import router
|
||||
|
||||
///
|
||||
|
||||
С помощью `app.include_router()` мы можем добавить каждый из маршрутизаторов (`APIRouter`) в основное приложение `FastAPI`.
|
||||
С помощью `app.include_router()` мы можем добавить каждый `APIRouter` в основное приложение `FastAPI`.
|
||||
|
||||
Он подключит все маршруты заданного маршрутизатора к нашему приложению.
|
||||
Он включит все маршруты этого маршрутизатора как часть приложения.
|
||||
|
||||
/// note | Технические детали
|
||||
|
||||
Фактически, внутри он создаст все *операции пути* для каждой операции пути объявленной в `APIRouter`.
|
||||
Фактически, внутри он создаст *операцию пути* для каждой *операции пути*, объявленной в `APIRouter`.
|
||||
|
||||
И под капотом всё будет работать так, как будто бы мы имеем дело с одним файлом приложения.
|
||||
Так что под капотом всё будет работать так, как будто всё было одним приложением.
|
||||
|
||||
///
|
||||
|
||||
/// check | Заметка
|
||||
|
||||
При подключении маршрутизаторов не стоит беспокоиться о производительности.
|
||||
При подключении маршрутизаторов не нужно беспокоиться о производительности.
|
||||
|
||||
Операция подключения займёт микросекунды и понадобится только при запуске приложения.
|
||||
Это займёт микросекунды и произойдёт только при старте.
|
||||
|
||||
Таким образом, это не повлияет на производительность. ⚡
|
||||
Так что это не повлияет на производительность. ⚡
|
||||
|
||||
///
|
||||
|
||||
### Подключение `APIRouter` с пользовательскими префиксом (`prefix`), тегами (`tags`), ответами (`responses`), и зависимостями (`dependencies`) { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
|
||||
### Подключение `APIRouter` с пользовательскими `prefix`, `tags`, `responses` и `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
|
||||
|
||||
Теперь давайте представим, что ваша организация передала вам файл `app/internal/admin.py`.
|
||||
|
||||
Он содержит `APIRouter` с некоторыми *эндпоитами* администрирования, которые ваша организация использует для нескольких проектов.
|
||||
Он содержит `APIRouter` с некоторыми административными *операциями пути*, которые ваша организация использует в нескольких проектах.
|
||||
|
||||
В данном примере это сделать очень просто. Но давайте предположим, что поскольку файл используется для нескольких проектов,
|
||||
то мы не можем модифицировать его, добавляя префиксы (`prefix`), зависимости (`dependencies`), теги (`tags`), и т.д. непосредственно в `APIRouter`:
|
||||
Для этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
|
||||
|
||||
Но, несмотря на это, мы хотим использовать кастомный префикс (`prefix`) для подключенного маршрутизатора (`APIRouter`), в результате чего, каждая *операция пути* будет начинаться с `/admin`. Также мы хотим защитить наш маршрутизатор с помощью зависимостей, созданных для нашего проекта. И ещё мы хотим включить теги (`tags`) и ответы (`responses`).
|
||||
Но мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`.
|
||||
|
||||
Мы можем применить все вышеперечисленные настройки, не изменяя начальный `APIRouter`. Нам всего лишь нужно передать нужные параметры в `app.include_router()`.
|
||||
Мы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
|
||||
|
||||
Таким образом, оригинальный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
|
||||
Таким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
|
||||
|
||||
В результате, в нашем приложении каждый *эндпоинт* модуля `admin` будет иметь:
|
||||
В результате в нашем приложении каждая из *операций пути* из модуля `admin` будет иметь:
|
||||
|
||||
* Префикс `/admin`.
|
||||
* Тег `admin`.
|
||||
* Зависимость `get_token_header`.
|
||||
* Ответ `418`. 🍵
|
||||
|
||||
Это будет иметь место исключительно для `APIRouter` в нашем приложении, и не затронет любой другой код, использующий его.
|
||||
Но это повлияет только на этот `APIRouter` в нашем приложении, а не на любой другой код, который его использует.
|
||||
|
||||
Например, другие проекты, могут использовать тот же самый `APIRouter` с другими методами аутентификации.
|
||||
Так что, например, другие проекты могут использовать тот же `APIRouter` с другим методом аутентификации.
|
||||
|
||||
### Подключение отдельного *эндпоинта* { #include-a-path-operation }
|
||||
### Подключение *операции пути* { #include-a-path-operation }
|
||||
|
||||
Мы также можем добавить *эндпоинт* непосредственно в основное приложение `FastAPI`.
|
||||
Мы также можем добавлять *операции пути* напрямую в приложение `FastAPI`.
|
||||
|
||||
Здесь мы это делаем ... просто, чтобы показать, что это возможно 🤷:
|
||||
Здесь мы делаем это... просто чтобы показать, что можем 🤷:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
|
||||
|
||||
и это будет работать корректно вместе с другими *эндпоинтами*, добавленными с помощью `app.include_router()`.
|
||||
и это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`.
|
||||
|
||||
/// info | Сложные технические детали
|
||||
/// info | Очень технические детали
|
||||
|
||||
**Примечание**: это сложная техническая деталь, которую, скорее всего, **вы можете пропустить**.
|
||||
**Примечание**: это очень техническая деталь, которую, вероятно, можно **просто пропустить**.
|
||||
|
||||
---
|
||||
|
||||
Маршрутизаторы (`APIRouter`) не "монтируются" по-отдельности и не изолируются от остального приложения.
|
||||
`APIRouter` не «монтируются», они не изолированы от остального приложения.
|
||||
|
||||
Это происходит потому, что нужно включить их *эндпоинты* в OpenAPI схему и в интерфейс пользователя.
|
||||
Это потому, что мы хотим включить их *операции пути* в OpenAPI-схему и пользовательские интерфейсы.
|
||||
|
||||
В силу того, что мы не можем их изолировать и "примонтировать" независимо от остальных, *эндпоинты* клонируются (пересоздаются) и не подключаются напрямую.
|
||||
Так как мы не можем просто изолировать их и «смонтировать» независимо от остального, *операции пути* «клонируются» (пересоздаются), а не включаются напрямую.
|
||||
|
||||
///
|
||||
|
||||
@@ -480,24 +481,24 @@ $ fastapi dev app/main.py
|
||||
|
||||
Откройте документацию по адресу <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Вы увидите автоматическую API документацию. Она включает в себя маршруты из суб-модулей, используя верные маршруты, префиксы и теги:
|
||||
Вы увидите автоматическую документацию API, включая пути из всех подмодулей, с использованием корректных путей (и префиксов) и корректных тегов:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## Подключение существующего маршрута через новый префикс (`prefix`) { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
## Подключение одного и того же маршрутизатора несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
Вы можете использовать `.include_router()` несколько раз с одним и тем же маршрутом, применив различные префиксы.
|
||||
Вы можете использовать `.include_router()` несколько раз с *одним и тем же* маршрутизатором, используя разные префиксы.
|
||||
|
||||
Это может быть полезным, если нужно предоставить доступ к одному и тому же API через различные префиксы, например, `/api/v1` и `/api/latest`.
|
||||
Это может быть полезно, например, чтобы предоставить доступ к одному и тому же API с разными префиксами, например `/api/v1` и `/api/latest`.
|
||||
|
||||
Это продвинутый способ, который вам может и не пригодится. Мы приводим его на случай, если вдруг вам это понадобится.
|
||||
Это продвинутое использование, которое вам может и не понадобиться, но оно есть на случай, если понадобится.
|
||||
|
||||
## Включение одного маршрутизатора (`APIRouter`) в другой { #include-an-apirouter-in-another }
|
||||
## Подключение `APIRouter` в другой `APIRouter` { #include-an-apirouter-in-another }
|
||||
|
||||
Точно так же, как вы включаете `APIRouter` в приложение `FastAPI`, вы можете включить `APIRouter` в другой `APIRouter`:
|
||||
Точно так же, как вы можете подключить `APIRouter` к приложению `FastAPI`, вы можете подключить `APIRouter` к другому `APIRouter`, используя:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Удостоверьтесь, что вы сделали это до того, как подключить маршрутизатор (`router`) к вашему `FastAPI` приложению, и *эндпоинты* маршрутизатора `other_router` были также подключены.
|
||||
Убедитесь, что вы сделали это до подключения `router` к приложению `FastAPI`, чтобы *операции пути* из `other_router` также были подключены.
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
## Обновление с заменой при помощи `PUT` { #update-replacing-with-put }
|
||||
|
||||
Для полного обновления элемента можно воспользоваться операцией <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
Чтобы обновить элемент, вы можете использовать операцию <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
|
||||
Вы можете использовать `jsonable_encoder`, чтобы преобразовать входные данные в данные, которые можно сохранить как JSON (например, в NoSQL-базе данных). Например, преобразование `datetime` в `str`.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
|
||||
|
||||
`PUT` используется для получения данных, которые должны полностью заменить существующие данные.
|
||||
`PUT` используется для получения данных, которые должны заменить существующие данные.
|
||||
|
||||
### Предупреждение о замене { #warning-about-replacing }
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
поскольку оно не включает уже сохраненный атрибут `"tax": 20.2`, входная модель примет значение по умолчанию `"tax": 10.5`.
|
||||
|
||||
И данные будут сохранены с этим "новым" `tax`, равным `10,5`.
|
||||
И данные будут сохранены с этим «новым» `tax`, равным `10.5`.
|
||||
|
||||
## Частичное обновление с помощью `PATCH` { #partial-updates-with-patch }
|
||||
|
||||
Также можно использовать <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> операцию для *частичного* обновления данных.
|
||||
Также можно использовать операцию <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> для *частичного* обновления данных.
|
||||
|
||||
Это означает, что можно передавать только те данные, которые необходимо обновить, оставляя остальные нетронутыми.
|
||||
|
||||
@@ -46,19 +46,13 @@
|
||||
|
||||
### Использование параметра `exclude_unset` в Pydantic { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
Если необходимо выполнить частичное обновление, то очень полезно использовать параметр `exclude_unset` в методе `.model_dump()` модели Pydantic.
|
||||
Если вы хотите получать частичные обновления, очень полезно использовать параметр `exclude_unset` в `.model_dump()` модели Pydantic.
|
||||
|
||||
Например, `item.model_dump(exclude_unset=True)`.
|
||||
|
||||
/// info | Информация
|
||||
В результате будет сгенерирован `dict`, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию.
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_dump()`.
|
||||
|
||||
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_dump()`.
|
||||
|
||||
///
|
||||
|
||||
В результате будет сгенерирован словарь, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию. Затем вы можете использовать это для создания словаря только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
|
||||
Затем вы можете использовать это для создания `dict` только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
|
||||
|
||||
@@ -66,14 +60,6 @@
|
||||
|
||||
Теперь можно создать копию существующей модели, используя `.model_copy()`, и передать параметр `update` с `dict`, содержащим данные для обновления.
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 метод назывался `.copy()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_copy()`.
|
||||
|
||||
Примеры здесь используют `.copy()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_copy()`.
|
||||
|
||||
///
|
||||
|
||||
Например, `stored_item_model.model_copy(update=update_data)`:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
@@ -84,9 +70,9 @@
|
||||
|
||||
* (Опционально) использовать `PATCH` вместо `PUT`.
|
||||
* Извлечь сохранённые данные.
|
||||
* Поместить эти данные в Pydantic модель.
|
||||
* Поместить эти данные в Pydantic-модель.
|
||||
* Сгенерировать `dict` без значений по умолчанию из входной модели (с использованием `exclude_unset`).
|
||||
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять значения, уже сохраненные в модели по умолчанию.
|
||||
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять уже сохраненные значения значениями по умолчанию из вашей модели.
|
||||
* Создать копию хранимой модели, обновив ее атрибуты полученными частичными обновлениями (с помощью параметра `update`).
|
||||
* Преобразовать скопированную модель в то, что может быть сохранено в вашей БД (например, с помощью `jsonable_encoder`).
|
||||
* Это сравнимо с повторным использованием метода модели `.model_dump()`, но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например, `datetime` в `str`.
|
||||
@@ -97,7 +83,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Эту же технику можно использовать и для операции HTTP `PUT`.
|
||||
На самом деле эту же технику можно использовать и для операции HTTP `PUT`.
|
||||
|
||||
Но в приведенном примере используется `PATCH`, поскольку он был создан именно для таких случаев использования.
|
||||
|
||||
|
||||
@@ -32,9 +32,10 @@
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
|
||||
Так же, как при объявлении параметров запроса: когда атрибут модели имеет значение по умолчанию, он не обязателен. Иначе он обязателен. Используйте `None`, чтобы сделать его просто необязательным.
|
||||
|
||||
Например, модель выше описывает такой JSON "объект" (или Python `dict`):
|
||||
Например, модель выше описывает такой JSON "`object`" (или Python `dict`):
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -45,7 +46,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "объект" тоже будет корректным:
|
||||
...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "`object`" тоже будет корректным:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -73,7 +74,7 @@
|
||||
* Передаст полученные данные в параметр `item`.
|
||||
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т. п.) для всех атрибутов и их типов.
|
||||
* Сгенерирует определения <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
|
||||
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces – Пользовательские интерфейсы">UIs</abbr>.
|
||||
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces - Пользовательские интерфейсы">UIs</abbr>.
|
||||
|
||||
## Автоматическая документация { #automatic-docs }
|
||||
|
||||
@@ -127,14 +128,6 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
|
||||
|
||||
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, используйте `.model_dump()`.
|
||||
|
||||
///
|
||||
|
||||
## Тело запроса + параметры пути { #request-body-path-parameters }
|
||||
|
||||
Вы можете одновременно объявить параметры пути и тело запроса.
|
||||
@@ -143,6 +136,7 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Тело запроса + параметры пути + параметры запроса { #request-body-path-query-parameters }
|
||||
|
||||
Вы также можете одновременно объявить параметры **тела**, **пути** и **запроса**.
|
||||
@@ -153,7 +147,7 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
Параметры функции будут распознаны следующим образом:
|
||||
|
||||
* Если параметр также объявлен в **пути**, он будет использоваться как параметр пути.
|
||||
* Если параметр также объявлен в **пути**, он будет использоваться как path-параметр.
|
||||
* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**.
|
||||
* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.
|
||||
|
||||
@@ -161,7 +155,7 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.
|
||||
|
||||
Аннотации типов `str | None` (Python 3.10+) или `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
|
||||
Аннотации типов `str | None` (Python 3.10+) или `Union` в `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
|
||||
|
||||
Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки.
|
||||
|
||||
@@ -169,4 +163,4 @@ FastAPI понимает, что значение `q` не является об
|
||||
|
||||
## Без Pydantic { #without-pydantic }
|
||||
|
||||
Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело — Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело запроса - Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
|
||||
@@ -22,21 +22,13 @@
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
/// info | Информация
|
||||
### Про `**user_in.model_dump()` { #about-user-in-model-dump }
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
|
||||
#### `.model_dump()` из Pydantic { #pydantics-model-dump }
|
||||
|
||||
В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, следует использовать `.model_dump()`.
|
||||
`user_in` — это Pydantic-модель класса `UserIn`.
|
||||
|
||||
///
|
||||
|
||||
### Про `**user_in.dict()` { #about-user-in-dict }
|
||||
|
||||
#### `.dict()` из Pydantic { #pydantics-dict }
|
||||
|
||||
`user_in` - это Pydantic-модель класса `UserIn`.
|
||||
|
||||
У Pydantic-моделей есть метод `.dict()`, который возвращает `dict` с данными модели.
|
||||
У Pydantic-моделей есть метод `.model_dump()`, который возвращает `dict` с данными модели.
|
||||
|
||||
Поэтому, если мы создадим Pydantic-объект `user_in` таким способом:
|
||||
|
||||
@@ -47,10 +39,10 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
и затем вызовем:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
то теперь у нас есть `dict` с данными модели в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
|
||||
то теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
|
||||
|
||||
И если мы вызовем:
|
||||
|
||||
@@ -58,7 +50,7 @@ user_dict = user_in.dict()
|
||||
print(user_dict)
|
||||
```
|
||||
|
||||
мы можем получить `dict` с такими данными:
|
||||
мы получим Python `dict` с:
|
||||
|
||||
```Python
|
||||
{
|
||||
@@ -71,7 +63,7 @@ print(user_dict)
|
||||
|
||||
#### Распаковка `dict` { #unpacking-a-dict }
|
||||
|
||||
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
|
||||
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python его "распакует". Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
|
||||
|
||||
Поэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:
|
||||
|
||||
@@ -79,7 +71,7 @@ print(user_dict)
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
Будет работать так же, как примерно такой код:
|
||||
будет эквивалентно:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -90,7 +82,7 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
Или, если для большей точности мы напрямую используем `user_dict` с любым потенциальным содержимым, то этот пример будет выглядеть так:
|
||||
Или, более точно, если использовать `user_dict` напрямую, с любым содержимым, которое он может иметь в будущем:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -101,22 +93,22 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
#### Pydantic-модель из содержимого другой модели { #a-pydantic-model-from-the-contents-of-another }
|
||||
#### Pydantic-модель из содержимого другой { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
|
||||
Как в примере выше мы получили `user_dict` из `user_in.model_dump()`, этот код:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
будет равнозначен такому:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...потому что `user_in.dict()` - это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` и ставим перед ним `**`.
|
||||
...потому что `user_in.model_dump()` — это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` с префиксом `**`.
|
||||
|
||||
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
|
||||
|
||||
@@ -125,10 +117,10 @@ UserInDB(**user_in.dict())
|
||||
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
... то мы получим что-то подобное:
|
||||
...то в итоге получится что-то подобное:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -142,13 +134,13 @@ UserInDB(
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Вспомогательные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.
|
||||
Вспомогательные дополнительные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.
|
||||
|
||||
///
|
||||
|
||||
## Сократите дублирование { #reduce-duplication }
|
||||
|
||||
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
|
||||
Сокращение дублирования кода — это одна из главных идей **FastAPI**.
|
||||
|
||||
Поскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.
|
||||
|
||||
@@ -166,7 +158,7 @@ UserInDB(
|
||||
|
||||
## `Union` или `anyOf` { #union-or-anyof }
|
||||
|
||||
Вы можете определить ответ как `Union` из двух или более типов. Это означает, что ответ должен соответствовать одному из них.
|
||||
Вы можете объявить HTTP-ответ как `Union` из двух или более типов. Это означает, что HTTP-ответ может быть любым из них.
|
||||
|
||||
Он будет определён в OpenAPI как `anyOf`.
|
||||
|
||||
@@ -174,7 +166,7 @@ UserInDB(
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>, сначала указывайте наиболее детальные типы, затем менее детальные. В примере ниже более детальный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
|
||||
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a> сначала указывайте наиболее специфичный тип, затем менее специфичный. В примере ниже более специфичный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
|
||||
|
||||
///
|
||||
|
||||
@@ -192,19 +184,19 @@ UserInDB(
|
||||
some_variable: PlaneItem | CarItem
|
||||
```
|
||||
|
||||
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
|
||||
Но если мы поместим это в присваивание `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
|
||||
|
||||
## Список моделей { #list-of-models }
|
||||
|
||||
Таким же образом вы можете определять ответы как списки объектов.
|
||||
Таким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов.
|
||||
|
||||
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
|
||||
Для этого используйте стандартный `typing.List` в Python (или просто `list` в Python 3.9 и выше):
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
|
||||
|
||||
## Ответ с произвольным `dict` { #response-with-arbitrary-dict }
|
||||
|
||||
Вы также можете определить ответ, используя произвольный одноуровневый `dict` и определяя только типы ключей и значений без использования Pydantic-моделей.
|
||||
Вы также можете объявить HTTP-ответ, используя обычный произвольный `dict`, объявив только тип ключей и значений, без использования Pydantic-модели.
|
||||
|
||||
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
|
||||
|
||||
@@ -214,6 +206,6 @@ some_variable: PlaneItem | CarItem
|
||||
|
||||
## Резюме { #recap }
|
||||
|
||||
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
|
||||
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждого случая.
|
||||
|
||||
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.
|
||||
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояние, включающее `password`, `password_hash` и отсутствие пароля.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Query-параметр `q` имеет тип `str | None`, это означает, что он имеет тип `str`, но также может быть `None`. Значение по умолчанию действительно `None`, поэтому FastAPI будет знать, что он не обязателен.
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
FastAPI поймёт, что значение `q` не обязательно, из‑за значения по умолчанию `= None`.
|
||||
|
||||
@@ -177,7 +177,7 @@ q: str = Query(default="rick")
|
||||
|
||||
**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
|
||||
|
||||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||||
|
||||
Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
|
||||
|
||||
@@ -191,7 +191,7 @@ q: str = Query(default="rick")
|
||||
|
||||
## Регулярные выражения { #add-regular-expressions }
|
||||
|
||||
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
|
||||
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) - это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -205,20 +205,6 @@ q: str = Query(default="rick")
|
||||
|
||||
Теперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.
|
||||
|
||||
### `regex` из Pydantic v1 вместо `pattern` { #pydantic-v1-regex-instead-of-pattern }
|
||||
|
||||
До Pydantic версии 2 и до FastAPI 0.100.0 этот параметр назывался `regex`, а не `pattern`, но сейчас он устарел.
|
||||
|
||||
Вы всё ещё можете встретить такой код:
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
|
||||
|
||||
////
|
||||
|
||||
Имейте в виду, что это устарело, и код следует обновить на использование нового параметра `pattern`. 🤓
|
||||
|
||||
## Значения по умолчанию { #default-values }
|
||||
|
||||
Конечно, можно использовать и другие значения по умолчанию, не только `None`.
|
||||
@@ -279,7 +265,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
вы получите множественные значения query-параметра `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
|
||||
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
|
||||
|
||||
Таким образом, ответ на этот URL будет:
|
||||
|
||||
@@ -331,7 +317,7 @@ http://localhost:8000/items/
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.
|
||||
|
||||
@@ -345,7 +331,7 @@ http://localhost:8000/items/
|
||||
|
||||
Эта информация будет включена в сгенерированную OpenAPI-схему и использована интерфейсами документации и внешними инструментами.
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
Помните, что разные инструменты могут иметь разный уровень поддержки OpenAPI.
|
||||
|
||||
@@ -415,7 +401,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
///
|
||||
|
||||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number – Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) — веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) - веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -455,7 +441,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
Затем с `random.choice()` можно получить **случайное значение** из списка — то есть кортеж вида `(id, name)`. Это будет что‑то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
После этого мы **распаковываем** эти два значения кортежа в переменные `id` и `name`.
|
||||
После этого мы **присваиваем эти два значения** кортежа переменным `id` и `name`.
|
||||
|
||||
Так что, если пользователь не передал ID элемента, он всё равно получит случайную рекомендацию.
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
|
||||
|
||||
FastAPI будет использовать этот тип ответа для:
|
||||
FastAPI будет использовать этот возвращаемый тип, чтобы:
|
||||
|
||||
* **Валидации** возвращаемых данных.
|
||||
* Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру.
|
||||
* Добавления **JSON Schema** для ответа в OpenAPI *операции пути*.
|
||||
* **Валидировать** возвращаемые данные.
|
||||
* Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру данных.
|
||||
* Добавить **JSON Schema** для ответа в OpenAPI *операции пути*.
|
||||
* Это будет использовано **автоматической документацией**.
|
||||
* Это также будет использовано инструментами автоматической генерации клиентского кода.
|
||||
|
||||
@@ -23,7 +23,7 @@ FastAPI будет использовать этот тип ответа для:
|
||||
|
||||
Бывают случаи, когда вам нужно или хочется возвращать данные, которые не в точности соответствуют объявленному типу.
|
||||
|
||||
Например, вы можете хотеть **возвращать словарь (dict)** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
|
||||
Например, вы можете хотеть **возвращать словарь** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
|
||||
|
||||
Если вы добавите аннотацию возвращаемого типа, инструменты и редакторы кода начнут жаловаться (и будут правы), что функция возвращает тип (например, dict), отличный от объявленного (например, Pydantic-модель).
|
||||
|
||||
@@ -47,13 +47,13 @@ FastAPI будет использовать этот тип ответа для:
|
||||
|
||||
`response_model` принимает тот же тип, что вы бы объявили для поля Pydantic-модели, то есть это может быть одна Pydantic-модель, а может быть, например, `list` Pydantic-моделей, как `List[Item]`.
|
||||
|
||||
FastAPI будет использовать `response_model` для документации, валидации и т. п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
|
||||
FastAPI будет использовать этот `response_model` для документирования, валидации данных и т.п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Если у вас в редакторе кода, mypy и т. п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
|
||||
Если у вас в редакторе кода, mypy и т.п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
|
||||
|
||||
Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документацию данных, валидацию, фильтрацию и т.д. с помощью `response_model`.
|
||||
Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документирование, валидацию, фильтрацию данных и т.д. с помощью `response_model`.
|
||||
|
||||
///
|
||||
|
||||
@@ -61,7 +61,7 @@ FastAPI будет использовать `response_model` для докуме
|
||||
|
||||
Если вы объявите и возвращаемый тип, и `response_model`, приоритет будет у `response_model`, именно его использует FastAPI.
|
||||
|
||||
Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
|
||||
Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор кода и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
|
||||
|
||||
Вы также можете указать `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для вещей, не являющихся валидными полями Pydantic. Пример вы увидите ниже.
|
||||
|
||||
@@ -75,7 +75,7 @@ FastAPI будет использовать `response_model` для докуме
|
||||
|
||||
Чтобы использовать `EmailStr`, сначала установите <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.
|
||||
|
||||
Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите пакет, например:
|
||||
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установите пакет, например:
|
||||
|
||||
```console
|
||||
$ pip install email-validator
|
||||
@@ -105,7 +105,7 @@ $ pip install "pydantic[email]"
|
||||
|
||||
///
|
||||
|
||||
## Добавить модель для ответа { #add-an-output-model }
|
||||
## Добавить выходную модель { #add-an-output-model }
|
||||
|
||||
Вместо этого мы можем создать входную модель с паролем в открытом виде и выходную модель без него:
|
||||
|
||||
@@ -123,7 +123,7 @@ $ pip install "pydantic[email]"
|
||||
|
||||
### `response_model` или возвращаемый тип { #response-model-or-return-type }
|
||||
|
||||
В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
|
||||
В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор кода и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
|
||||
|
||||
Поэтому в этом примере мы должны объявить тип ответа в параметре `response_model`.
|
||||
|
||||
@@ -135,33 +135,33 @@ $ pip install "pydantic[email]"
|
||||
|
||||
Мы хотим, чтобы FastAPI продолжал **фильтровать** данные с помощью модели ответа. Так что, даже если функция возвращает больше данных, в ответ будут включены только поля, объявленные в модели ответа.
|
||||
|
||||
В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора и инструментов, проверяющих возвращаемый тип функции.
|
||||
В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора кода и инструментов, проверяющих возвращаемый тип функции.
|
||||
|
||||
Однако в большинстве таких случаев нам нужно лишь **отфильтровать/убрать** некоторые данные, как в этом примере.
|
||||
|
||||
И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе и инструментах и при этом получить **фильтрацию данных** от FastAPI.
|
||||
И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе кода и инструментах и при этом получить **фильтрацию данных** от FastAPI.
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
|
||||
|
||||
Так мы получаем поддержку инструментов (редакторы, mypy) — код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
|
||||
Так мы получаем поддержку инструментов — редакторов кода и mypy, так как этот код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
|
||||
|
||||
Как это работает? Давайте разберёмся. 🤓
|
||||
|
||||
### Аннотации типов и инструменты { #type-annotations-and-tooling }
|
||||
|
||||
Сначала посмотрим, как это увидят редакторы, mypy и другие инструменты.
|
||||
Сначала посмотрим, как это увидят редактор кода, mypy и другие инструменты.
|
||||
|
||||
`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он включает все поля обеих моделей.
|
||||
`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он будет включать все поля обеих моделей.
|
||||
|
||||
Мы аннотируем возвращаемый тип функции как `BaseUser`, но фактически возвращаем экземпляр `UserIn`.
|
||||
|
||||
Редактор, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
|
||||
Редактор кода, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
|
||||
|
||||
### Фильтрация данных FastAPI { #fastapi-data-filtering }
|
||||
|
||||
Теперь, для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
|
||||
Теперь для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
|
||||
|
||||
FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы вернуть гораздо больше данных, чем ожидали.
|
||||
FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы в итоге вернуть намного больше данных, чем ожидали.
|
||||
|
||||
Таким образом вы получаете лучшее из обоих миров: аннотации типов с **поддержкой инструментов** и **фильтрацию данных**.
|
||||
|
||||
@@ -171,17 +171,17 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
<img src="/img/tutorial/response-model/image01.png">
|
||||
|
||||
И обе модели используются в интерактивной документации API:
|
||||
И обе модели будут использоваться в интерактивной документации API:
|
||||
|
||||
<img src="/img/tutorial/response-model/image02.png">
|
||||
|
||||
## Другие аннотации возвращаемых типов { #other-return-type-annotations }
|
||||
|
||||
Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор, mypy и т. д.).
|
||||
Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор кода, mypy и т.д.).
|
||||
|
||||
### Возврат Response напрямую { #return-a-response-directly }
|
||||
|
||||
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
|
||||
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
|
||||
|
||||
@@ -195,7 +195,7 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
|
||||
|
||||
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот случай.
|
||||
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.
|
||||
|
||||
### Некорректные аннотации возвращаемых типов { #invalid-return-type-annotations }
|
||||
|
||||
@@ -209,15 +209,15 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
### Отключить модель ответа { #disable-response-model }
|
||||
|
||||
Продолжая пример выше, вы можете не хотеть использовать стандартную валидацию данных, документацию, фильтрацию и т.д., выполняемые FastAPI.
|
||||
Продолжая пример выше, вы можете не хотеть использовать стандартные валидацию данных, документирование, фильтрацию и т.п., выполняемые FastAPI.
|
||||
|
||||
Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов (редакторы, проверки типов вроде mypy).
|
||||
Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов вроде редакторов кода и инструментов проверки типов (например, mypy).
|
||||
|
||||
В этом случае вы можете отключить генерацию модели ответа, установив `response_model=None`:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
|
||||
|
||||
Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, не влияя на ваше приложение FastAPI. 🤓
|
||||
Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, которые вам нужны, без влияния на ваше приложение FastAPI. 🤓
|
||||
|
||||
## Параметры кодирования модели ответа { #response-model-encoding-parameters }
|
||||
|
||||
@@ -252,20 +252,6 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
|
||||
|
||||
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, применяйте `.model_dump()`.
|
||||
|
||||
///
|
||||
|
||||
/// info | Информация
|
||||
|
||||
FastAPI использует метод `.dict()` у Pydantic-моделей с <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">параметром `exclude_unset`</a>, чтобы добиться такого поведения.
|
||||
|
||||
///
|
||||
|
||||
/// info | Информация
|
||||
|
||||
Вы также можете использовать:
|
||||
|
||||
* `response_model_exclude_defaults=True`
|
||||
@@ -312,7 +298,7 @@ FastAPI достаточно умен (на самом деле, это Pydantic
|
||||
|
||||
Обратите внимание, что значения по умолчанию могут быть любыми, не только `None`.
|
||||
|
||||
Это может быть список (`[]`), число с плавающей точкой `10.5` и т. д.
|
||||
Это может быть список (`[]`), число с плавающей точкой `10.5` и т.д.
|
||||
|
||||
///
|
||||
|
||||
@@ -346,7 +332,7 @@ FastAPI достаточно умен (на самом деле, это Pydantic
|
||||
|
||||
#### Использование `list` вместо `set` { #using-lists-instead-of-sets }
|
||||
|
||||
Если вы забыли использовать `set` и применили `list` или `tuple`, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:
|
||||
Если вы забыли использовать `set` и применили `list` или `tuple` вместо него, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
|
||||
|
||||
|
||||
@@ -8,36 +8,14 @@
|
||||
|
||||
Вы можете объявить `examples` для модели Pydantic, которые будут добавлены в сгенерированную JSON Schema.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
|
||||
|
||||
////
|
||||
|
||||
Эта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
В Pydantic версии 2 вы будете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
|
||||
Вы можете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
|
||||
|
||||
Вы можете задать `"json_schema_extra"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
В Pydantic версии 1 вы будете использовать внутренний класс `Config` и `schema_extra`, как описано в <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Документации Pydantic: Настройка схемы</a>.
|
||||
|
||||
Вы можете задать `schema_extra` со `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
|
||||
|
||||
////
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Вы можете использовать тот же приём, чтобы расширить JSON Schema и добавить свою собственную дополнительную информацию.
|
||||
@@ -124,7 +102,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
|
||||
|
||||
Ключи `dict` идентифицируют каждый пример, а каждое значение — это ещё один `dict`.
|
||||
|
||||
Каждый конкретный пример‑`dict` в `examples` может содержать:
|
||||
Каждый конкретный пример `dict` в `examples` может содержать:
|
||||
|
||||
* `summary`: Краткое описание примера.
|
||||
* `description`: Подробное описание, которое может содержать текст в Markdown.
|
||||
@@ -135,7 +113,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
|
||||
|
||||
### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
|
||||
### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
|
||||
|
||||
С `openapi_examples`, добавленным в `Body()`, страница `/docs` будет выглядеть так:
|
||||
|
||||
@@ -213,7 +191,7 @@ OpenAPI также добавила поля `example` и `examples` в друг
|
||||
|
||||
### Swagger UI и специфичные для OpenAPI `examples` { #swagger-ui-and-openapi-specific-examples }
|
||||
|
||||
Раньше, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.
|
||||
Теперь, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.
|
||||
|
||||
Чтобы решить это, FastAPI `0.103.0` **добавил поддержку** объявления того же старого, **специфичного для OpenAPI**, поля `examples` с новым параметром `openapi_examples`. 🤓
|
||||
|
||||
|
||||
@@ -90,5 +90,12 @@ For the following technical terms, use these specific translations to ensure con
|
||||
* serve (meaning providing access to something): «отдавать» (or `предоставлять доступ к`)
|
||||
* recap (noun): резюме
|
||||
* utility function: вспомогательная функция
|
||||
* fast to code: позволяет быстро писать код
|
||||
* Tutorial - User Guide: Учебник - Руководство пользователя
|
||||
* submodule: подмодуль
|
||||
* subpackage: подпакет
|
||||
* router: роутер
|
||||
* building, deploying, accessing (when describing features of FastAPI Cloud): созданиe образа, развертывание и доступ
|
||||
* type checker tool: инструмент проверки типов
|
||||
|
||||
Do not add whitespace in `т.д.`, `т.п.`.
|
||||
|
||||
@@ -4,10 +4,16 @@ Translate to Turkish (Türkçe).
|
||||
|
||||
Language code: tr.
|
||||
|
||||
### Core principle
|
||||
|
||||
Don't translate word-by-word. Rewrite naturally in Turkish as if writing the doc from scratch. Preserve meaning, but prioritize fluency over literal accuracy.
|
||||
|
||||
### Grammar and tone
|
||||
|
||||
- Use instructional Turkish, consistent with existing Turkish docs.
|
||||
- Use imperative/guide language when appropriate (e.g. “açalım”, “gidin”, “kopyalayalım”).
|
||||
- Use imperative/guide language (e.g. "açalım", "gidin", "kopyalayalım", "bir bakalım").
|
||||
- Avoid filler words and overly long sentences.
|
||||
- Ensure sentences make sense in Turkish context — adjust structure, conjunctions, and verb forms as needed for natural flow (e.g. use "Ancak" instead of "Ve" when connecting contrasting sentences, use "-maktadır/-mektedir" for formal statements).
|
||||
|
||||
### Headings
|
||||
|
||||
@@ -15,13 +21,23 @@ Language code: tr.
|
||||
|
||||
### Quotes
|
||||
|
||||
- Alıntı stili mevcut Türkçe dokümanlarla tutarlı tutun (genellikle metin içinde ASCII tırnak işaretleri kullanılır).
|
||||
- Satır içi kod, kod blokları, URL'ler veya dosya yolları içindeki tırnak işaretlerini asla değiştirmeyin.
|
||||
- Keep quote style consistent with existing Turkish docs (typically ASCII quotes in text).
|
||||
- Never modify quotes inside inline code, code blocks, URLs, or file paths.
|
||||
|
||||
### Ellipsis
|
||||
|
||||
- Üç nokta (...) stili mevcut Türkçe dokümanlarla tutarlı tutun.
|
||||
- Kod, URL veya CLI örneklerindeki `...` ifadesini asla değiştirmeyin.
|
||||
- Keep ellipsis style (`...`) consistent with existing Turkish docs.
|
||||
- Never modify `...` in code, URLs, or CLI examples.
|
||||
|
||||
### Consistency
|
||||
|
||||
- Use the same translation for the same term throughout the document.
|
||||
- If you translate a concept one way, keep it consistent across all occurrences.
|
||||
|
||||
### Links and references
|
||||
|
||||
- Never modify link syntax like `{.internal-link target=_blank}`.
|
||||
- Keep markdown link structure intact: `[text](url){.internal-link}`.
|
||||
|
||||
### Preferred translations / glossary
|
||||
|
||||
|
||||
Reference in New Issue
Block a user