From 856e1ca4c1a462c399533f4f7148e7b8dfb52f14 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Sat, 22 Nov 2025 23:33:52 +0300 Subject: [PATCH] Fix select_for_update with nullable FK outer join error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- myproject/pos/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/myproject/pos/views.py b/myproject/pos/views.py index fd8b278..774dae4 100644 --- a/myproject/pos/views.py +++ b/myproject/pos/views.py @@ -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