1.transaction.atomic() and nested blocks
Django runs in autocommit mode by default — every query commits immediately on its own. transaction.atomic() (as a decorator or with block) groups everything inside into one real transaction: all-or-nothing, committed together on success, rolled back together on any exception. A NESTED atomic() block creates a SAVEPOINT, not a separate transaction — if the inner block raises, only ITS changes roll back (to the savepoint); the outer block continues and can still commit its own, earlier work.
Key features
- Django's default is autocommit — atomic() is what turns a group of statements into one real transaction instead of many independent auto-committed ones
- atomic() works as both a decorator (@transaction.atomic) wrapping a whole function, and a context manager (with transaction.atomic():) wrapping just part of one
- A NESTED atomic() block creates a SAVEPOINT — an inner block's rollback (via an exception) undoes only that inner block's changes, not the outer block's already-completed work
- If the OUTER atomic() block itself raises (uncaught), everything rolls back — including changes from inner blocks that had already "succeeded" and exited normally
- The outer-most atomic() block is the true transaction boundary — commit only happens when THAT block exits without an exception
What rolls back, at which nesting level
- Outer atomic() — the true commit boundary — its rollback undoes everything, inner blocks included
- Inner atomic() (savepoint) — its own rollback stays scoped to just its own changes
- Autocommit (no atomic()) — default — every query commits immediately on its own
Command
@transaction.atomic
def transfer(from_id, to_id, amount):
...
# or, scoped to part of a function:
def view(request):
do_stuff() # autocommit — not part of any transaction
with transaction.atomic():
do_more_stuff() # atomicDjango defaults to autocommit — atomic() (decorator or context manager) is what groups statements into one real transaction. A NESTED atomic() block is a savepoint, not a separate transaction: its own rollback stays scoped to it, but the OUTERMOST block is the true commit boundary, and its rollback undoes everything, inner blocks included.