이전의 내용에서 유저에 관한 모델을 생각해보자.
이를 단순히 작성하면 아래와 같을 것이다.
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Optional[str] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Optional[str] = None
class UserInDB(BaseModel):
username: str
hashed_password: str
email: EmailStr
full_name: Optional[str] = None
딱 봐도 중복된 내용이 너무나도 많다.
상속을 이용하여 깔끔하게 정리하면 아래와 같다.
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: Optional[str] = None
class UserIn(UserBase):
password: str
class UserOut(UserBase):
pass
class UserInDB(UserBase):
hashed_password: str
UserBase
라는 추상 pydantic 모델을 만들어 놓고 각각의 클래스에 상속하여 사용하는 것을 볼 수 있다.
pydantic 모델 객체를 파이썬 딕셔너리로 바꿀 수 있다.
만약
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
와 같이 정의가 되어 있다면,
user_dict = user_in.dict()
와 같이 딕셔너리로 바꿀 수 있다.
{
'username': 'john',
'password': 'secret',
'email': 'john.doe@example.com',
'full_name': None,
}
만약 이러한 값들을 pydantic 모델에 집어넣고 싶다면 어떻게 해야할까? 원래였다면, 위에서 본 것과 같이 keyword로 직접 넣어주어야 했다.
하지만 아래와 같이 작성하면 그러한 귀찮음이 없어진다.
UserInDB(**user_dict)
"""
UserInDB(
username="john",
password="secret",
email="john.doe@example.com",
full_name=None,
)
"""
위의 코드는 딕셔너리를 key/value 쌍으로 직접 넘겨주는 효과를 보이며, 바로 아래의 코드와 똑같이 작동한다.
추가적인 keyword argument도 넣을 수 있다.
UserInDB(**user_in.dict(), hashed_password=hashed_password)
모델의 형식을 선언하거나 response model의 output 값으로 여러 개의 형식을 내보내고 싶을 경우가 있다.
이를 가능하게 하는 것이 바로 Union
이다.
from typing import Union
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type = "car"
class PlaneItem(BaseItem):
type = "plane"
size: int
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
return items[item_id]
Union
으로 묶어 response_model
로 PlanetItem
이나 CarItem
형식의 데이터를 내보내겠다고 선언한 것이다.
이렇게 되면 read_item
이 return한 데이터가 PlanetItem
이나 CarItem
둘 중 하나의 형식과 맞으면 되는 것이다.