About Locking Database Table Rows
The select_for_update() method of a queryset allows locking filtered table rows for updates within the same atomic transaction. This ensures that two concurrent Django requests don't create race conditions - that is, they don't both read and modify the same initial data, but instead process the data sequentially, one after the other.
from django.db import transaction
from myapp.models import Account
@transaction.atomic
def transfer_money(from_account_id, to_account_id, amount):
# Lock the rows to prevent concurrent modifications
from_account = Account.objects.select_for_update().get(
pk=from_account_id
)
to_account = Account.objects.select_for_update().get(
pk=to_account_id
)
# Check if from_account has sufficient balance
if from_account.balance < amount:
raise ValueError("Insufficient funds")
# Perform the transfer
from_account.balance -= amount
to_account.balance += amount
# Save both accounts
from_account.save()
to_account.save()
Tips and Tricks Programming Databases Django 6.x Django 5.2 Django 4.2 Django ORM
Also by me
Django Messaging
For Django-based social platforms.
Django Paddle Subscriptions
For Django-based SaaS projects.
Django GDPR Cookie Consent
For Django websites that use cookies.