본문 바로가기
Fast API/fastapi배우기

Fast API 배우기 18부 - jsonable_encoder, PUT, PATCH

by 붕어사랑 티스토리 2021. 11. 3.
반응형

jsonable_encoder

 

데이터 자료형을 json compatiable한 데이터로 바꿔주는 함수이다.

다른 파이썬 라이브러리를 사용할때 json 호환 데이터를 요구할 경우가 있다면 이 함수를 이용하자

가령 예를들면 데이터베이스는 Pydantic model을 받지 않고 dict만 받는 경우가 있다.

또는 datetime을 데이터베이스로 넘겨줄때 str로 바꿔주어야 한다.

이럴때 jsonable_encoder를 사용한다.

 

아래는 그 예제이다.

from datetime import datetime
from typing import Optional

from fastapi import FastAPI

from fastapi.encoders import jsonable_encoder

from pydantic import BaseModel

fake_db = {}


class Item(BaseModel):
    title: str
    timestamp: datetime
    description: Optional[str] = None


app = FastAPI()


@app.put("/items/{id}")
def update_item(id: str, item: Item):

    json_compatible_item_data = jsonable_encoder(item)

    fake_db[id] = json_compatible_item_data

 

 

PUT operation

put은 데이터를 업데이트할 때 쓰이는 operation이다. PUT대신에 PATCH도 사용 가능하다.

from typing import List, Optional

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
    update_item_encoded = jsonable_encoder(item)
    items[item_id] = update_item_encoded
    return update_item_encoded
반응형

 

exclude_unset

위 예제에서 주의해야 할 점이 있다.

아래와 같은 데이터를 보냈다고 하자.

{
    "name": "Barz",
    "price": 3,
    "description": None,
}

나는 위 데이터만 업데이트 하고싶다고 치자.

허나 Pydantic model에 초기값이 tax로 10.5가 들어가있다.

 

고로 위 방식대로 업데이트 해버리면 tax: 20.2 값이 10.5로 바뀌어버린다.

 

이 문제를 해결하는 방법은 이전에 배웠다.

 

Pydantic's model의 dict()함수에서 exclude_unset을 이용하면 된다.

 

dict자료형을 만들어 주면서 unset된 데이터들을 제외해준다.

 

 

from typing import List, Optional

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.patch("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
    stored_item_data = items[item_id]
    stored_item_model = Item(**stored_item_data)

    update_data = item.dict(exclude_unset=True)

    updated_item = stored_item_model.copy(update=update_data)
    items[item_id] = jsonable_encoder(updated_item)
    return updated_item

 

stored_item_data = items[item_id]
stored_item_model = Item(**stored_item_data)
update_data = item.dict(exclude_unset=True)
updated_item = stored_item_model.copy(update=update_data)
items[item_id] = jsonable_encoder(updated_item)

위 코드에서 데이터를 업데이트 해줄 때 copy() 함수에서 update 파라미터를 이용한것을 주목하자.

 

 

즉 정리하자면 데이터 업데이트는 다음과 같이 이루어진다.

 

  1. PATCH나 PUT operation을 이용한다
  2. 저장된 데이터를 가져온다
  3. 저장된 데이터를 Pydantic Model로 바꾸어준다
  4. request data를 dict()로 바꾼다. 바꿀때 exclude_unset을 해줌을 기억하자
  5. 저장된 데이터에서 copy() 메소드를 이용하여 업데이트된 아이템을 얻는다
  6. 업데이트된 아이템을 jsonable_encoder를 이용하여 json compatiable 데이터로 변환한다
  7. db에 변환된 아이템을 저장한다.
  8. db를 업데이트한다

 

반응형

댓글