Écriture conditionnelle DynamoDB en Python (boto3)
boto3 est le seul SDK où une écriture conditionnelle dispose d'une classe d'exception nommée à attraper, et c'est aussi le seul où l'élément renvoyé se cache à un endroit que tu ne devinerais pas. L'expression elle-même fonctionne pareil partout ; les expressions de condition DynamoDB couvrent les fonctions et le motif du verrouillage optimiste.
Code
import boto3
client = boto3.client("dynamodb")
# Update the item only if nobody changed it since we read version 7.
try:
client.update_item(
TableName="Music",
Key={"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
UpdateExpression="SET #upd0 = :updValue0, #version = :newVersion",
ConditionExpression="attribute_exists(#cond0) AND #version = :expectedVersion",
ExpressionAttributeNames={"#upd0": "Genre", "#version": "Version", "#cond0": "Artist"},
ExpressionAttributeValues={
":updValue0": {"S": "Latin Jazz"},
":expectedVersion": {"N": "7"},
":newVersion": {"N": "8"},
},
ReturnValuesOnConditionCheckFailure="ALL_OLD",
)
print("Updated to version 8")
except client.exceptions.ConditionalCheckFailedException as e:
# With ReturnValuesOnConditionCheckFailure="ALL_OLD", the current item
# rides back on the exception — no extra read to see what beat you.
print("Lost the race — item is now:", e.response.get("Item"))Explication
ConditionalCheckFailedExceptionest une classe modélisée, doncexcept client.exceptions.…fonctionne. La plupart des erreurs DynamoDB ne le sont pas :ValidationExceptionn'a aucune classe et doit être discriminée sure.response["Error"]["Code"]. La classe modélisée hérite quand même deClientError, donc unexcept ClientErrorlarge placé en amont l'avalera si tu ordonnes tes handlers sans précaution.- L'élément renvoyé est une clé de premier niveau de
e.response, pas dee.response["Error"]. C'est pour ça que le bloc lite.response.get("Item"). Il est facile d'aller chercher sous["Error"], à côté deCodeetMessage, de ne rien trouver et d'en conclure que le paramètre n'a pas marché. - L'élément revient en DynamoDB JSON même si tu as l'habitude des valeurs natives, parce qu'il s'agit ici du client bas niveau.
boto3.dynamodb.types.TypeDeserializerle convertit si tu veux du Python ordinaire. - L'API resource exprime la même garde sous forme d'objets,
ConditionExpression=Attr("Version").eq(7) & Attr("Artist").exists(), avec des valeurs natives et sans maps de placeholders. Elle lève exactement la même exception, donc la gestion ci-dessous est inchangée. - Une vérification échouée facture quand même une écriture. Le Developer Guide est explicite : une condition fausse consomme de la capacité d'écriture, dimensionnée sur le plus gros de l'ancien et du nouvel élément. Une reprise sans plafond sur une clé disputée coûte donc de l'argent réel sans jamais avancer.
Où boto3 range l'élément renvoyé
Lance le bloc sur une Version stockée à 9 et affiche les clés de la réponse portée par l'exception. DynamoDB Local 3.3.0, boto3 1.43.58 :
sorted(e.response.keys()) -> ['Error', 'Item', 'ResponseMetadata']
e.response["Item"] -> {'Artist': {'S': 'Arturo Sandoval'},
'Year': {'N': '1994'},
'Version': {'N': '9'},
'SongTitle': {'S': 'Cubano Chant'},
'AlbumTitle': {'S': 'Danzon'}}Supprime ReturnValuesOnConditionCheckFailure et le même échec donne ['Error', 'ResponseMetadata']. La clé Item est absente, et e.response.get("Item") renvoie None au lieu de lever une exception. C'est la version de ce bug qui survit à la revue de code et se met à journaliser None en production.
Pourquoi chaque nom de l'expression est aliasé
Le bloc écrit #version et #cond0 plutôt que Version et Artist, ce qui paraît excessif pour deux mots ordinaires. Ça l'est, pour ces deux-là. Version n'est pas un mot réservé DynamoDB, et écrit en clair il passe la validation des noms.
Year est réservé, et la même table en a un. Garde dessus directement et tu obtiens :
ValidationException: Invalid ConditionExpression: Attribute name is a reserved keyword;
reserved keyword: Year573 mots figurent sur cette liste, dont Name, Status, Size, Count, Data, Owner, Timestamp et Items. Tout aliaser, c'est ainsi que le code généré évite d'avoir à savoir lequel est lequel. Colle tes noms d'attributs dans le vérificateur de mots réservés et il te rend la map ExpressionAttributeNames pour ceux qui en ont besoin.
Pour écrire ces gardes sur tes propres tables avec l'aliasage pris en charge pour toi, télécharge DynoTable.
Exemples liés
- Écriture conditionnelle DynamoDB en Node.js — le même verrou optimiste avec AWS SDK v3.
- Écriture conditionnelle DynamoDB avec l'AWS CLI — le même verrou optimiste depuis le shell.
- DynamoDB PutItem en Python — le put
attribute_not_existsen création seule. - Les expressions de condition DynamoDB — chaque fonction, avec des motifs.
- Imposer l'unicité sur plusieurs attributs — conditions et transactions combinées.
- DynamoDB ConditionalCheckFailedException — quand la vérification échouée est attendue, et comment la gérer à moindre coût.
Références
- UpdateItem — Amazon DynamoDB API Reference
- DynamoDB.Client.update_item — Boto3 documentation
- Condition expressions — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations (capacity unit consumption) — Amazon DynamoDB Developer Guide
- Reserved words in DynamoDB — Amazon DynamoDB Developer Guide
Dernière vérification le 2026-07-28 par rapport à la documentation officielle AWS liée ci-dessus.