Corps - Mises à jour¶
🌐 Traduction par IA et humains
Cette traduction a été réalisée par une IA guidée par des humains. 🤝
Elle peut contenir des erreurs d'interprétation du sens original, ou paraître peu naturelle, etc. 🤖
Vous pouvez améliorer cette traduction en nous aidant à mieux guider le LLM d'IA.
Mettre à jour en remplaçant avec PUT¶
Pour mettre à jour un élément, vous pouvez utiliser l’opération HTTP PUT.
Vous pouvez utiliser le jsonable_encoder pour convertir les données d’entrée en données pouvant être stockées au format JSON (par exemple, avec une base de données NoSQL). Par exemple, convertir datetime en 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
On utilise PUT pour recevoir des données qui doivent remplacer les données existantes.
Avertissement concernant le remplacement¶
Cela signifie que si vous souhaitez mettre à jour l’élément bar avec PUT et un corps contenant :
{
"name": "Barz",
"price": 3,
"description": None,
}
comme il n’inclut pas l’attribut déjà enregistré « tax »: 20.2, le modèle d’entrée prendrait la valeur par défaut « tax »: 10.5.
Et les données seraient enregistrées avec cette « nouvelle » tax de 10.5.
Effectuer des mises à jour partielles avec PATCH¶
Vous pouvez également utiliser l’opération HTTP PATCH pour mettre à jour des données de manière partielle.
Cela signifie que vous pouvez n’envoyer que les données que vous souhaitez mettre à jour, en laissant le reste intact.
Remarque
PATCH est moins utilisé et moins connu que PUT.
Et de nombreuses équipes n’utilisent que PUT, même pour les mises à jour partielles.
Vous êtes libre de les utiliser comme vous le souhaitez, FastAPI n’impose aucune restriction.
Mais ce guide vous montre, plus ou moins, la façon dont ils sont censés être utilisés.
Utiliser le paramètre exclude_unset de Pydantic¶
Si vous souhaitez recevoir des mises à jour partielles, il est très utile d’utiliser le paramètre exclude_unset dans la méthode .model_dump() du modèle Pydantic.
Comme item.model_dump(exclude_unset=True).
Cela génère un dict ne contenant que les données définies lors de la création du modèle item, en excluant les valeurs par défaut.
Vous pouvez ensuite l’utiliser pour produire un dict avec uniquement les données définies (envoyées dans la requête), en omettant les valeurs par défaut :
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}")
async def update_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)
return updated_item
Utiliser le paramètre update de Pydantic¶
Vous pouvez maintenant créer une copie du modèle existant avec .model_copy(), et passer le paramètre update avec un dict contenant les données à mettre à jour.
Comme stored_item_model.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}")
async def update_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)
return updated_item
Récapitulatif des mises à jour partielles¶
En résumé, pour appliquer des mises à jour partielles, vous procédez ainsi :
- (Optionnel) utilisez
PATCHau lieu dePUT. - Récupérez les données stockées.
- Placez ces données dans un modèle Pydantic.
- Générez un
dictsans valeurs par défaut à partir du modèle d’entrée (en utilisantexclude_unset).- De cette façon, vous mettez à jour uniquement les valeurs effectivement définies par l’utilisateur, au lieu d’écraser des valeurs déjà stockées par des valeurs par défaut de votre modèle.
- Créez une copie du modèle stocké, en mettant à jour ses attributs avec les mises à jour partielles reçues (en utilisant le paramètre
update). - Convertissez le modèle copié en quelque chose qui peut être stocké dans votre base de données (par exemple en utilisant le
jsonable_encoder).- Cela est comparable à l’utilisation à nouveau de la méthode
.model_dump()du modèle, mais cela vérifie (et convertit) les valeurs vers des types pouvant être convertis en JSON, par exempledatetimeenstr.
- Cela est comparable à l’utilisation à nouveau de la méthode
- Enregistrez les données dans votre base de données.
- Retournez le modèle mis à jour.
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}")
async def update_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)
return updated_item
Astuce
Vous pouvez en réalité utiliser cette même technique avec une opération HTTP PUT.
Mais l’exemple ici utilise PATCH car il a été créé pour ces cas d’usage.
Remarque
Remarquez que le modèle d’entrée est toujours validé.
Ainsi, si vous souhaitez recevoir des mises à jour partielles pouvant omettre tous les attributs, vous devez disposer d’un modèle avec tous les attributs marqués comme optionnels (avec des valeurs par défaut ou None).
Pour distinguer les modèles avec toutes les valeurs optionnelles pour les mises à jour et les modèles avec des valeurs requises pour la création, vous pouvez utiliser les idées décrites dans Modèles supplémentaires.