Лучший способ обновить объекты со свойствами, допускающими обнуление, с помощью fastapi

#python #fastapi

Вопрос:

Я создаю простой REST API. Если объект, который вы хотите обновить, содержит свойства, которые могут содержать значение null, как лучше всего определить его в fastapi?

При использовании pydantic.BaseModel невозможно поддерживать использование не обновлять, если свойство не существует.

пример:

 from fastapi import Body, FastAPI
from typing import Optional, Literal
import dataclasses

app = FastAPI()

@dataclasses.dataclass
class User:
    name: str
    type: Optional[Literal['admin', 'guest']]

user = User('test_user', 'admin')

class UpdateUser(BaseModel):
    name: str
    type: Optional[Literal['admin', 'guest']]

@app.put('/')
def put(update_user: UpdateUser):
    # In the case of BaseModel, I don't know the difference between the property 
    # that I don't update and the property that I want to update with None,
    # so I always update with None.
    user.name = update_user.name
    user.type = update_user.type
 

Я думаю, что самый простой способ-это использовать dict .

пример:

 from fastapi import Body, FastAPI
from typing import Optional, Literal
import dataclasses

app = FastAPI()

@dataclasses.dataclass
class User:
    id: int
    name: str
    type: Optional[Literal['admin', 'guest']]

user = User(1, 'test_user', 'admin')

@app.put('/')
def put(body = Body(...)):
    if 'name' in body:
        user.name = body.name
    if 'type' in body:
        user.type = body.type
 

Однако в этом случае невозможно указать тип JSON, используемый для запроса, например BaseModel.

Как я могу реализовать процесс обновления с гибкостью, подобной диктанту, сохраняя при этом информацию о типе?

Ответ №1:

Оказывается, это типичный запрос на исправление. Во время обновления пользователь UpdateUser может получить его и update_user.dict(exclude_unset=True) может получить словарь, содержащий только те части, которые необходимо обновить.

пример:

 from fastapi import Body, FastAPI
from typing import Optional, Literal
import dataclasses

app = FastAPI()

@dataclasses.dataclass
class User:
    name: str
    type: Optional[Literal['admin', 'guest']]

user = User('test_user', 'admin')

class UpdateUser(BaseModel):
    name: str
    type: Optional[Literal['admin', 'guest']]

@app.patch('/')
def patch(update_user: UpdateUser):
    update_user_dict = update_user.dict(exclude_unset=True)

    if 'name' in update_user_dict:
        user.name = update_user.name
    if 'type' in update_user_dict:
        user.type = update_user.type
 

https://fastapi.tiangolo.com/tutorial/body-updates/#using-pydantics-exclude_unset-parameter