Улучшение системы работы с фото: добавлена команда очистки битых записей и оптимизация обработки изображений

This commit is contained in:
2026-01-06 09:25:37 +03:00
parent 0f19542ac9
commit 288716deba
14 changed files with 535 additions and 122 deletions

View File

@@ -4,6 +4,7 @@
"""
from abc import abstractmethod
from django.db import models
from django.db.models import Q
from django.utils import timezone
@@ -73,14 +74,25 @@ class BasePhoto(models.Model):
Паттерн: Template Method
- Общие методы save(), delete() и get_*_url() определены здесь
- Специфичные детали (related entity, upload path) задаются через абстрактные методы
Главное фото:
- is_main=True определяет главное фото (используется в карточках, каталоге, превью)
- Constraint уникальности (только одно is_main=True на сущность) реализован в дочерних классах
- order используется для сортировки остальных фото
"""
image = models.ImageField(verbose_name="Оригинальное фото")
is_main = models.BooleanField(
default=False,
db_index=True,
verbose_name="Главное фото",
help_text="Главное фото отображается в карточках, каталоге и превью. Может быть только одно."
)
order = models.PositiveIntegerField(default=0, verbose_name="Порядок")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
class Meta:
abstract = True
ordering = ['order', '-created_at']
ordering = ['-is_main', 'order', '-created_at'] # Главное фото всегда первое
@abstractmethod
def get_entity(self):
@@ -319,12 +331,19 @@ class ProductPhoto(BasePhoto):
class Meta:
verbose_name = "Фото товара"
verbose_name_plural = "Фото товаров"
ordering = ['order', '-created_at']
ordering = ['-is_main', 'order', '-created_at']
indexes = [
models.Index(fields=['quality_level']),
models.Index(fields=['quality_warning']),
models.Index(fields=['quality_warning', 'product']), # Для поиска товаров требующих обновления фото
]
constraints = [
models.UniqueConstraint(
fields=['product'],
condition=Q(is_main=True),
name='unique_main_photo_per_product'
)
]
def __str__(self):
return f"Фото для {self.product.name} ({self.get_quality_level_display()})"
@@ -386,12 +405,19 @@ class ProductKitPhoto(BasePhoto):
class Meta:
verbose_name = "Фото комплекта"
verbose_name_plural = "Фото комплектов"
ordering = ['order', '-created_at']
ordering = ['-is_main', 'order', '-created_at']
indexes = [
models.Index(fields=['quality_level']),
models.Index(fields=['quality_warning']),
models.Index(fields=['quality_warning', 'kit']),
]
constraints = [
models.UniqueConstraint(
fields=['kit'],
condition=Q(is_main=True),
name='unique_main_photo_per_kit'
)
]
def __str__(self):
return f"Фото для {self.kit.name} ({self.get_quality_level_display()})"
@@ -453,12 +479,19 @@ class ProductCategoryPhoto(BasePhoto):
class Meta:
verbose_name = "Фото категории"
verbose_name_plural = "Фото категорий"
ordering = ['order', '-created_at']
ordering = ['-is_main', 'order', '-created_at']
indexes = [
models.Index(fields=['quality_level']),
models.Index(fields=['quality_warning']),
models.Index(fields=['quality_warning', 'category']),
]
constraints = [
models.UniqueConstraint(
fields=['category'],
condition=Q(is_main=True),
name='unique_main_photo_per_category'
)
]
def __str__(self):
return f"Фото для {self.category.name} ({self.get_quality_level_display()})"