committed by
GitHub
1 changed files with 360 additions and 0 deletions
@ -0,0 +1,360 @@ |
|||
# SQL (๊ด๊ณํ) ๋ฐ์ดํฐ๋ฒ ์ด์ค |
|||
|
|||
**FastAPI**์์ SQL(๊ด๊ณํ) ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ์ ํ์๊ฐ ์๋๋๋ค. ์ฌ๋ฌ๋ถ์ด ์ํ๋ **์ด๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ** ์ฌ์ฉํ ์ ์์ต๋๋ค. |
|||
|
|||
์ฌ๊ธฐ์๋ <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>์ ์ฌ์ฉํ๋ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. |
|||
|
|||
**SQLModel**์ <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a>์ Pydantic์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค.SQLModel์ **SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค**๋ฅผ ์ฌ์ฉํ๋ FastAPI ์ ํ๋ฆฌ์ผ์ด์
์ ์๋ฒฝํ ์ด์ธ๋ฆฌ๋๋ก **FastAPI**์ ์ ์์๊ฐ ์ค๊ณํ ๋๊ตฌ์
๋๋ค. |
|||
|
|||
/// tip | ํ |
|||
|
|||
๋ค๋ฅธ SQL ๋๋ NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค (์ผ๋ถ๋ <abbr title="๊ฐ์ฒด ๊ด๊ณ ๋งคํผ(Object Relational Mapper), SQL ํ
์ด๋ธ์ ๋ํ๋ด๋ ํด๋์ค๋ฅผ ์ ๊ณตํ๊ณ ํ
์ด๋ธ์ ํ์ ์ธ์คํด์ค๋ก ํํํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ง์นญํ๋ ์ฉ์ด">"ORM"</abbr>์ด๋ผ๊ณ ๋ ๋ถ๋ฆฝ๋๋ค), FastAPI๋ ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฌ์ฉ์ ๊ฐ์ํ์ง ์์ต๋๋ค. ๐ |
|||
|
|||
/// |
|||
|
|||
SQLModel์ SQLAlchemy๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฏ๋ก, SQLAlchemy์์ **์ง์ํ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค**๋ฅผ ์์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค(SQLModel์์๋ ๋์ผํ๊ฒ ์ง์๋ฉ๋๋ค). ์๋ฅผ ๋ค๋ฉด: |
|||
|
|||
* PostgreSQL |
|||
* MySQL |
|||
* SQLite |
|||
* Oracle |
|||
* Microsoft SQL Server ๋ฑ. |
|||
|
|||
์ด ์์ ์์๋ **SQLite**๋ฅผ ์ฌ์ฉํฉ๋๋ค. SQLite๋ ๋จ์ผ ํ์ผ์ ์ฌ์ฉํ๊ณ ํ์ด์ฌ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ฐ๋ผ์ ์ด ์์ ๋ฅผ ๊ทธ๋๋ก ๋ณต์ฌํ์ฌ ์คํํ ์ ์์ต๋๋ค. |
|||
|
|||
๋์ค์ ์ค์ ํ๋ก๋์
์ ํ๋ฆฌ์ผ์ด์
์์๋ **PostgreSQL**๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. |
|||
|
|||
/// tip | ํ |
|||
|
|||
**FastAPI**์ **PostgreSQL**๋ฅผ ํฌํจํ์ฌ ํ๋ก ํธ์๋์ ๋ค์ํ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ ๊ณต์ ํ๋ก์ ํธ ์์ฑ๊ธฐ๊ฐ ์์ต๋๋ค: <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a> |
|||
|
|||
/// |
|||
|
|||
์ด ํํ ๋ฆฌ์ผ์ ๋งค์ฐ ๊ฐ๋จํ๊ณ ์งง์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ๋ณธ ๊ฐ๋
, SQL, ๋๋ ๋ ๋ณต์กํ ๊ธฐ๋ฅ์ ๋ํด ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด, <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel ๋ฌธ์</a>๋ฅผ ์ฐธ๊ณ ํ์ธ์. |
|||
|
|||
## `SQLModel` ์ค์นํ๊ธฐ |
|||
|
|||
๋จผ์ , [๊ฐ์ ํ๊ฒฝ](../virtual-environments.md){.internal-link target=_blank}์ ์์ฑํ๊ณ ํ์ฑํํ ๋ค์, `sqlmodel`์ ์ค์นํ์ธ์: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install sqlmodel |
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
## ๋จ์ผ ๋ชจ๋ธ๋ก ์ ํ๋ฆฌ์ผ์ด์
์์ฑํ๊ธฐ |
|||
|
|||
์ฐ์ ๋จ์ผ **SQLModel** ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ์ฅ ๊ฐ๋จํ ์ฒซ ๋ฒ์งธ ๋ฒ์ ์ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค. |
|||
|
|||
์ดํ **๋ค์ค ๋ชจ๋ธ**์ ์ถ๊ฐํ์ฌ ๋ณด์๊ณผ ์ ์ฐ์ฑ์ ๊ฐํํ ๊ฒ์
๋๋ค. ๐ค |
|||
|
|||
### ๋ชจ๋ธ ์์ฑํ๊ธฐ |
|||
|
|||
`SQLModel`์ ๊ฐ์ ธ์ค๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ์ ์์ฑํฉ๋๋ค: |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *} |
|||
|
|||
`Hero` ํด๋์ค๋ Pydantic ๋ชจ๋ธ๊ณผ ๋งค์ฐ ์ ์ฌํฉ๋๋ค (์ค์ ๋ก ๋ด๋ถ์ ์ผ๋ก *Pydantic ๋ชจ๋ธ์ด๊ธฐ๋ ํฉ๋๋ค*). |
|||
|
|||
๋ช ๊ฐ์ง ์ฐจ์ด์ ์ด ์์ต๋๋ค: |
|||
|
|||
* `table=True`๋ SQLModel์ ์ด ๋ชจ๋ธ์ด *ํ
์ด๋ธ ๋ชจ๋ธ*์ด๋ฉฐ, ๋จ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ์ด ์๋๋ผ SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ **ํ
์ด๋ธ**์ ๋ํ๋ธ๋ค๋ ๊ฒ์ ์๋ ค์ค๋๋ค. (๋ค๋ฅธ ์ผ๋ฐ์ ์ธ Pydantic ํด๋์ค์ฒ๋ผ) ๋จ์ํ *๋ฐ์ดํฐ ๋ชจ๋ธ*์ด ์๋๋๋ค. |
|||
|
|||
* `Field(primary_key=True)`๋ SQLModel์ `id`๊ฐ SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ **๊ธฐ๋ณธ ํค**์์ ์๋ ค์ค๋๋ค (SQL ๊ธฐ๋ณธ ํค์ ๋ํ ์์ธํ ๋ด์ฉ์ SQLModel ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ธ์). |
|||
|
|||
`int | None` ์ ํ์ผ๋ก ์ค์ ํ๋ฉด, SQLModel์ ํด๋น ์ด์ด SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ `INTEGER` ์ ํ์ด๋ฉฐ `NULLABLE` ๊ฐ์ด์ด์ผ ํ๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. |
|||
|
|||
* `Field(index=True)`๋ SQLModel์ ํด๋น ์ด์ ๋ํด **SQL ์ธ๋ฑ์ค**๋ฅผ ์์ฑํ๋๋ก ์ง์ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ด ์ด์ผ๋ก ํํฐ๋ง๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ๋ ๋ ๋น ๋ฅด๊ฒ ์กฐํํ ์ ์์ต๋๋ค. |
|||
|
|||
SQLModel์ `str`์ผ๋ก ์ ์ธ๋ ํญ๋ชฉ์ด SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ `TEXT` (๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ๋ผ `VARCHAR`) ์ ํ์ ์ด๋ก ์ ์ฅ๋๋ค๋ ๊ฒ์ ์ธ์ํฉ๋๋ค. |
|||
|
|||
### ์์ง ์์ฑํ๊ธฐ |
|||
|
|||
SQLModel์ `engine` (๋ด๋ถ์ ์ผ๋ก๋ SQLAlchemy `engine`)์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ **์ฐ๊ฒฐ์ ์ ์ง**ํ๋ ์ญํ ์ ํฉ๋๋ค. |
|||
|
|||
**ํ๋์ ๋จ์ผ engine ๊ฐ์ฒด**๋ฅผ ํตํด ์ฝ๋ ์ ์ฒด์์ ๋์ผํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *} |
|||
|
|||
`check_same_thread=False`๋ฅผ ์ฌ์ฉํ๋ฉด FastAPI์์ ์ฌ๋ฌ ์ค๋ ๋์์ ๋์ผํ SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ **ํ๋์ ๋จ์ผ ์์ฒญ**์ด **์ฌ๋ฌ ์ค๋ ๋**๋ฅผ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ํ์ํฉ๋๋ค(์: ์์กด์ฑ์์ ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ). |
|||
|
|||
๊ฑฑ์ ํ์ง ๋ง์ธ์. ์ฝ๋๊ฐ ๊ตฌ์กฐํ๋ ๋ฐฉ์์ผ๋ก ์ธํด, ์ดํ์ **๊ฐ ์์ฒญ๋ง๋ค ๋จ์ผ SQLModel *์ธ์
*์ ์ฌ์ฉ**ํ๋๋ก ๋ณด์ฅํ ๊ฒ์
๋๋ค. ์ค์ ๋ก ๊ทธ๊ฒ์ด `check_same_thread`๊ฐ ํ๋ ค๋ ๊ฒ์
๋๋ค. |
|||
|
|||
### ํ
์ด๋ธ ์์ฑํ๊ธฐ |
|||
|
|||
๊ทธ ๋ค์ `SQLModel.metadata.create_all(engine)`์ ์ฌ์ฉํ์ฌ ๋ชจ๋ *ํ
์ด๋ธ ๋ชจ๋ธ*์ **ํ
์ด๋ธ์ ์์ฑ**ํ๋ ํจ์๋ฅผ ์ถ๊ฐํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *} |
|||
|
|||
### ์ธ์
์์กด์ฑ ์์ฑํ๊ธฐ |
|||
|
|||
**`Session`**์ **๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ฒด**๋ฅผ ์ ์ฅํ๊ณ ๋ฐ์ดํฐ์ ํ์ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํ ํ, **`engine`์ ํตํด** ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํต์ ํฉ๋๋ค. |
|||
|
|||
`yield`๋ฅผ ์ฌ์ฉํด FastAPI์ **์์กด์ฑ**์ ์์ฑํ์ฌ ๊ฐ ์์ฒญ๋ง๋ค ์๋ก์ด `Session`์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ์์ฒญ๋น ํ๋์ ์ธ์
๋ง ์ฌ์ฉ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ๐ค |
|||
|
|||
๊ทธ๋ฐ ๋ค์ ์ด ์์กด์ฑ์ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ๊ฐ์ํํ๊ธฐ ์ํด `Annotated` ์์กด์ฑ `SessionDep`์ ์์ฑํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *} |
|||
|
|||
### ์์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ ์์ฑํ๊ธฐ |
|||
|
|||
์ ํ๋ฆฌ์ผ์ด์
์์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ์ ์์ฑํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *} |
|||
|
|||
์ฌ๊ธฐ์๋ ์ ํ๋ฆฌ์ผ์ด์
์์ ์ด๋ฒคํธ ์ ํ
์ด๋ธ์ ์์ฑํฉ๋๋ค. |
|||
|
|||
ํ๋ก๋์
ํ๊ฒฝ์์๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ํ๊ธฐ ์ ์ ์คํ๋๋ ๋ง์ด๊ทธ๋ ์ด์
์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ๐ค |
|||
|
|||
/// tip | ํ |
|||
|
|||
SQLModel์ Alembic์ ๊ฐ์ธ๋ ๋ง์ด๊ทธ๋ ์ด์
์ ํธ๋ฆฌํฐ๋ฅผ ์ ๊ณตํ ์์ ์
๋๋ค. ํ์ง๋ง ํ์ฌ <a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a>์ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค. |
|||
|
|||
/// |
|||
|
|||
### Hero ์์ฑํ๊ธฐ |
|||
|
|||
๊ฐ SQLModel ๋ชจ๋ธ์ Pydantic ๋ชจ๋ธ์ด๊ธฐ๋ ํ๋ฏ๋ก, Pydantic ๋ชจ๋ธ์ ์ฌ์ฉํ ์ ์๋ **ํ์
์ด๋
ธํ
์ด**์
์์ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. |
|||
|
|||
์๋ฅผ ๋ค์ด, ํ๋ผ๋ฏธํฐ๋ฅผ `Hero` ํ์
์ผ๋ก ์ ์ธํ๋ฉด **JSON ๋ณธ๋ฌธ**์์ ๊ฐ์ ์ฝ์ด์ต๋๋ค. |
|||
|
|||
๋ง์ฐฌ๊ฐ์ง๋ก, ํจ์์ **๋ฐํ ํ์
**์ผ๋ก ์ ์ธํ๋ฉด ํด๋น ๋ฐ์ดํฐ์ ๊ตฌ์กฐ๊ฐ ์๋์ผ๋ก ์์ฑ๋๋ API ๋ฌธ์์ UI์ ๋ํ๋ฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} |
|||
|
|||
</details> |
|||
|
|||
์ฌ๊ธฐ์ `SessionDep` ์์กด์ฑ (์ฆ, `Session`)์ ์ฌ์ฉํ์ฌ ์๋ก์ด `Hero`๋ฅผ `Session` ์ธ์คํด์ค์ ์ถ๊ฐํ๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณ๊ฒฝ ์ฌํญ์ ์ปค๋ฐํ๊ณ , `hero` ๋ฐ์ดํฐ์ ์ต์ ์ํ๋ฅผ ๊ฐฑ์ ํ ๋ค์ ์ด๋ฅผ ๋ฐํํฉ๋๋ค. |
|||
|
|||
### Heroes ์กฐํํ๊ธฐ |
|||
|
|||
`select()`๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ `Hero`๋ฅผ **์กฐํ**ํ ์ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ํ์ด์ง๋ค์ด์
์ ์ ์ฉํ๊ธฐ ์ํด `limit`์ `offset`์ ํฌํจํ ์ ์์ต๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *} |
|||
|
|||
### ๋จ์ผ Hero ์กฐํํ๊ธฐ |
|||
|
|||
๋จ์ผ `Hero`๋ฅผ **์กฐํ**ํ ์๋ ์์ต๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *} |
|||
|
|||
### Hero ์ญ์ ํ๊ธฐ |
|||
|
|||
`Hero`๋ฅผ **์ญ์ **ํ๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *} |
|||
|
|||
### ์ ํ๋ฆฌ์ผ์ด์
์คํํ๊ธฐ |
|||
|
|||
์ ํ๋ฆฌ์ผ์ด์
์ ์คํํ๋ ค๋ฉด ๋ค์ ๋ช
๋ น์ ์ฌ์ฉํฉ๋๋ค: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ fastapi dev main.py |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
๊ทธ๋ฐ ๋ค์ `/docs` UI๋ก ์ด๋ํ๋ฉด, **FastAPI**๊ฐ ํด๋น **model๋ค**์ ์ฌ์ฉํ์ฌ API **๋ฌธ์๋ฅผ ์์ฑ**ํ๋ ๊ฒ์ผ๋ฅด ํ์ธํ ์ ์์ต๋๋ค. ๋ํ ์ด ๋ชจ๋ธ๋ค์ ๋ฐ์ดํฐ๋ฅผ ์ง๋ ฌํํ๊ณ ๊ฒ์ฆํ๋ ๋ฐ์๋ ์ฌ์ฉ๋ฉ๋๋ค. |
|||
|
|||
<div class="screenshot"> |
|||
<img src="/img/tutorial/sql-databases/image01.png"> |
|||
</div> |
|||
|
|||
## ์ฌ๋ฌ ๋ชจ๋ธ๋ก ์ ํ๋ฆฌ์ผ์ด์
์
๋ฐ์ดํธ |
|||
|
|||
์ด์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฝ๊ฐ **๋ฆฌํฉํ ๋ง**ํ์ฌ **๋ณด์**๊ณผ **์ ์ฐ์ฑ**์ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. |
|||
|
|||
์ด์ ์ ํ๋ฆฌ์ผ์ด์
์ UI๋ฅผ ๋ณด๋ฉด, ์ง๊ธ๊น์ง๋ ํด๋ผ์ด์ธํธ๊ฐ ์์ฑํ `Hero`์ `id`๋ฅผ ์ง์ ์ง์ ํ ์ ์๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๐ฑ |
|||
|
|||
์ด๋ ํ์ฉ๋์ด์ ์ ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฏธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ `id`๋ฅผ ๋ฎ์ด์ธ ์ํ์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค. `id`๋ **๋ฐฑ์๋** ๋๋ **๋ฐ์ดํฐ๋ฒ ์ด์ค**๊ฐ ๊ฒฐ์ ํด์ผ ํ๋ฉฐ, **ํด๋ผ์ด์ธํธ**๊ฐ ๊ฒฐ์ ํด์๋ ์ ๋ฉ๋๋ค. |
|||
|
|||
๋ํ hero์ `secret_name`์ ์์ฑํ๊ธด ํ์ง๋ง, ์ง๊ธ๊น์ง๋ ์ด ๊ฐ์ ์ด๋์์๋ ๋ฐํํ๊ณ ์์ต๋๋ค. ์ด๋ ๊ทธ๋ค์ง **๋น๋ฐ์ค๋ฝ์ง** ์์ต๋๋ค... ๐
|
|||
|
|||
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ช ๊ฐ์ง **์ถ๊ฐ ๋ชจ๋ธ**์ ์ถ๊ฐํ ๊ฒ์
๋๋ค. ๋ฐ๋ก ์ฌ๊ธฐ์ SQLModel์ด ๋น์ ๋ฐํ๊ฒ ๋ฉ๋๋ค. โจ |
|||
|
|||
### ์ฌ๋ฌ ๋ชจ๋ธ ์์ฑํ๊ธฐ |
|||
|
|||
**SQLModel**์์ `table=True`๊ฐ ์ค์ ๋ ๋ชจ๋ธ ํด๋์ค๋ **ํ
์ด๋ธ ๋ชจ๋ธ**์
๋๋ค. |
|||
|
|||
`table=True`๊ฐ ์๋ ๋ชจ๋ธ ํด๋์ค๋ **๋ฐ์ดํฐ ๋ชจ๋ธ**๋ก, ์ด๋ ์ค์ ๋ก ๋ช ๊ฐ์ง ์ถ๊ฐ ๊ธฐ๋ฅ์ด ํฌํจ๋ Pydantic ๋ชจ๋ธ์ ๋ถ๊ณผํฉ๋๋ค. ๐ค |
|||
|
|||
SQLModel์ ์ฌ์ฉํ๋ฉด **์์**์ ํตํด ๋ชจ๋ ๊ฒฝ์ฐ์ ํ๋๋ฅผ **์ค๋ณต ์ ์ธํ์ง ์์๋** ๋ฉ๋๋ค. |
|||
|
|||
#### `HeroBase` - ๊ธฐ๋ณธ ํด๋์ค |
|||
|
|||
๋ชจ๋ ๋ชจ๋ธ์์ **๊ณต์ ๋๋ ํ๋**๋ฅผ ๊ฐ์ง `HeroBase` ๋ชจ๋ธ์ ์์ํด ๋ด
์๋ค: |
|||
|
|||
* `name` |
|||
* `age` |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *} |
|||
|
|||
#### `Hero` - *ํ
์ด๋ธ ๋ชจ๋ธ* |
|||
|
|||
๋ค์์ผ๋ก ์ค์ *ํ
์ด๋ธ ๋ชจ๋ธ*์ธ `Hero`๋ฅผ ์์ฑํฉ๋๋ค. ์ด ๋ชจ๋ธ์ ๋ค๋ฅธ ๋ชจ๋ธ์๋ ํญ์ ํฌํจ๋๋ ๊ฑด ์๋ **์ถ๊ฐ ํ๋**๋ฅผ ํฌํจํฉ๋๋ค: |
|||
|
|||
* `id` |
|||
* `secret_name` |
|||
|
|||
`Hero`๋ `HeroBase`๋ฅผ ์์ํ๋ฏ๋ก `HeroBase`์ ์ ์ธ๋ ํ๋๋ ํฌํจํฉ๋๋ค. ๋ฐ๋ผ์ `Hero`๋ ๋ค์ **ํ๋๋ค๋** ๊ฐ์ง๊ฒ ๋ฉ๋๋ค: |
|||
|
|||
* `id` |
|||
* `name` |
|||
* `age` |
|||
* `secret_name` |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *} |
|||
|
|||
#### `HeroPublic` - ๊ณต๊ฐ *๋ฐ์ดํฐ ๋ชจ๋ธ* |
|||
|
|||
๋ค์์ผ๋ก `HeroPublic` ๋ชจ๋ธ์ ์์ฑํฉ๋๋ค. ์ด ๋ชจ๋ธ์ API ํด๋ผ์ด์ธํธ์ **๋ฐํ**๋๋ ๋ชจ๋ธ์
๋๋ค. |
|||
|
|||
`HeroPublic`์ `HeroBase`์ ๋์ผํ ํ๋๋ฅผ ๊ฐ์ง๋ฉฐ, `secret_name`์ ํฌํจํ์ง ์์ต๋๋ค. |
|||
|
|||
๋ง์นจ๋ด ์ฐ๋ฆฌ์ heroes์ ์ ์ฒด๊ฐ ๋ณดํธ๋ฉ๋๋ค! ๐ฅท |
|||
|
|||
๋ํ `id: int`๋ฅผ ๋ค์ ์ ์ธํฉ๋๋ค. ์ด๋ฅผ ํตํด, API ํด๋ผ์ด์ธํธ์ **๊ณ์ฝ**์ ๋งบ์ด `id`๊ฐ ํญ์ ์กด์ฌํ๋ฉฐ ํญ์ `int` ํ์
์ด๋ผ๋ ๊ฒ์ ๋ณด์ฅํฉ๋๋ค(`None`์ด ๋ ์ ์์ต๋๋ค). |
|||
|
|||
/// tip | ํ |
|||
|
|||
๋ฐํ ๋ชจ๋ธ์ด ๊ฐ์ด ํญ์ ์กด์ฌํ๊ณ ํญ์ `int`(`None`์ด ์๋)๋ฅผ ๋ณด์ฅํ๋ ๊ฒ์ API ํด๋ผ์ด์ธํธ์๊ฒ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ์ด๋ฅผ ํตํด API์ ํต์ ํ๋ ๊ฐ๋ฐ์๊ฐ ํจ์ฌ ๋ ๊ฐ๋จํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. |
|||
|
|||
๋ํ **์๋์ผ๋ก ์์ฑ๋ ํด๋ผ์ด์ธํธ**๋ ๋ ๋จ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ฏ๋ก, API์ ์ํตํ๋ ๊ฐ๋ฐ์๋ค์ด ํจ์ฌ ์์ํ๊ฒ ์์
ํ ์ ์์ต๋๋ค. ๐ |
|||
|
|||
/// |
|||
|
|||
`HeroPublic`์ ๋ชจ๋ ํ๋๋ `HeroBase`์ ๋์ผํ๋ฉฐ, `id`๋ `int`๋ก ์ ์ธ๋ฉ๋๋ค(`None`์ด ์๋): |
|||
|
|||
* `id` |
|||
* `name` |
|||
* `age` |
|||
* `secret_name` |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *} |
|||
|
|||
#### `HeroCreate` - hero ์์ฑ์ฉ *๋ฐ์ดํฐ ๋ชจ๋ธ* |
|||
|
|||
์ด์ `HeroCreate` ๋ชจ๋ธ์ ์์ฑํฉ๋๋ค. ์ด ๋ชจ๋ธ์ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ **๊ฒ์ฆ**ํ๋ ์ญํ ์ ํฉ๋๋ค. |
|||
|
|||
`HeroCreate`๋ `HeroBase์` ๋์ผํ ํ๋๋ฅผ ๊ฐ์ง๋ฉฐ, ์ถ๊ฐ๋ก `secret_name์` ํฌํจํฉ๋๋ค. |
|||
|
|||
ํด๋ผ์ด์ธํธ๊ฐ **์ hero์ ์์ฑ**ํ ๋ `secret_name`์ ๋ณด๋ด๊ณ , ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋์ง๋ง, ํด๋น ๋น๋ฐ ์ด๋ฆ์ API๋ฅผ ํตํด ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐํ๋์ง ์์ต๋๋ค. |
|||
|
|||
/// tip | ํ |
|||
|
|||
์ด ๋ฐฉ์์ **๋น๋ฐ๋ฒํธ**๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ๊ณผ ๋์ผํฉ๋๋ค. ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ์ง๋ง, ์ด๋ฅผ API์์ ๋ฐํํ์ง๋ ์์ต๋๋ค. |
|||
|
|||
๋น๋ฐ๋ฒํธ ๊ฐ์ ์ ์ฅํ๊ธฐ ์ ์ **ํด์ฑ**ํ์ฌ ์ ์ฅํ๊ณ , **ํ๋ฌธ์ผ๋ก ์ ์ฅํ์ง ๋ง์ญ์์ค**. |
|||
|
|||
/// |
|||
|
|||
`HeroCreate`์ ํ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค: |
|||
|
|||
* `name` |
|||
* `age` |
|||
* `secret_name` |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *} |
|||
|
|||
#### `HeroUpdate` - hero ์์ ์ฉ *๋ฐ์ดํฐ ๋ชจ๋ธ* |
|||
|
|||
์ด์ ์ ํ๋ฆฌ์ผ์ด์
์์๋ **hero๋ฅผ ์์ **ํ ๋ฐฉ๋ฒ์ด ์์์ง๋ง, ์ด์ **๋ค์ค ๋ชจ๋ธ**์ ํตํด ์์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ๐ |
|||
|
|||
`HeroUpdate` *๋ฐ์ดํฐ ๋ชจ๋ธ*์ ์ฝ๊ฐ ํน๋ณํ๋ฐ, ์ hero์ ์์ฑํ ๋ ํ์ํ **๋ชจ๋ ๋์ผํ ํ๋**๋ฅผ ๊ฐ์ง์ง๋ง, ๋ชจ๋ ํ๋๊ฐ **์ ํ์ **(๊ธฐ๋ณธ๊ฐ์ด ์์)์
๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด hero์ ์์ ํ ๋ ์์ ํ๋ ค๋ ํ๋๋ง ๋ณด๋ผ ์ ์์ต๋๋ค. |
|||
|
|||
๋ชจ๋ **ํ๋๊ฐ ๋ณ๊ฒฝ๋๊ธฐ** ๋๋ฌธ์(ํ์
์ด `None`์ ํฌํจํ๊ณ , ๊ธฐ๋ณธ๊ฐ์ด `None`์ผ๋ก ์ค์ ๋จ), ๋ชจ๋ ํ๋๋ฅผ **๋ค์ ์ ์ธ**ํด์ผ ํฉ๋๋ค. |
|||
|
|||
์๋ฐํ ๋งํ๋ฉด `HeroBase`๋ฅผ ์์ํ ํ์๋ ์์ต๋๋ค. ๋ชจ๋ ํ๋๋ฅผ ๋ค์ ์ ์ธํ๊ธฐ ๋๋ฌธ์
๋๋ค. ์ผ๊ด์ฑ์ ์ํด ์์์ ์ ์งํ๊ธด ํ์ง๋ง, ํ์๋ ์๋๋๋ค. ์ด๋ ๊ฐ์ธ์ ์ธ ์ทจํฅ์ ๋ฌธ์ ์
๋๋ค. ๐คท |
|||
|
|||
`HeroUpdate`์ ํ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค: |
|||
|
|||
* `name` |
|||
* `age` |
|||
* `secret_name` |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *} |
|||
|
|||
### `HeroCreate`๋ก ์์ฑํ๊ณ `HeroPublic` ๋ฐํํ๊ธฐ |
|||
|
|||
์ด์ **๋ค์ค ๋ชจ๋ธ**์ ์ฌ์ฉํ๋ฏ๋ก ์ ํ๋ฆฌ์ผ์ด์
์ ๊ด๋ จ ๋ถ๋ถ์ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค. |
|||
|
|||
์์ฒญ์์ `HeroCreate` *๋ฐ์ดํฐ ๋ชจ๋ธ*์ ๋ฐ์ ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก `Hero` *ํ
์ด๋ธ ๋ชจ๋ธ*์ ์์ฑํฉ๋๋ค. |
|||
|
|||
์ด ์ *ํ
์ด๋ธ ๋ชจ๋ธ* `Hero`๋ ํด๋ผ์ด์ธํธ์์ ๋ณด๋ธ ํ๋๋ฅผ ๊ฐ์ง๋ฉฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์์ฑ๋ `id`๋ ํฌํจํฉ๋๋ค. |
|||
|
|||
๊ทธ๋ฐ ๋ค์ ํจ์๋ฅผ ํตํด ๋์ผํ *ํ
์ด๋ธ ๋ชจ๋ธ* `Hero`๋ฅผ ๋ฐํํฉ๋๋ค. ํ์ง๋ง `response_model`๋ก `HeroPublic` *๋ฐ์ดํฐ ๋ชจ๋ธ*์ ์ ์ธํ๊ธฐ ๋๋ฌธ์, **FastAPI**๋ `HeroPublic`์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ฆํ๊ณ ์ง๋ ฌํํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *} |
|||
|
|||
/// tip | ํ |
|||
|
|||
์ด์ **๋ฐํ ํ์
์ฃผ์** `-> HeroPublic` ๋์ `response_model=HeroPublic`์ ์ฌ์ฉํฉ๋๋ค. ๋ฐํํ๋ ๊ฐ์ด ์ค์ ๋ก `HeroPublic`์ด *์๋๊ธฐ* ๋๋ฌธ์
๋๋ค. |
|||
|
|||
๋ง์ฝ `-> HeroPublic`์ผ๋ก ์ ์ธํ๋ค๋ฉด, ์๋ํฐ์ ๋ฆฐํฐ์์ ๋ฐํ๊ฐ์ด `HeroPublic`์ด ์๋๋ผ `Hero`๋ผ๊ณ ๊ฒฝ๊ณ ํ์ ๊ฒ์
๋๋ค. ์ด๋ ์ ์ ํ ๊ฒฝ๊ณ ์
๋๋ค. |
|||
|
|||
`response_model`์ ์ ์ธํจ์ผ๋ก์จ **FastAPI**๊ฐ ์ด๋ฅผ ์ฒ๋ฆฌํ๋๋ก ํ๊ณ , ํ์
์ด๋
ธํ
์ด์
๊ณผ ์๋ํฐ ๋ฐ ๋ค๋ฅธ ๋๊ตฌ์ ๋์์๋ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ์ค์ ํฉ๋๋ค. |
|||
|
|||
/// |
|||
|
|||
### `HeroPublic`์ผ๋ก Heroes ์กฐํํ๊ธฐ |
|||
|
|||
์ด์ ๊ณผ ๋์ผํ๊ฒ `Hero`๋ฅผ **์กฐํ**ํ ์ ์์ต๋๋ค. ์ด๋ฒ์๋ `response_model=list[HeroPublic]`์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ฒ์ฆ๋๊ณ ์ง๋ ฌํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *} |
|||
|
|||
### `HeroPublic`์ผ๋ก ๋จ์ผ Hero ์กฐํํ๊ธฐ |
|||
|
|||
๋จ์ผ hero์ **์กฐํ**ํ ์๋ ์์ต๋๋ค: |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *} |
|||
|
|||
### `HeroUpdate`๋ก Hero ์์ ํ๊ธฐ |
|||
|
|||
**hero๋ฅผ ์์ **ํ ์๋ ์์ต๋๋ค. ์ด๋ฅผ ์ํด HTTP `PATCH` ์์
์ ์ฌ์ฉํฉ๋๋ค. |
|||
|
|||
์ฝ๋์์๋ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ๋ฐ์ดํฐ๋ฅผ ๋์
๋๋ฆฌ ํํ(`dict`)๋ก ๊ฐ์ ธ์ต๋๋ค. ์ด๋ **ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ๋ฐ์ดํฐ๋ง ํฌํจ**ํ๋ฉฐ, ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋ค์ด๊ฐ๋ ๊ฐ์ ์ ์ธํฉ๋๋ค. ์ด๋ฅผ ์ํด `exclude_unset=True`๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๊ฒ์ด ์ฃผ์ ํต์ฌ์
๋๋ค. ๐ช |
|||
|
|||
๊ทธ๋ฐ ๋ค์, `hero_db.sqlmodel_update(hero_data)`๋ฅผ ์ฌ์ฉํ์ฌ `hero_data`์ ๋ฐ์ดํฐ๋ฅผ `hero_db`์ ์
๋ฐ์ดํธํฉ๋๋ค. |
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *} |
|||
|
|||
### Hero ๋ค์ ์ญ์ ํ๊ธฐ |
|||
|
|||
hero **์ญ์ **๋ ์ด์ ๊ณผ ๊ฑฐ์ ๋์ผํฉ๋๋ค. |
|||
|
|||
์ด๋ฒ์๋ ๋ชจ๋ ๊ฒ์ ๋ฆฌํฉํ ๋งํ๊ณ ์ถ์ ์๊ตฌ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ ๊ฒ ๊ฐ์ต๋๋ค. ๐
|
|||
|
|||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} |
|||
|
|||
### ์ ํ๋ฆฌ์ผ์ด์
๋ค์ ์คํํ๊ธฐ |
|||
|
|||
๋ค์ ๋ช
๋ น์ ์ฌ์ฉํด ์ ํ๋ฆฌ์ผ์ด์
์ ๋ค์ ์คํํ ์ ์์ต๋๋ค: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ fastapi dev main.py |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
`/docs` API UI๋ก ์ด๋ํ๋ฉด ์
๋ฐ์ดํธ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์์
์ ์์ฑํ ๋ `id`๋ฅผ ์ ๊ณตํ ํ์๊ฐ ์๊ฒ ๋๋ ๋ฑ์ ๋ณํ๋ ๋ณด์
๋๋ค. |
|||
|
|||
<div class="screenshot"> |
|||
<img src="/img/tutorial/sql-databases/image02.png"> |
|||
</div> |
|||
|
|||
## ์์ฝ |
|||
|
|||
<a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a>์ ์ฌ์ฉํ์ฌ SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉํ๊ณ , *๋ฐ์ดํฐ ๋ชจ๋ธ* ๋ฐ *ํ
์ด๋ธ ๋ชจ๋ธ*๋ก ์ฝ๋๋ฅผ ๊ฐ์ํํ ์ ์์ต๋๋ค. |
|||
|
|||
๋ ๋ง์ ๋ด์ฉ์ ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด, **SQLModel** ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ธ์. <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">SQLModel์ **FastAPI**์ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒ์ ๋ํ ๋ ๊ธด ๋ฏธ๋ ํํ ๋ฆฌ์ผ</a>๋ ์ ๊ณตํฉ๋๋ค. ๐ |
Loadingโฆ
Reference in new issue