1. transaction.on_commit()
c'est quoi ?
C'est une méthode d'enregistrement de callback utilisée dans Django pour exécuter une action juste après qu'une transaction de base de données ait été commitée avec succès.
from django.db import transaction
transaction.on_commit(my_function)
Lorsque ce code est exécuté, my_function()
sera appelé après que la transaction actuelle soit terminée avec succès.
2. Dans quelles situations l'utiliser ?
Situation | Utilisation |
---|---|
Quand vous voulez exécuter quelque chose après avoir confirmé que les données sont bien stockées dans la DB | ✅ Adapté |
Quand vous voulez exécuter une tâche Celery après la transaction | ✅ Adapté |
Appels d'API externes, mise à jour des caches, etc. | ✅ Adapté |
Quand l'ordre des appels n'est pas important en dehors de la transaction | ❌ Inadapté |
3. Concepts clés
on_commit()
n'a de sens que lorsque « une transaction est en cours d'exécution ».- S'il n'y a pas de transaction, le callback sera exécuté immédiatement!
4. Exemple incorrect
def my_view(request):
def notify():
print("Exécuté !")
transaction.on_commit(notify) # S'exécute immédiatement car il n'y a pas de transaction !
5. Exemple d'utilisation correct
from django.db import transaction
def my_view(request):
with transaction.atomic():
post = Post.objects.create(...)
post.categories.add(...)
def translate():
translate_post.delay(post.id)
transaction.on_commit(translate)
Dans cet exemple, translate()
n'est exécuté qu'après que la création du post
et l'ajout de catégories soient tous deux terminés.
6. Pourquoi est-ce important ?
Beaucoup de développeurs confondent les points suivants :
- Les
create()
etadd()
de l'ORM ne signifient pas que les données sont effectivement commités - Avant le commit, tout est en état de « stockage logique »
- Les tâches Celery s'exécutent dans un processus séparé, donc
- Si elles s'exécutent avant le commit, elles référenceront des données incomplètes
7. Exemple idéal d'utilisation avec Celery
@shared_task
def post_finalize_task(post_id, categories, tags):
post = Post.objects.get(id=post_id)
with transaction.atomic():
for name in categories:
cat, _ = Category.objects.get_or_create(name=name)
post.categories.add(cat)
for name in tags:
tag, _ = Tag.objects.get_or_create(name=name)
post.tags.add(tag)
def schedule_translation():
translate_post.delay(post.id)
transaction.on_commit(schedule_translation)
Cette structure garantit que la tâche translate_post
ne sera exécutée qu'après que le stockage des catégories et des tags soit confirmé.
8. Résumé
Concept | Description |
---|---|
Quand s'exécute-t-il ? | Juste après qu'une transaction soit commitée avec succès |
En cas d'échec ? | Ne s'exécute jamais en cas de rollback |
Pas de transaction ? | S'exécute immédiatement (attention !) |
Où l'utiliser ? | À l'intérieur d'un bloc with transaction.atomic() |
Exemples d'application | Exécution de tâches Celery, envoi de notifications, mise à jour des caches, etc. |
9. Commentaire de Jesse
transaction.on_commit()
n'est pas une simple exécution différée.
C'est une expression claire de l'intention du développeur de n'exécuter le code que si la transaction est réussie,
et c'est un outil essentiel pour maintenir l'intégrité des données lorsque l'ORM et le traitement asynchrone sont utilisés ensemble.
Add a New Comment