Fix select_for_update with nullable FK outer join error

Remove select_related('locked_by_user') from select_for_update query
to avoid PostgreSQL error "FOR UPDATE cannot be applied to the
nullable side of an outer join". Username is now fetched via lazy load.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-22 23:33:52 +03:00
parent 38ee2f5df7
commit 856e1ca4c1

View File

@@ -486,6 +486,7 @@ def add_showcase_kit_to_cart(request, kit_id):
# Атомарная проверка и создание блокировки (предотвращает race condition)
with transaction.atomic():
# Блокируем строки резервов для этого комплекта на уровне БД
# Примечание: нельзя использовать select_related с nullable FK при select_for_update
reservations = Reservation.objects.select_for_update().filter(
product_kit=kit,
status='reserved'
@@ -496,13 +497,15 @@ def add_showcase_kit_to_cart(request, kit_id):
cart_lock_expires_at__gt=timezone.now()
).exclude(
locked_by_user=request.user
).select_related('locked_by_user').first()
).first()
if existing_lock:
# Получаем username отдельным запросом (избегаем outer join с select_for_update)
locked_by_username = existing_lock.locked_by_user.username if existing_lock.locked_by_user else 'другой кассир'
time_left = (existing_lock.cart_lock_expires_at - timezone.now()).total_seconds() / 60
return JsonResponse({
'success': False,
'error': f'Этот букет уже в корзине кассира "{existing_lock.locked_by_user.username}". '
'error': f'Этот букет уже в корзине кассира "{locked_by_username}". '
f'Блокировка истечет через {int(time_left)} мин.'
}, status=409) # 409 Conflict