Body - Actualizaciones¶
🌐 Traducción por IA y humanos
Esta traducción fue hecha por IA guiada por humanos. 🤝
Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖
Puedes mejorar esta traducciónayudándonos a guiar mejor al LLM de IA.
Actualización reemplazando conPUT¶
Para actualizar un ítem puedes utilizar la operación deHTTPPUT.
Puedes usar eljsonable_encoder para convertir los datos de entrada en datos que se puedan almacenar como JSON (por ejemplo, con una base de datos NoSQL). Por ejemplo, convirtiendodatetime astr.
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 se usa para recibir datos que deben reemplazar los datos existentes.
Advertencia sobre el reemplazo¶
Esto significa que si quieres actualizar el ítembar usandoPUT con un body que contenga:
{"name":"Barz","price":3,"description":None,}debido a que no incluye el atributo ya almacenado"tax": 20.2, el modelo de entrada tomaría el valor por defecto de"tax": 10.5.
Y los datos se guardarían con ese "nuevo"tax de10.5.
Actualizaciones parciales conPATCH¶
También puedes usar la operación deHTTPPATCH para actualizarparcialmente datos.
Esto significa que puedes enviar solo los datos que deseas actualizar, dejando el resto intacto.
Nota
PATCH es menos usado y conocido quePUT.
Y muchos equipos utilizan soloPUT, incluso para actualizaciones parciales.
Ereslibre de usarlos como desees,FastAPI no impone ninguna restricción.
Pero esta guía te muestra, más o menos, cómo se pretende que se usen.
Uso del parámetroexclude_unset de Pydantic¶
Si quieres recibir actualizaciones parciales, es muy útil usar el parámetroexclude_unset en el.model_dump() del modelo de Pydantic.
Comoitem.model_dump(exclude_unset=True).
Eso generaría undict solo con los datos que se establecieron al crear el modeloitem, excluyendo los valores por defecto.
Luego puedes usar esto para generar undict solo con los datos que se establecieron (enviados en el request), omitiendo los valores por defecto:
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_itemUso del parámetroupdate de Pydantic¶
Ahora, puedes crear una copia del modelo existente usando.model_copy(), y pasar el parámetroupdate con undict que contenga los datos a actualizar.
Comostored_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_itemResumen de actualizaciones parciales¶
En resumen, para aplicar actualizaciones parciales deberías:
- (Opcionalmente) usar
PATCHen lugar dePUT. - Recuperar los datos almacenados.
- Poner esos datos en un modelo de Pydantic.
- Generar un
dictsin valores por defecto del modelo de entrada (usandoexclude_unset).- De esta manera puedes actualizar solo los valores realmente establecidos por el usuario, en lugar de sobrescribir valores ya almacenados con valores por defecto en tu modelo.
- Crear una copia del modelo almacenado, actualizando sus atributos con las actualizaciones parciales recibidas (usando el parámetro
update). - Convertir el modelo copiado en algo que pueda almacenarse en tu DB (por ejemplo, usando el
jsonable_encoder).- Esto es comparable a usar el método
.model_dump()del modelo de nuevo, pero asegura (y convierte) los valores a tipos de datos que pueden convertirse a JSON, por ejemplo,datetimeastr.
- Esto es comparable a usar el método
- Guardar los datos en tu DB.
- Devolver el modelo actualizado.
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_itemConsejo
Puedes realmente usar esta misma técnica con una operación HTTPPUT.
Pero el ejemplo aquí usaPATCH porque fue creado para estos casos de uso.
Nota
Observa que el modelo de entrada sigue siendo validado.
Entonces, si deseas recibir actualizaciones parciales que puedan omitir todos los atributos, necesitas tener un modelo con todos los atributos marcados como opcionales (con valores por defecto oNone).
Para distinguir entre los modelos con todos los valores opcionales paraactualizaciones y modelos con valores requeridos paracreación, puedes utilizar las ideas descritas enModelos Extra.







