committed by
GitHub
37 changed files with 998 additions and 1262 deletions
@ -1,83 +1,75 @@ |
|||
# FastAPI CLI |
|||
# FastAPI CLI { #fastapi-cli } |
|||
|
|||
**FastAPI CLI**는 FastAPI 애플리케이션을 실행하고, 프로젝트를 관리하는 등 다양한 작업을 수행할 수 있는 커맨드 라인 프로그램입니다. |
|||
**FastAPI CLI**는 FastAPI 애플리케이션을 서빙하고, 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: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> |
|||
|
|||
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮ |
|||
│ │ |
|||
│ 🐍 main.py │ |
|||
│ │ |
|||
╰──────────────────────╯ |
|||
|
|||
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font> |
|||
<font color="#3465A4">INFO </font> Found importable FastAPI app |
|||
|
|||
╭─ <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> │ |
|||
│ │ |
|||
╰──────────────────────────╯ |
|||
|
|||
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font> |
|||
|
|||
<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> |
|||
|
|||
<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. |
|||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u> |
|||
|
|||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀 |
|||
|
|||
Searching for package file structure from directories with |
|||
<font color="#3465A4">__init__.py</font> files |
|||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the |
|||
following code: |
|||
|
|||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use: |
|||
<b>fastapi run</b> |
|||
|
|||
Logs: |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories: |
|||
<b>[</b><font color="#4E9A06">'/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. |
|||
``` |
|||
|
|||
</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)** 기능이 활성화되어, 코드에 변경이 생기면 서버를 자동으로 다시 시작합니다. 하지만 이 기능은 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 따라서 개발 환경에서만 사용하는 것이 좋습니다. 또한, 서버는 컴퓨터가 자체적으로 통신할 수 있는 IP 주소(`localhost`)인 `127.0.0.1`에서 연결을 대기합니다. |
|||
기본적으로 **auto-reload**가 활성화되어 코드에 변경이 생기면 서버를 자동으로 다시 로드합니다. 이는 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 개발 환경에서만 사용해야 합니다. 또한 컴퓨터가 자신과만 통신하기 위한(`localhost`) IP인 `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/index.md){.internal-link target=_blank}에서 확인할 수 있습니다. |
|||
|
|||
/// |
|||
|
|||
@ -1,81 +1,79 @@ |
|||
# 역사, 디자인 그리고 미래 |
|||
# 역사, 디자인 그리고 미래 { #history-design-and-future } |
|||
|
|||
어느 날, [한 FastAPI 사용자](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920)가 이렇게 물었습니다: |
|||
얼마 전, <a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">한 **FastAPI** 사용자가 이렇게 물었습니다</a>: |
|||
|
|||
> 이 프로젝트의 역사를 알려 주실 수 있나요? 몇 주 만에 멋진 결과를 낸 것 같아요. [...] |
|||
> 이 프로젝트의 역사는 무엇인가요? 몇 주 만에 아무 데서도 갑자기 나타나 엄청나게 좋아진 것처럼 보이네요 [...] |
|||
|
|||
여기서 그 역사에 대해 간단히 설명하겠습니다. |
|||
|
|||
--- |
|||
## 대안 { #alternatives } |
|||
|
|||
## 대안 |
|||
저는 여러 해 동안 복잡한 요구사항(머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 등)을 가진 API를 만들면서 여러 개발 팀을 이끌어 왔습니다. |
|||
|
|||
저는 여러 해 동안 머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 같은 복잡한 요구사항을 가진 API를 개발하며 여러 팀을 이끌어 왔습니다. |
|||
그 과정에서 많은 대안을 조사하고, 테스트하고, 사용해야 했습니다. |
|||
|
|||
이 과정에서 많은 대안을 조사하고, 테스트하며, 사용해야 했습니다. **FastAPI**의 역사는 그 이전에 나왔던 여러 도구의 역사와 밀접하게 연관되어 있습니다. |
|||
**FastAPI**의 역사는 상당 부분 그 이전에 있던 도구들의 역사입니다. |
|||
|
|||
[대안](alternatives.md){.internal-link target=_blank} 섹션에서 언급된 것처럼: |
|||
|
|||
> **FastAPI**는 이전에 나왔던 많은 도구들의 노력 없이는 존재하지 않았을 것입니다. |
|||
> |
|||
> 이전에 개발된 여러 도구들이 이 프로젝트에 영감을 주었습니다. |
|||
> |
|||
> 저는 오랫동안 새로운 프레임워크를 만드는 것을 피하고자 했습니다. 처음에는 **FastAPI**가 제공하는 기능들을 다양한 프레임워크와 플러그인, 도구들을 조합해 해결하려 했습니다. |
|||
> |
|||
> 하지만 결국에는 이 모든 기능을 통합하는 도구가 필요해졌습니다. 이전 도구들로부터 최고의 아이디어들을 모으고, 이를 최적의 방식으로 조합해야만 했습니다. 이는 :term:Python 3.6+ 타입 힌트 <type hints>와 같은, 이전에는 사용할 수 없었던 언어 기능이 가능했기 때문입니다. |
|||
<blockquote markdown="1"> |
|||
|
|||
--- |
|||
**FastAPI**는 다른 사람들이 이전에 해온 작업이 없었다면 존재하지 않았을 것입니다. |
|||
|
|||
## 조사 |
|||
그 전에 만들어진 많은 도구들이 이것의 탄생에 영감을 주었습니다. |
|||
|
|||
여러 대안을 사용해 보며 다양한 도구에서 배운 점들을 모아 저와 개발팀에게 가장 적합한 방식을 찾았습니다. |
|||
저는 여러 해 동안 새로운 프레임워크를 만드는 것을 피하고 있었습니다. 처음에는 **FastAPI**가 다루는 모든 기능을 여러 다른 프레임워크, 플러그인, 도구들을 사용해 해결하려고 했습니다. |
|||
|
|||
예를 들어, 표준 :term:Python 타입 힌트 <type hints>에 기반하는 것이 이상적이라는 점이 명확했습니다. |
|||
하지만 어느 시점에는, 이전 도구들의 최고의 아이디어를 가져와 가능한 한 최선의 방식으로 조합하고, 이전에는 존재하지 않았던 언어 기능(Python 3.6+ type hints)을 사용해 이 모든 기능을 제공하는 무언가를 만드는 것 외에는 다른 선택지가 없었습니다. |
|||
|
|||
또한, 이미 존재하는 표준을 활용하는 것이 가장 좋은 접근법이라 판단했습니다. |
|||
</blockquote> |
|||
|
|||
그래서 **FastAPI**의 코드를 작성하기 전에 몇 달 동안 OpenAPI, JSON Schema, OAuth2 명세를 연구하며 이들의 관계와 겹치는 부분, 차이점을 이해했습니다. |
|||
## 조사 { #investigation } |
|||
|
|||
--- |
|||
이전의 모든 대안을 사용해 보면서, 각 도구로부터 배울 기회를 얻었고, 아이디어를 가져와 제가 일해온 개발 팀들과 저 자신에게 가장 적합하다고 찾은 방식으로 조합할 수 있었습니다. |
|||
|
|||
## 디자인 |
|||
예를 들어, 이상적으로는 표준 Python 타입 힌트에 기반해야 한다는 점이 분명했습니다. |
|||
|
|||
그 후, **FastAPI** 사용자가 될 개발자로서 사용하고 싶은 개발자 "API"를 디자인했습니다. |
|||
또한, 가장 좋은 접근법은 이미 존재하는 표준을 사용하는 것이었습니다. |
|||
|
|||
[Python Developer Survey](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)에 따르면 약 80%의 Python 개발자가 PyCharm, VS Code, Jedi 기반 편집기 등에서 개발합니다. 이 과정에서 여러 아이디어를 테스트했습니다. |
|||
그래서 **FastAPI**의 코딩을 시작하기도 전에, OpenAPI, JSON Schema, OAuth2 등과 같은 명세를 몇 달 동안 공부했습니다. 이들의 관계, 겹치는 부분, 차이점을 이해하기 위해서였습니다. |
|||
|
|||
대부분의 다른 편집기도 유사하게 동작하기 때문에, **FastAPI**의 이점은 거의 모든 편집기에서 누릴 수 있습니다. |
|||
## 디자인 { #design } |
|||
|
|||
이 과정을 통해 코드 중복을 최소화하고, 모든 곳에서 자동 완성, 타입 검사, 에러 확인 기능이 제공되는 최적의 방식을 찾아냈습니다. |
|||
그 다음에는 (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와 완벽히 호환되도록 개선하고, 다양한 제약 조건 선언을 지원하며, 여러 편집기에서의 자동 완성과 타입 검사 기능을 향상하기 위해 기여했습니다. |
|||
모든 개발자에게 최고의 개발 경험을 제공하는 방식으로 말입니다. |
|||
|
|||
또한, 또 다른 주요 필요조건이었던 [Starlette](https://www.starlette.dev/)에도 기여했습니다. |
|||
## 필요조건 { #requirements } |
|||
|
|||
--- |
|||
여러 대안을 테스트한 후, 장점 때문에 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">**Pydantic**</a>을 사용하기로 결정했습니다. |
|||
|
|||
## 개발 |
|||
그 후, JSON Schema를 완전히 준수하도록 하고, 제약 조건 선언을 정의하는 다양한 방식을 지원하며, 여러 편집기에서의 테스트를 바탕으로 편집기 지원(타입 검사, 자동 완성)을 개선하기 위해 기여했습니다. |
|||
|
|||
**FastAPI**를 개발하기 시작할 즈음에는 대부분의 준비가 이미 완료된 상태였습니다. 설계가 정의되었고, 필요조건과 도구가 준비되었으며, 표준과 명세에 대한 지식도 충분했습니다. |
|||
개발 과정에서, 또 다른 핵심 필요조건인 <a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>에도 기여했습니다. |
|||
|
|||
--- |
|||
## 개발 { #development } |
|||
|
|||
## 미래 |
|||
**FastAPI** 자체를 만들기 시작했을 때쯤에는, 대부분의 조각들이 이미 갖춰져 있었고, 디자인은 정의되어 있었으며, 필요조건과 도구는 준비되어 있었고, 표준과 명세에 대한 지식도 명확하고 최신 상태였습니다. |
|||
|
|||
현시점에서 **FastAPI**가 많은 사람들에게 유용하다는 것이 명백해졌습니다. |
|||
## 미래 { #future } |
|||
|
|||
여러 용도에 더 적합한 도구로서 기존 대안보다 선호되고 있습니다. |
|||
이미 많은 개발자와 팀들이 **FastAPI**에 의존해 프로젝트를 진행 중입니다 (저와 제 팀도 마찬가지입니다). |
|||
이 시점에는, **FastAPI**가 그 아이디어와 함께 많은 사람들에게 유용하다는 것이 이미 분명합니다. |
|||
|
|||
하지만 여전히 개선해야 할 점과 추가할 기능들이 많이 남아 있습니다. |
|||
많은 사용 사례에 더 잘 맞기 때문에 이전 대안들보다 선택되고 있습니다. |
|||
|
|||
많은 개발자와 팀이 이미 자신의 프로젝트를 위해 **FastAPI**에 의존하고 있습니다(저와 제 팀도 포함해서요). |
|||
|
|||
하지만 여전히, 앞으로 나올 개선 사항과 기능들이 많이 있습니다. |
|||
|
|||
**FastAPI**의 미래는 밝습니다. |
|||
|
|||
**FastAPI**는 밝은 미래로 나아가고 있습니다. |
|||
그리고 [여러분의 도움](help-fastapi.md){.internal-link target=_blank}은 큰 힘이 됩니다. |
|||
|
|||
@ -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="[email protected] |
|||
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: |
|||
|
|||
@ -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="[email protected] |
|||
и затем вызовем: |
|||
|
|||
```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` и отсутствие пароля. |
|||
|
|||
Loading…
Reference in new issue