1. Was ist transaction.on_commit()?

Es handelt sich um eine Callback-Registrierungsmethode, die in Django verwendet wird, wenn man nach erfolgreichem Commit einer Datenbanktransaktion eine Aktion ausführen möchte.

from django.db import transaction

transaction.on_commit(my_function)

Wenn dieser Code ausgeführt wird, wird my_function() nach erfolgreichem Abschluss der aktuellen Transaktion ausgeführt.

Django transaction.on_commit Konzeptbild


2. In welchen Situationen wird es verwendet?

Situation Verwendung
Wenn man nach dem sicheren Speichern in die DB etwas ausführen möchte ✅ Geeignet
Wenn man Celery-Tasks nach der Transaktion ausführen möchte ✅ Geeignet
Für externe API-Calls, Cache-Aktualisierungen usw. ✅ Geeignet
Wenn die Reihenfolge der Aufrufe außerhalb der Transaktion nicht wichtig ist ❌ Nicht geeignet

3. Kernkonzepte

  • on_commit() hat nur Bedeutung, wenn eine aktuelle Transaktion aktiv ist.
  • Wenn keine Transaktion vorhanden ist, wird der Callback sofort ausgeführt!

4. Falsches Beispiel

def my_view(request):
    def notify():
        print("Ausgeführt!")

    transaction.on_commit(notify)  # Da keine Transaktion vorhanden ist, wird es sofort ausgeführt!

5. Richtiges Beispiel

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)

In diesem Beispiel wird translate() nur ausgeführt, nachdem post erstellt und die Kategorien hinzugefügt wurden.


6. Warum ist das wichtig?

Viele Entwickler verwechseln folgendes:

  • ORMs create(), add() sind nicht tatsächlich committed
  • Vor dem Commit befinden sich alle in "logischer Speicherung" Status
  • Celery-Tasks werden in separaten Prozessen ausgeführt,
  • Wenn sie vor dem Commit ausgeführt werden, wird auf unvollständige Daten verwiesen

7. Ideales Beispiel mit 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)

Diese Struktur stellt sicher, dass die Speicherung von Kategorien/Tags abgeschlossen ist, bevor der translate_post Task ausgeführt wird.


8. Zusammenfassung

Konzept Beschreibung
Wann wird es ausgeführt? Unmittelbar nach erfolgreichem Commit der Transaktion
Im Falle eines Fehlers? Wird niemals ausgeführt, wenn ein Rollback passiert
Wenn keine Transaktion vorhanden ist? Wird sofort ausgeführt (Vorsicht!)
Verwendungsort Innerhalb des with transaction.atomic() Blocks
Anwendungsbeispiele Ausführung von Celery-Tasks, Benachrichtigungen, Cache-Updates usw.

9. Jesses Kommentar

transaction.on_commit() ist nicht einfach nur eine Verzögerung der Ausführung.
Es ist ein klares Ausdruck der Absicht des Entwicklers, dass es nur ausgeführt wird, wenn die Transaktion erfolgreich ist, und es ist ein notwendiges Werkzeug, um die Datenintegrität zu wahren, wenn ORM und asynchrone Verarbeitung zusammen verwendet werden.