From d5e40bb1c89b6d41c31775b9ae1c11f9c9a4da62 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Thu, 11 Dec 2025 22:14:57 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B4=D0=B0=D0=B6=D0=B0?= =?UTF-8?q?=20=D0=BC=D0=BD=D0=BE=D0=B6=D0=B5=D1=81=D1=82=D0=B2=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D1=8D=D0=BA=D0=B7=D0=B5=D0=BC=D0=BF=D0=BB?= =?UTF-8?q?=D1=8F=D1=80=D0=BE=D0=B2=20=D0=B2=D0=B8=D1=82=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B1=D1=83=D0=BA=D0=B5=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема: При продаже 2+ экземпляров одного витринного комплекта возникала ошибка 'Один из экземпляров уже был продан'. Это происходило потому что объекты ShowcaseItem проверялись по старому состоянию из памяти. Причина: - При вызове sell_showcase_items() передавался список объектов из запроса - Первый ShowcaseItem менял статус на 'sold' через mark_sold() - Второй объект в списке все еще имел старый статус из памяти - Проверка в цикле срабатывала некорректно Решение: - Перезагружаем ВСЕ ShowcaseItem из БД с блокировкой перед обработкой - Используем select_for_update() для получения актуального статуса - Теперь каждый экземпляр проверяется по свежим данным из БД - Защита от race conditions через database-level locking Результат: Теперь можно продавать 2+ экземпляра одного букета без ошибок. --- myproject/inventory/services/showcase_manager.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/myproject/inventory/services/showcase_manager.py b/myproject/inventory/services/showcase_manager.py index 8299a76..384ba3d 100644 --- a/myproject/inventory/services/showcase_manager.py +++ b/myproject/inventory/services/showcase_manager.py @@ -151,7 +151,17 @@ class ShowcaseManager: try: with transaction.atomic(): - for showcase_item in showcase_items: + # Собираем ID для перезагрузки с блокировкой + showcase_item_ids = [item.id for item in showcase_items] + + # Перезагружаем объекты из БД с блокировкой для актуального статуса + showcase_items_locked = list( + ShowcaseItem.objects.select_for_update().filter( + id__in=showcase_item_ids + ) + ) + + for showcase_item in showcase_items_locked: # Проверка статуса перед продажей if showcase_item.status == 'sold': raise ValidationError(