1. What is transaction.on_commit()
?
It is a callback registration method used in Django when you want to execute some operation immediately after a database transaction has been successfully committed.
from django.db import transaction
transaction.on_commit(my_function)
When this code is executed, my_function()
will run after the current transaction is successfully completed.
2. When to use it?
Situation | Usage |
---|---|
When you want to execute something after confirming the data is saved to the DB | ✅ Appropriate |
When you want to execute a Celery task after the transaction | ✅ Appropriate |
For external API calls, cache refresh, etc. | ✅ Appropriate |
When the order of execution outside the transaction is not important | ❌ Inappropriate |
3. Key Concepts
on_commit()
only makes sense when there is an active transaction.- If there is no transaction, the callback will be executed immediately!
4. Incorrect Example
def my_view(request):
def notify():
print("Executed!")
transaction.on_commit(notify) # Executes immediately as there is no transaction!
5. Correct Usage Example
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 the above example, translate()
will only be executed after both the post
creation and category addition are completed.
6. Why is it important?
Many developers confuse the following:
- ORM's
create()
andadd()
does not mean that it is actually committed - Before the commit, everything is in a "logical save" state
- Since a Celery task runs in a separate process,
- If executed before the commit, it will reference incomplete data
7. Ideal Example of Using 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)
This structure ensures that the translate_post
task is only executed after the categories/tags are confirmed to be stored.
8. Summary
Concept | Description |
---|---|
When does it execute? | Immediately after the transaction is successfully committed |
What if it fails? | Will never execute if rollback occurs |
What if there is no transaction? | Executes immediately (caution!) |
Where to use it? | Inside with transaction.atomic() block |
Practical examples | Execute Celery tasks, send notifications, update caches, etc. |
9. Jesse's Comment
transaction.on_commit()
is not just a simple delayed execution.
It is a clear expression of the developer's intent to execute only if the transaction succeeds,
and is an essential tool to ensure data integrity when using ORM and asynchronous processing together.
There are no comments.