Lesson 20 / 26
Transactions and Referential Protection
All or nothing; no orphaned rows.
transaction.atomic and on_delete=PROTECT
transaction.atomic() wraps several writes so they commit together or roll back together when an exception occurs. Combine it with database constraints (unique, foreign keys) to keep data consistent even when application code has bugs. on_delete=PROTECT raises ProtectedError instead of deleting a category that still has products. Consider ATOMIC_REQUESTS or explicit atomic blocks around multi-step operations such as creating an order with its items.
A rolled-back transaction and a protected delete, run
I ran this script with python manage.py shell --no-imports in the demo project (Django 6.1.1, SQLite). Creating a category and product, then a duplicate category name, raises IntegrityError: the whole block rolls back, so the product count and the Toys category are unchanged. Deleting a category with products raises ProtectedError.
from decimal import Decimal
from django.db import IntegrityError, transaction
from catalog.models import Category, Product
before = Product.objects.count()
try:
with transaction.atomic():
toys = Category.objects.create(name="Toys")
Product.objects.create(category=toys, name="Yo-yo", price=Decimal("99"))
Category.objects.create(name="Office") # violates unique=True -> error
except IntegrityError as e:
print("rolled back:", type(e).__name__)
print("products before/after:", before, Product.objects.count())
print("Toys exists:", Category.objects.filter(name="Toys").exists())
try:
Category.objects.get(name="Office").delete()
except Exception as e:
print(type(e).__name__, "- PROTECT keeps products from losing their category")
Output:
rolled back: IntegrityError products before/after: 4 4 Toys exists: False ProtectedError - PROTECT keeps products from losing their category
Keep external calls outside transactions
Do not call payment or email APIs inside atomic blocks; use transaction.on_commit to trigger them after a successful commit.
Quick check: What happens to earlier writes in an atomic block when a later write fails?
- They stay committed
- They are rolled back too
- They are duplicated
- They are written to a log only
Answer
They are rolled back too — All or nothing.