python 36 lines · 1 tab

Django select_for_update for database locking

Priya Sharma Jan 2026
1 tab
from django.db import transaction
from django.shortcuts import get_object_or_404
from django.http import JsonResponse
from .models import Product


@transaction.atomic
def purchase_product(request, product_id, quantity):
    """Purchase product with stock locking."""
    # Lock the product row
    product = Product.objects.select_for_update().get(id=product_id)

    if product.stock < quantity:
        return JsonResponse({'error': 'Insufficient stock'}, status=400)

    # Decrement stock
    product.stock -= quantity
    product.save()

    # Create order (simplified)
    # Order.objects.create(...)

    return JsonResponse({'success': True, 'remaining_stock': product.stock})


def try_reserve_product(product_id):
    """Try to reserve without waiting for lock."""
    try:
        with transaction.atomic():
            product = Product.objects.select_for_update(nowait=True).get(id=product_id)
            product.reserved = True
            product.save()
            return True
    except models.DatabaseError:
        # Lock not available
        return False
1 file · python Explain with highlit

select_for_update() locks rows until transaction completes, preventing race conditions. I use it for operations requiring read-modify-write atomicity like decrementing stock or updating counters. The lock is released on transaction commit/rollback. For non-blocking behavior, I use nowait=True or skip_locked=True. This is essential for concurrent writes to the same records. I wrap in transaction.atomic() for proper lock management. PostgreSQL and MySQL support this; SQLite has limited support. This prevents lost updates in high-concurrency scenarios.


Related snips

Share this code

Here's the card — post it anywhere.

Django select_for_update for database locking — share card
Link copied