Body - Обновления¶
🌐 Перевод выполнен с помощью ИИ и людей
Этот перевод был сделан ИИ под руководством людей. 🤝
В нем могут быть ошибки из-за неправильного понимания оригинального смысла или неестественности и т. д. 🤖
Вы можете улучшить этот перевод,помогая нам лучше направлять ИИ LLM.
Обновление с заменой при помощиPUT¶
Чтобы обновить элемент, вы можете использовать операциюHTTPPUT.
Вы можете использоватьjsonable_encoder, чтобы преобразовать входные данные в данные, которые можно сохранить как JSON (например, в NoSQL-базе данных). Например, преобразованиеdatetime вstr.
fromfastapiimportFastAPIfromfastapi.encodersimportjsonable_encoderfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:str|None=Nonedescription:str|None=Noneprice:float|None=Nonetax:float=10.5tags: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)asyncdefread_item(item_id:str):returnitems[item_id]@app.put("/items/{item_id}",response_model=Item)asyncdefupdate_item(item_id:str,item:Item):update_item_encoded=jsonable_encoder(item)items[item_id]=update_item_encodedreturnupdate_item_encodedPUT используется для получения данных, которые должны заменить существующие данные.
Предупреждение о замене¶
Это означает, что если вы хотите обновить элементbar, используяPUT с телом, содержащим:
{"name":"Barz","price":3,"description":None,}поскольку оно не включает уже сохраненный атрибут"tax": 20.2, входная модель примет значение по умолчанию"tax": 10.5.
И данные будут сохранены с этим «новым»tax, равным10.5.
Частичное обновление с помощьюPATCH¶
Также можно использовать операциюHTTPPATCH длячастичного обновления данных.
Это означает, что можно передавать только те данные, которые необходимо обновить, оставляя остальные нетронутыми.
Технические детали
PATCH менее распространен и известен, чемPUT.
А многие команды используют толькоPUT, даже для частичного обновления.
Вы можетесвободно использовать их как угодно,FastAPI не накладывает никаких ограничений.
Но в данном руководстве более или менее понятно, как они должны использоваться.
Использование параметраexclude_unset в Pydantic¶
Если вы хотите получать частичные обновления, очень полезно использовать параметрexclude_unset в.model_dump() модели Pydantic.
Например,item.model_dump(exclude_unset=True).
В результате будет сгенерированdict, содержащий только те данные, которые были заданы при создании моделиitem, без учета значений по умолчанию.
Затем вы можете использовать это для созданияdict только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
fromfastapiimportFastAPIfromfastapi.encodersimportjsonable_encoderfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:str|None=Nonedescription:str|None=Noneprice:float|None=Nonetax:float=10.5tags: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)asyncdefread_item(item_id:str):returnitems[item_id]@app.patch("/items/{item_id}")asyncdefupdate_item(item_id:str,item:Item)->Item:stored_item_data=items[item_id]stored_item_model=Item(**stored_item_data)update_data=item.model_dump(exclude_unset=True)updated_item=stored_item_model.model_copy(update=update_data)items[item_id]=jsonable_encoder(updated_item)returnupdated_itemИспользование параметраupdate в Pydantic¶
Теперь можно создать копию существующей модели, используя.model_copy(), и передать параметрupdate сdict, содержащим данные для обновления.
Например,stored_item_model.model_copy(update=update_data):
fromfastapiimportFastAPIfromfastapi.encodersimportjsonable_encoderfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:str|None=Nonedescription:str|None=Noneprice:float|None=Nonetax:float=10.5tags: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)asyncdefread_item(item_id:str):returnitems[item_id]@app.patch("/items/{item_id}")asyncdefupdate_item(item_id:str,item:Item)->Item:stored_item_data=items[item_id]stored_item_model=Item(**stored_item_data)update_data=item.model_dump(exclude_unset=True)updated_item=stored_item_model.model_copy(update=update_data)items[item_id]=jsonable_encoder(updated_item)returnupdated_itemКратко о частичном обновлении¶
В целом, для применения частичных обновлений необходимо:
- (Опционально) использовать
PATCHвместоPUT. - Извлечь сохранённые данные.
- Поместить эти данные в Pydantic-модель.
- Сгенерировать
dictбез значений по умолчанию из входной модели (с использованиемexclude_unset).- Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять уже сохраненные значения значениями по умолчанию из вашей модели.
- Создать копию хранимой модели, обновив ее атрибуты полученными частичными обновлениями (с помощью параметра
update). - Преобразовать скопированную модель в то, что может быть сохранено в вашей БД (например, с помощью
jsonable_encoder).- Это сравнимо с повторным использованием метода модели
.model_dump(), но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например,datetimeвstr.
- Это сравнимо с повторным использованием метода модели
- Сохранить данные в своей БД.
- Вернуть обновленную модель.
fromfastapiimportFastAPIfromfastapi.encodersimportjsonable_encoderfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:str|None=Nonedescription:str|None=Noneprice:float|None=Nonetax:float=10.5tags: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)asyncdefread_item(item_id:str):returnitems[item_id]@app.patch("/items/{item_id}")asyncdefupdate_item(item_id:str,item:Item)->Item:stored_item_data=items[item_id]stored_item_model=Item(**stored_item_data)update_data=item.model_dump(exclude_unset=True)updated_item=stored_item_model.model_copy(update=update_data)items[item_id]=jsonable_encoder(updated_item)returnupdated_itemПодсказка
На самом деле эту же технику можно использовать и для операции HTTPPUT.
Но в приведенном примере используетсяPATCH, поскольку он был создан именно для таких случаев использования.
Технические детали
Обратите внимание, что входная модель по-прежнему валидируется.
Таким образом, если вы хотите получать частичные обновления, в которых могут быть опущены все атрибуты, вам необходимо иметь модель, в которой все атрибуты помечены как необязательные (со значениями по умолчанию илиNone).
Чтобы отличить модели со всеми необязательными значениями дляобновления от моделей с обязательными значениями длясоздания, можно воспользоваться идеями, описанными вДополнительные модели.







