https://fastapi.tiangolo.com/tutorial/body-updates/
Body - Updates - FastAPI
Body - Updates Update replacing with PUT To update an item you can use the HTTP PUT operation. You can use the jsonable_encoder to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting datetime to s
fastapi.tiangolo.com
<FastAPI 공식문서 참조>
1. Update replacing with PUT
item을 Update하는 방법을 알아보자.
HTTP PUT 연산을 이용한다.
아래 예시는 PUT 연산을 이용한 update method 인데,
바로 이전 포스트에서 배운 jsonable_encoder를 이용해 datetime을 str로 바꾸는 과정까지 구현되어있다.
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str | None = None
description: str | None = None
price: float | None = 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
이미 존재하는 데이터를 대체하기 위해 새로운 데이터를 받는데 PUT 연산이 사용된다.
1-1. Warning about replacing
Replacing 할 때 주의해야할 점이 있다.
다음 body를 포함한 내용을 PUT하여 bar 를 update하려는 경우,
{
"name": "Barz",
"price": 3,
"description": None,
}
위 body는 bar에 이미 존재하는 속성 "tax" : 20.2 가 포함되어 있지 않기 때문에,
default value로 지정된 "tax" : 10.5 가 들어가게 된다.
tax의 20.2라는 값을 수정하려는 의도는 없었는데, 10.5로 의도치않게 수정해버릴 수도 있다.
2. Partial updates with PATCH
위와 같은 문제 상황에서!! PATCH를 사용해 부분적으로 update할 수 있다.
* PUT만 이용해도 부분적으로 수정 가능하다. 따라서 사실 PATCH는 partial update에 범용적으로 사용되는 메소드는 아니다.
2-1. Using Pydantic's exclude_unset parameter
Pydantic model의 .dict() 에서 부분 수정을 받으려면 exclude_unset 매개변수를 사용하는것은 매우 유용하다.
이렇게 사용한다. item.dict(exclude_unset=True)
기본 값을 제외하고 item model을 생성할 때 설정된 데이터만으로 dictionary가 생성됨을 의미한다.
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str | None = None
description: str | None = None
price: float | None = 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
2-2. Using Pydantic's update parameter
.copy() 를 사용해 이미 존재하는 모델의 복사본을 만들어보자.
그 후 수정할 데이터를 담은 dict와 함께 update 매개변수를 넣어주면
*[코드는 다음과 같다. stored_item_model.copy(update=update_data): ]
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str | None = None
description: str | None = None
price: float | None = 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
3. Partial updates recap
요약해서, 부분 업데이트를 하려면 :
- (선택적) PATCH를 PUT 대신에 사용한다.
- 저장된 데이터를 돌려받는다.
- Pydantic model 속의 데이터를 PUT 한다.
- input model의 default value 없이 생성한다( exclude_unset 사용)
- 이 방법은 이미 저장된 값을 overriding하는 대신 사실상 사용자가 설정한 값만 update할 수 있다.
- 저장된 모델의 복사본을 만들고, 받은 partial updates들을 가지고 속성을 update한다(using the update parameter).
- 복사된 모델을 DB에 저장할 수 있는 형태로 변환한다(jsonable_encoder를 사용)
- 데이터를 DB에 저장한다.
- 수정된 모델을 return.
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str | None = None
description: str | None = None
price: float | None = 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
아래를 집중해서 보자.
@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
4. Reference
https://fastapi.tiangolo.com/tutorial/body-updates/
Body - Updates - FastAPI
Body - Updates Update replacing with PUT To update an item you can use the HTTP PUT operation. You can use the jsonable_encoder to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting datetime to s
fastapi.tiangolo.com
'프레임워크 > FastAPI' 카테고리의 다른 글
[FastAPI] FastAPI [25] SQL (Relational) Databases (2) (0) | 2023.06.06 |
---|---|
[FastAPI] FastAPI [24] SQL (Relational) Databases (1) (0) | 2023.05.30 |
[FastAPI] FastAPI [22] JSON Compatible Encoder (0) | 2023.05.23 |
[FastAPI] FastAPI [21] Path Operation Configuration (0) | 2023.05.16 |
[FastAPI] FastAPI [20] Handling Errors (0) | 2023.05.09 |