Реализован полный CRUD для тегов товаров

Упрощена модель ProductTag:
- Удалены поля soft delete (is_deleted, deleted_at, deleted_by)
- Добавлено поле is_active для управления статусом
- Упрощены менеджеры и методы модели

Создан CRUD функционал:
- ProductTagForm: форма с автогенерацией slug
- Views: список, создание, просмотр, редактирование, удаление
- URL маршруты: /products/tags/*
- Шаблоны: list, form, detail, confirm_delete

Особенности:
- Поиск по названию и slug
- Фильтрация по статусу активности
- Статистика использования тегов в товарах/комплектах
- Пагинация (20 на страницу)
- Предупреждение при удалении с отображением связанных объектов
- Добавлена ссылка "Теги" в навигацию

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-11 23:14:01 +03:00
parent 4a1f8266de
commit 1a0360f8c0
12 changed files with 733 additions and 48 deletions

View File

@@ -451,3 +451,40 @@ ProductVariantGroupItemFormSetUpdate = inlineformset_factory(
validate_min=False, # Не требовать минимум товаров
can_delete_extra=True, # Разрешить удалять дополнительные формы
)
class ProductTagForm(forms.ModelForm):
"""
Форма для создания и редактирования тегов товаров.
"""
class Meta:
model = ProductTag
fields = ['name', 'slug', 'is_active']
labels = {
'name': 'Название',
'slug': 'URL-идентификатор',
'is_active': 'Активен'
}
help_texts = {
'slug': 'Оставьте пустым для автоматической генерации из названия',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({
'class': 'form-control form-control-lg fw-semibold',
'placeholder': 'Введите название тега'
})
self.fields['slug'].widget.attrs.update({
'class': 'form-control',
'placeholder': 'url-identifier (автоматически)'
})
self.fields['slug'].required = False
self.fields['is_active'].widget.attrs.update({'class': 'form-check-input'})
def clean_slug(self):
"""Разрешаем пустой slug - он сгенерируется в модели"""
slug = self.cleaned_data.get('slug')
if slug == '' or slug is None:
return None
return slug