""" Менеджеры и QuerySets для моделей продуктов. Реализуют паттерн Soft Delete и фильтрацию активных записей. """ from django.db import models from django.utils import timezone class ActiveManager(models.Manager): """Менеджер для фильтрации только активных записей""" def get_queryset(self): # Работает с обоими полями: status (Product/ProductKit) и is_active (Category/Tag) qs = super().get_queryset() if hasattr(self.model, 'status'): return qs.filter(status='active') elif hasattr(self.model, 'is_active'): return qs.filter(is_active=True) return qs class SoftDeleteQuerySet(models.QuerySet): """ QuerySet для архивирования товаров. Позволяет фильтровать архивированные/снятые элементы и восстанавливать их. Поддерживает обе системы: status (новая) и is_deleted/is_active (старая). """ def _has_status_field(self): """Проверяет, использует ли модель поле status""" return hasattr(self.model, 'status') def _has_is_deleted_field(self): """Проверяет, использует ли модель поле is_deleted""" return hasattr(self.model, 'is_deleted') def delete(self): """Архивирование вместо hard delete""" if self._has_status_field(): return self.update( status='archived', archived_at=timezone.now() ) elif self._has_is_deleted_field(): return self.update( is_deleted=True, deleted_at=timezone.now() ) else: # Fallback для моделей без мягкого удаления return super().delete() def hard_delete(self): """Явный hard delete - удаляет из БД окончательно""" return super().delete() def archive(self): """Архивирование товаров""" if self._has_status_field(): return self.update(status='archived', archived_at=timezone.now()) elif self._has_is_deleted_field(): return self.update(is_deleted=True, deleted_at=timezone.now()) else: return self.delete() def restore(self): """Восстановление архивированных товаров""" if self._has_status_field(): return self.update( status='active', archived_at=None, archived_by=None ) elif self._has_is_deleted_field(): return self.update( is_deleted=False, deleted_at=None, deleted_by=None ) def discontinue(self): """Пометить как снятые (устарели)""" if self._has_status_field(): return self.update(status='discontinued') else: # Для моделей без status просто архивируем return self.archive() def archived_only(self): """Получить только архивированные товары""" if self._has_status_field(): return self.filter(status='archived') elif self._has_is_deleted_field(): return self.filter(is_deleted=True) return self.none() def discontinued_only(self): """Получить только снятые товары""" if self._has_status_field(): return self.filter(status='discontinued') return self.none() def active_only(self): """Получить только активные товары""" if self._has_status_field(): return self.filter(status='active') elif self._has_is_deleted_field(): return self.filter(is_deleted=False) return self.all() def with_archived(self): """Получить все элементы включая архивированные""" return self.all() class SoftDeleteManager(models.Manager): """ Manager для работы с архивированием товаров. По умолчанию показывает только активные товары/элементы. Поддерживает обе системы: status (новая) и is_deleted/is_active (старая). """ def get_queryset(self): qs = SoftDeleteQuerySet(self.model, using=self._db) # Автоматически фильтруем активные записи в зависимости от полей if hasattr(self.model, 'status'): return qs.filter(status='active') elif hasattr(self.model, 'is_deleted'): return qs.filter(is_deleted=False) elif hasattr(self.model, 'is_active'): return qs.filter(is_active=True) return qs def archived_only(self): """Получить только архивированные товары""" qs = SoftDeleteQuerySet(self.model, using=self._db) if hasattr(self.model, 'status'): return qs.filter(status='archived') elif hasattr(self.model, 'is_deleted'): return qs.filter(is_deleted=True) return qs.none() def discontinued_only(self): """Получить только снятые товары""" qs = SoftDeleteQuerySet(self.model, using=self._db) if hasattr(self.model, 'status'): return qs.filter(status='discontinued') return qs.none() def all_with_archived(self): """Получить все товары включая архивированные""" return SoftDeleteQuerySet(self.model, using=self._db).all()