์ถ๊ฐ ๋ชจ๋ธ¶
์ด์ ์ ์์ ์ ์ด์ด์, ์ผ๋ฐ์ ์ผ๋ก๋ ํ ๊ฐ์ง ์ด์์ ๊ด๊ณ ๋ชจ๋ธ์ ๊ฐ์ง ๊ฒ์ ๋๋ค.
์ฌ์ฉ์ ๋ชจ๋ธ์ ๊ฒฝ์ฐ๊ฐ ํนํ ๊ทธ๋ ์ต๋๋ค. ์๋ํ๋ฉด:
- ์ ๋ ฅ ๋ชจ๋ธ์ ๋น๋ฐ๋ฒํธ๋ฅผ ๊ฐ์ง ์ ์์ด์ผ ํฉ๋๋ค.
- ์ถ๋ ฅ ๋ชจ๋ธ์ ๋น๋ฐ๋ฒํธ๊ฐ ์์ด์ผ ํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ์ ํด์ ๋ ๋น๋ฐ๋ฒํธ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
์ํ
์ฌ์ฉ์์ ํ๋ฌธ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ์ ์ฅํ์ง ๋ง์ญ์์ค. ํญ์ ๊ฒ์ฆํ ์ ์๋ "์์ ํ ํด์"๋ก ์ ์ฅํ์ญ์์ค.
๋ง์ฝ ๋น์ ์ด ๋ชจ๋ฅธ๋ค๋ฉด ๋ณด์ ์ฑํฐ์์ "๋น๋ฐ๋ฒํธ ํด์"๊ฐ ๋ฌด์์ธ์ง ๋ฐฐ์ธ ์ ์์ต๋๋ค.
๋ณตํฉ ๋ชจ๋ธ๋ค¶
๋ชจ๋ธ๋ค์ด ๋น๋ฐ๋ฒํธ ํ๋์ ๊ทธ๊ฒ์ด ์ฌ์ฉ๋๋ ์์น์์ ์ด๋ป๊ฒ ๋ณด์ผ ์ ์๋์ง์ ๋ํ ์ผ๋ฐ์ ์ธ ์์ด๋์ด๋ฅผ ์๊ฐํฉ๋๋ค.
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Union[str, None] = None
class UserInDB(BaseModel):
username: str
hashed_password: str
email: EmailStr
full_name: Union[str, None] = None
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
**user_in.dict()
์ ๊ดํด¶
Pydantic์์์ .dict()
¶
user_in
์ UserIn
ํด๋์ค์ Pydantic ๋ชจ๋ธ์
๋๋ค.
Pydantic ๋ชจ๋ธ์ ๋ชจ๋ธ ๋ฐ์ดํฐ์ dict
๋ฅผ ๋ฐํํ๋ .dict()
๋ฉ์๋๊ฐ ์์ต๋๋ค.
๊ทธ๋์, ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ Pydantic ๊ฐ์ฒด์ธ user_in
์ ์์ฑํด๋ณด๋ฉด:
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ ์ด๋ ๊ฒ ํธ์ถํฉ๋๋ค:
user_dict = user_in.dict()
์ฐ๋ฆฌ๋ user_dict
(Pydantic ๋ชจ๋ธ ๊ฐ์ฒด ๋์ dict
์
๋๋ค) ๋ณ์ ๋ด๋ถ์ ์๋ ๋ฐ์ดํฐ๋ฅผ dict
๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ ์ด๋ ๊ฒ ํธ์ถํ๋ค๋ฉด:
print(user_dict)
์ฐ๋ฆฌ๋ ํ์ด์ฌ dict
๋ฅผ ์ป์ ์ ์์ต๋๋ค:
{
'username': 'john',
'password': 'secret',
'email': 'john.doe@example.com',
'full_name': None,
}
dict
๋ฅผ ํ๊ธฐ¶
์ฐ๋ฆฌ๊ฐ user_dict
๊ฐ์ dict
๋ฅผ ์ป์ด์ค๊ฑฐ๋ **user_dict
์ ํํ๋ก ํจ์๋ ํด๋์ค๋ก ์ ๋ฌํ ๋, ํ์ด์ฌ์ ์ด๊ฒ์ "ํ๊ธฐ(unwrap)"๋ฅผ ํฉ๋๋ค. ์ด๊ฒ์ user_dict
์ ํค์ ๊ฐ์ ํค-๊ฐ ์ธ์(arguments)๋ก ์ง์ ์ ์ผ๋ก ๋๊น๋๋ค.
๊ทธ๋์, ์์์ ์ค๋ช
ํ๋ user_dict
๋ก ๊ณ์ ์งํํ๊ฒ ์ต๋๋ค:
UserInDB(**user_dict)
์๋์ ๋๋ฑํ ๊ฒฐ๊ณผ๋ฅผ ์ค ๊ฒ์ ๋๋ค.
UserInDB(
username="john",
password="secret",
email="john.doe@example.com",
full_name=None,
)
๋๋ ๋ ์ ํํ๊ฒ๋ ๋์ค์ ์ด๋ค๋ด์ฉ์ ๋ด๊ฒ ๋๋๋ผ๋ user_dict
๋ฅผ ์ง์ ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค:
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
)
๋ ๋ค๋ฅธ ๋ด์ฉ์ผ๋ก๋ถํฐ Pydantic ๋ชจ๋ธ¶
์์ ์์ ์์๋ user_in.dict()
์์ user_dict
๋ฅผ ์ป์ ์ ์์์ต๋๋ค. ์ด ์ฝ๋์
๋๋ค:
user_dict = user_in.dict()
UserInDB(**user_dict)
์ด๊ฒ๊ณผ ๋๋ฑํ ๊ฒ์ ๋๋ค:
UserInDB(**user_in.dict())
... ์๋ํ๋ฉด user_in.dict()
๋ dict
์ด๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ UserInDB
์์ **
๋ฅผ ๋ถ์ฌ์ ์ ๋ฌํจ์ผ๋ก์จ Python์ด "ํ๊ธฐ"๋ฅผ ํ๋๋ก ํ ์ ์์ต๋๋ค.
๊ทธ๋์, ์ฐ๋ฆฌ๋ ๋๋ค๋ฅธ Pydantic ๋ชจ๋ธ์ ์๋ ๋ฐ์ดํฐ์์ Pydantic ๋ชจ๋ธ์ ์ป์ ์ ์์ต๋๋ค.
dict
๋ฅผ ํ๊ธฐ ๊ทธ๋ฆฌ๊ณ ์ถ๊ฐ ํค์๋๋ค¶
๊ทธ๋ฆฌ๊ณ ์ถ๊ฐ ํค์๋ ์์ฑ์ธ hashed_password=hashed_password
์ ์ถ๊ฐํ๊ฒ ์ต๋๋ค. ์๋์ ๊ฐ์ต๋๋ค:
UserInDB(**user_in.dict(), hashed_password=hashed_password)
... ๊ฒฐ๊ตญ์๋ ์ด๋ ๊ฒ ๋ ๊ฒ์ ๋๋ค:
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
hashed_password = hashed_password,
)
๊ฒฝ๊ณ
์ถ๊ฐ์ ์ธ ํจ์ ์ง์์ ๊ฐ๋ฅํ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ณด์ฌ์ฃผ๋ ๋ฐ๋ชจ์ผ ๋ฟ์ด๋ฉฐ, ๋น์ฐํ ๊ทธ ์ด๋ค ์ค์ ๋ณด์๋ ์ ๊ณตํ์ง ์์ต๋๋ค.
์ค๋ณต ์ค์ด๊ธฐ¶
์ค๋ณต ์ฝ๋ ์ค์ด๊ธฐ๋ FASTAPI์ ํต์ฌ ๊ฐ๋ ์ค ํ๋์ ๋๋ค.
์ฝ๋ ์ค๋ณต์ ๋ฒ๊ทธ์ ๊ฐ๋ฅ์ฑ, ๋ณด์ ์ด์, ์ฝ๋ ๋น๋๊ธฐํ ๋ฌธ์ (ํ ์ฅ์์๋ ์ ๋ฐ์ดํธ ํ์ง๋ง ๋ค๋ฅธ ๊ณณ์์๋ ๊ทธ๋ ์ง ๋ชปํ ๋) ๋ฑ์ ์ฆ๊ฐ์ํต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๋ชจ๋ธ๋ค์ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๊ณ ํ์ ๊ณผ ์ธ์ ์ด๋ฆ๋ค์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
๋ ์ํ ์ ์์ต๋๋ค.
๋ค๋ฅธ ๋ชจ๋ธ๋ค์ ๊ธฐ์ด๊ฐ ๋๋ UserBase
๋ชจ๋ธ์ ์ ์ธํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ ์ด ์ธ์๋ค(ํ์
์ ์ธ, ๊ฒ์ฆ ๋ฑ)์ ์์๋ฐ์ ๋ชจ๋ธ์ธ ์๋ธํด๋์ค๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
๋ชจ๋ ๋ฐ์ดํฐ์ ๋ณํ, ๊ฒ์ฆ, ๋ฌธ์ํ ๋ฑ์ ์ฌ์ ํ ์ ์์ ์ผ๋ก ๋์ํ ๊ฒ์ ๋๋ค.
์ด๋ฌํ ๋ฐฉ๋ฒ์ผ๋ก ์ฐ๋ฆฌ๋ ๋ชจ๋ธ๋ค ์ฌ์ด์ ์ฐจ์ด๋ง์ ์ ์ธํ ์ ์์ต๋๋ค.(ํ๋ฌธ password
์ ํจ๊ป, hashed_password
์ ํจ๊ป, ๋น๋ฐ๋ฒํธ๋ ์์ด)
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: Union[str, None] = None
class UserIn(UserBase):
password: str
class UserOut(UserBase):
pass
class UserInDB(UserBase):
hashed_password: str
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
Union
๋๋ anyOf
¶
Union
์ ํตํด ๋ ๊ฐ์ง ํ์
์ ์๋ต์ ์ ์ธํ ์ ์์ต๋๋ค. ๊ทธ ๋ง์, ์๋ต์ ๊ทธ ๋ ๊ฐ์ง ์ค ์๋ฌด๊ฑฐ๋ ๋ ์ ์๋ค๋ ์๋ฏธ์
๋๋ค.
์ด๋ OpenAPI์์ anyOf
๋ก ์ ์ํ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ํ๊ธฐ ์ํด์๋ ํ์ค ํ์ด์ฌ ํ์
ํํธ typing.Union
๋ฅผ ์ฌ์ฉํ์ญ์์ค:
์ฐธ๊ณ
Union
์ ์ ์ธํ ๋, ๊ฐ์ฅ ํน์ ํ ํ์
์ ์ฒซ ๋ฒ์งธ๋ก ํฌํจํ๊ณ , ๋ ํน์ ํ ํ์
์ ๋ค์ ๋ถ์ด์ญ์์ค. ์๋ฅผ ๋ค์ด, Union[PlaneItem, CarItem]
์์ ๋ ํน์ ํ PlaneItem
์ CarItem
๋ณด๋ค ๋ ์์ ์ต๋๋ค.
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type = "car"
class PlaneItem(BaseItem):
type = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
}
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
return items[item_id]
๋ชจ๋ธ๋ค์ ๋ฆฌ์คํธ¶
๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก, ๊ฐ์ฒด์ ๋ฆฌ์คํธ๋ฅผ ์๋ต์ผ๋ก ์ ์ธํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ํด์ ํ์ค ํ์ด์ฌ typing.List
๋ฅผ ์ฌ์ฉํ์ญ์์ค:
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str
items = [
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
@app.get("/items/", response_model=List[Item])
async def read_items():
return items
์์์ dict
๋ก ์๋ตํ๊ธฐ¶
Pydantic ๋ชจ๋ธ์ ์ฌ์ฉํ์ง ์๊ณ ๋จ์ํ ํค์ ๊ฐ์ ํ์
์ผ๋ก ์ ์ธํ๋ ํ๋ฒํ ์์์ dict
๋ก ์๋ต์ ์ ์ธํ ์ ์์ต๋๋ค.
๋ฏธ๋ฆฌ ์ ํจํ ํ๋์ ์์ฑ์ ์ด๋ฆ(์ด๊ฒ์ ์๋ง Pydantic ๋ชจ๋ธ์ ํ์ํ ๊ฒ์ ๋๋ค)์ ์์ง ๋ชปํ ๋ ์ ์ฉํฉ๋๋ค.
์ด ์ํฉ์์ typing.Dict
๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.:
from typing import Dict
from fastapi import FastAPI
app = FastAPI()
@app.get("/keyword-weights/", response_model=Dict[str, float])
async def read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}
์ ๋ฆฌ¶
๊ฐ๊ฐ์ ์ํฉ์์ ๋ค์์ Pydantic ๋ชจ๋ธ๋ค์ ์ฌ์ฉํ๊ณ ์์ ๋กญ๊ฒ ์์ํ์ญ์์ค.
๋ง์ฝ ๊ฐ์ฒด๊ฐ ๋ค๋ฅธ "์ํ"๋ฅผ ๊ฐ์ง ์๋ฐ์ ์๋ค๋ฉด, ๊ตณ์ด ํ๋์ ๊ฐ์ฒด๋น ํ๋์ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๊ฐ์ง ํ์๊ฐ ์์ต๋๋ค. password
, password_hash
๋ ์์ผ๋ ๋น๋ฐ๋ฒํธ๋ ์๋ ์ฌ์ฉ์ "entity" ์ํฉ์ด ๊ทธ๋ ์ต๋๋ค.