Fast API, Syntactic sugar / 꿀팁

Junha Kim·2021년 1월 23일
0

FastAPI

목록 보기
15/16

Reduce Duplication

이전의 내용에서 유저에 관한 모델을 생각해보자.

  • input model은 password가 있어야하고,
  • output model은 password를 내보내지 말아야하고,
  • database model은 hashed password가 필요하다.

이를 단순히 작성하면 아래와 같을 것이다.

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 모델을 만들어 놓고 각각의 클래스에 상속하여 사용하는 것을 볼 수 있다.

Unwrapping pydantic model

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)

Union

모델의 형식을 선언하거나 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_modelPlanetItem 이나 CarItem 형식의 데이터를 내보내겠다고 선언한 것이다.

이렇게 되면 read_item이 return한 데이터가 PlanetItem이나 CarItem 둘 중 하나의 형식과 맞으면 되는 것이다.

0개의 댓글