Реализовано управление активностью тегов товаров и комплектов

## Что сделано:

### 1. Фильтрация тегов по активности
- ProductForm и ProductKitForm показывают только активные теги в селектах
- ProductListView, ProductKitListView передают только активные теги в контекст фильтров

### 2. Отображение тегов на страницах товаров/комплектов
- product_detail.html отображает только активные теги
- productkit_detail.html отображает только активные теги

### 3. Логика отображения в деталях тега
- Для активного тега: показываются только активные товары/комплекты
- Для неактивного тега: показываются ВСЕ товары/комплекты (для возможности ручной очистки)

### 4. API endpoint для переключения статуса
- Новый endpoint toggle_tag_status_api в api_views.py
- POST /products/api/tags/<id>/toggle/
- Переключает is_active и возвращает новый статус

### 5. AJAX toggle switch в таблице тегов
- Заменены бейджи на toggle switch в tag_list.html
- Переключатель в 1.3x больше (масштабирование через CSS)
- Мгновенное обновление без перезагрузки страницы
- Показывает сообщение об успехе/ошибке

### 6. Связь в БД остаётся неизменной
- При деактивации тег остаётся привязан к товарам в БД
- Просто скрывается в интерфейсе
- При реактивации вновь становится видимым

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-12 11:33:12 +03:00
parent a1f5733fde
commit 77064a274f
9 changed files with 252 additions and 20 deletions

View File

@@ -8,7 +8,7 @@ from django.urls import reverse_lazy
from django.shortcuts import redirect
from django.db import transaction
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto, Product, ProductVariantGroup
from ..forms import ProductKitForm, KitItemFormSetCreate, KitItemFormSetUpdate
from .utils import handle_photos
@@ -52,7 +52,7 @@ class ProductKitListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# Данные для фильтров
context['filters'] = {
'categories': ProductCategory.objects.filter(is_active=True),
'tags': ProductTag.objects.all(),
'tags': ProductTag.objects.filter(is_active=True),
'current': {
'search': self.request.GET.get('search', ''),
'category': self.request.GET.get('category', ''),
@@ -146,10 +146,20 @@ class ProductKitCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateVi
if '-variant_group' in key and value:
try:
variant_group = ProductVariantGroup.objects.get(id=value)
variant_group = ProductVariantGroup.objects.prefetch_related(
'items__product'
).get(id=value)
variant_price = variant_group.price or 0
count = variant_group.items.count()
selected_variants[key] = {
'id': variant_group.id,
'text': variant_group.name
'text': f"{variant_group.name} ({count} вариантов)",
'price': str(variant_price),
'actual_price': str(variant_price),
'type': 'variant',
'count': count
}
except ProductVariantGroup.DoesNotExist:
pass
@@ -248,9 +258,98 @@ class ProductKitUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateVi
if self.request.POST:
context['kititem_formset'] = KitItemFormSetUpdate(self.request.POST, instance=self.object, prefix='kititem')
# При ошибке валидации - подготавливаем данные для Select2
selected_products = {}
selected_variants = {}
for key, value in self.request.POST.items():
if '-product' in key and value:
try:
# Очищаем ID от префикса если есть
numeric_value = value.split('_')[1] if '_' in value else value
product = Product.objects.get(id=numeric_value)
text = product.name
if product.sku:
text += f" ({product.sku})"
actual_price = product.sale_price if product.sale_price else product.price
selected_products[key] = {
'id': product.id,
'text': text,
'price': str(product.price) if product.price else None,
'actual_price': str(actual_price) if actual_price else '0'
}
except Product.DoesNotExist:
pass
if '-variant_group' in key and value:
try:
variant_group = ProductVariantGroup.objects.prefetch_related(
'items__product'
).get(id=value)
variant_price = variant_group.price or 0
count = variant_group.items.count()
selected_variants[key] = {
'id': variant_group.id,
'text': f"{variant_group.name} ({count} вариантов)",
'price': str(variant_price),
'actual_price': str(variant_price),
'type': 'variant',
'count': count
}
except ProductVariantGroup.DoesNotExist:
pass
context['selected_products'] = selected_products
context['selected_variants'] = selected_variants
else:
context['kititem_formset'] = KitItemFormSetUpdate(instance=self.object, prefix='kititem')
# Подготавливаем данные для предзагрузки в Select2
selected_products = {}
selected_variants = {}
for item in self.object.kit_items.all():
form_prefix = f"kititem-{item.id}"
if item.product:
product = item.product
text = product.name
if product.sku:
text += f" ({product.sku})"
actual_price = product.sale_price if product.sale_price else product.price
selected_products[f"{form_prefix}-product"] = {
'id': product.id,
'text': text,
'price': str(product.price) if product.price else None,
'actual_price': str(actual_price) if actual_price else '0'
}
if item.variant_group:
variant_group = ProductVariantGroup.objects.prefetch_related(
'items__product'
).get(id=item.variant_group.id)
variant_price = variant_group.price or 0
count = variant_group.items.count()
selected_variants[f"{form_prefix}-variant_group"] = {
'id': variant_group.id,
'text': f"{variant_group.name} ({count} вариантов)",
'price': str(variant_price),
'actual_price': str(variant_price),
'type': 'variant',
'count': count
}
context['selected_products'] = selected_products
context['selected_variants'] = selected_variants
context['productkit_photos'] = self.object.photos.all().order_by('order', 'created_at')
context['photos_count'] = self.object.photos.count()