feat: Добавить трёхуровневую защиту от дубликатов имён товаров, категорий, тегов и комплектов
Реализована полная система обеспечения уникальности названий: 1. **Уровень БД (Model Constraints)** - добавлены UniqueConstraint для: - Product: уникальность имени среди активных товаров - ProductCategory: уникальность имени среди активных категорий - ProductTag: уникальность имени только для активных тегов (неактивные могут повторяться) - ProductKit: уникальность имени среди активных, непроизвременных комплектов 2. **Уровень формы (Form Validation)** - добавлены clean() методы для: - ProductForm, ProductKitForm, ProductCategoryForm, ProductTagForm - Валидация до попытки сохранения в БД - Сохранение введённых данных при ошибке валидации 3. **Уровень представления (IntegrityError Handling)** - добавлена обработка в views: - ProductCategoryCreateView, ProductCategoryUpdateView - ProductTagCreateView, ProductTagUpdateView - ProductKitCreateView, ProductKitUpdateView - create_tag_api: защита от race conditions с fallback поиском Три уровня защиты гарантируют: - Профилактика ошибок на уровне формы - Обработка исключительных ситуаций в views - Защита БД от одновременных запросов (race conditions) - Пользователь видит понятное сообщение об ошибке вместо 500 ошибки 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"""
|
||||
from decimal import Decimal
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
@@ -110,6 +111,15 @@ class ProductKit(BaseProductEntity):
|
||||
models.Index(fields=['is_temporary']),
|
||||
models.Index(fields=['order']),
|
||||
]
|
||||
constraints = [
|
||||
# Уникальное имя для активных комплектов (исключаем удалённые)
|
||||
# Примечание: временные комплекты могут иметь дубли имён (создаются для заказов)
|
||||
models.UniqueConstraint(
|
||||
fields=['name'],
|
||||
condition=Q(is_deleted=False, is_temporary=False),
|
||||
name='unique_active_kit_name'
|
||||
),
|
||||
]
|
||||
|
||||
@property
|
||||
def actual_price(self):
|
||||
|
||||
Reference in New Issue
Block a user