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.
Add a New Comment