fix: Улучшения системы ценообразования комплектов
Исправлены 4 проблемы: 1. Расчёт цены первого товара - улучшена валидация в getProductPrice и calculateFinalPrice 2. Отображение actual_price в Select2 вместо обычной цены 3. Количество по умолчанию = 1 для новых форм компонентов 4. Auto-select текста при клике на поле количества для удобства редактирования Изменённые файлы: - products/forms.py: добавлен __init__ в KitItemForm для quantity.initial = 1 - products/templates/includes/select2-product-init.html: обновлена formatSelectResult - products/templates/productkit_create.html: добавлен focus handler для auto-select - products/templates/productkit_edit.html: добавлен focus handler для auto-select 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
276
PHOTO_QUALITY_SYSTEM_PHASE1.md
Normal file
276
PHOTO_QUALITY_SYSTEM_PHASE1.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# Система оценки качества фотографий товаров - ФАЗА 1 ✅ ЗАВЕРШЕНА
|
||||
|
||||
## Что реализовано
|
||||
|
||||
### 1. Конфигурация в settings.py
|
||||
```python
|
||||
IMAGE_QUALITY_LEVELS = {
|
||||
'excellent': 0.95, # >= 95% от max (если max=2160 → >= 2052px)
|
||||
'good': 0.70, # >= 70% от max (если max=2160 → >= 1512px)
|
||||
'acceptable': 0.40, # >= 40% от max (если max=2160 → >= 864px)
|
||||
'poor': 0.20, # >= 20% от max (если max=2160 → >= 432px)
|
||||
# < 20% = very_poor
|
||||
}
|
||||
|
||||
IMAGE_QUALITY_LABELS = {
|
||||
'excellent': {'label': 'Отлично', 'color': 'success', 'recommendation': '...'},
|
||||
'good': {'label': 'Хорошо', 'color': 'info', 'recommendation': '...'},
|
||||
'acceptable': {'label': 'Приемлемо', 'color': 'warning', 'recommendation': '...'},
|
||||
'poor': {'label': 'Плохо', 'color': 'danger', 'recommendation': '...'},
|
||||
'very_poor': {'label': 'Очень плохо', 'color': 'danger', 'recommendation': '...'},
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Валидатор (validators/image_validators.py)
|
||||
**Полностью гибкий валидатор, который:**
|
||||
- Динамически читает max размеры из `IMAGE_PROCESSING_CONFIG`
|
||||
- Вычисляет пороги как процент от максимума
|
||||
- Определяет уровень качества для любого размера изображения
|
||||
|
||||
**Функции:**
|
||||
```python
|
||||
# Получить максимальный размер из конфиг
|
||||
get_max_dimension_from_config() → 2160
|
||||
|
||||
# Определить качество на основе размеров
|
||||
get_image_quality_level(width, height) → ('good', False)
|
||||
|
||||
# Получить информацию о уровне
|
||||
get_quality_info('excellent') → {label, color, recommendation, ...}
|
||||
|
||||
# Валидация фото для UI
|
||||
validate_product_image(file) → {valid, width, height, quality_level, message, error}
|
||||
```
|
||||
|
||||
**Пример работы:**
|
||||
```python
|
||||
# Если вы загружаете фото 546×546 (а max=2160):
|
||||
quality_level, needs_update = get_image_quality_level(546, 546)
|
||||
# Результат: ('acceptable', False)
|
||||
# Расчет: 546/2160 = 0.253 (25.3%)
|
||||
# 25.3% >= 40%? Нет, >= 20%? Да → poor
|
||||
# На самом деле: 25.3% >= 40%? Нет, но >= 20%? Да → poor
|
||||
# Хм, давайте пересчитаем:
|
||||
# - excellent: 546/2160 = 0.253 >= 0.95? Нет
|
||||
# - good: 0.253 >= 0.70? Нет
|
||||
# - acceptable: 0.253 >= 0.40? Нет
|
||||
# - poor: 0.253 >= 0.20? Да ✓
|
||||
# Результат: ('poor', True) ← требует обновления
|
||||
```
|
||||
|
||||
### 3. Модели (ProductPhoto, ProductKitPhoto, ProductCategoryPhoto)
|
||||
**Добавлены новые поля:**
|
||||
```python
|
||||
quality_level = CharField(
|
||||
choices=[
|
||||
('excellent', 'Отлично (>= 2052px)'),
|
||||
('good', 'Хорошо (1512-2051px)'),
|
||||
('acceptable', 'Приемлемо (864-1511px)'),
|
||||
('poor', 'Плохо (432-863px)'),
|
||||
('very_poor', 'Очень плохо (< 432px)'),
|
||||
],
|
||||
default='acceptable',
|
||||
db_index=True,
|
||||
)
|
||||
|
||||
quality_warning = BooleanField(
|
||||
default=False, # True для poor и very_poor
|
||||
db_index=True,
|
||||
)
|
||||
```
|
||||
|
||||
**Индексы для быстрого поиска:**
|
||||
```python
|
||||
indexes = [
|
||||
models.Index(fields=['quality_level']),
|
||||
models.Index(fields=['quality_warning']),
|
||||
models.Index(fields=['quality_warning', 'product']), # Товары требующие обновления
|
||||
]
|
||||
```
|
||||
|
||||
### 4. Image Processor (image_processor.py)
|
||||
**Обновлен метод process_image:**
|
||||
```python
|
||||
def process_image(image_file, base_path, entity_id, photo_id):
|
||||
# Раньше возвращал:
|
||||
# {'original': '...', 'large': '...', 'medium': '...', 'thumbnail': '...'}
|
||||
|
||||
# Теперь возвращает дополнительно:
|
||||
{
|
||||
'original': '...',
|
||||
'large': '...',
|
||||
'medium': '...',
|
||||
'thumbnail': '...',
|
||||
'width': 1920,
|
||||
'height': 1080,
|
||||
'quality_level': 'excellent',
|
||||
'quality_warning': False,
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Сохранение фото (photos.py -> save())
|
||||
**Автоматическое определение качества:**
|
||||
- При создании нового фото → вычисляет quality_level и quality_warning
|
||||
- При обновлении фото → пересчитывает качество
|
||||
- Сохраняет все три поля atomically в БД
|
||||
|
||||
## Как это работает (пример)
|
||||
|
||||
### Сценарий: Загрузка фото 546×546px
|
||||
|
||||
1. **Пользователь загружает фото** через форму продукта
|
||||
2. **Вызывается ProductPhoto.save()**
|
||||
3. **ImageProcessor.process_image()** обрабатывает фото:
|
||||
- Открывает изображение, получает размеры 546×546
|
||||
- **Вызывает get_image_quality_level(546, 546)**
|
||||
- Вычисляет: max=2160 (из settings), percent=546/2160=0.253
|
||||
- Сравнивает с пороги: 0.253 >= 0.20? **Да** → 'poor'
|
||||
- Возвращает: ('poor', True)
|
||||
- Сохраняет все размеры (original, large, medium, thumb)
|
||||
- Возвращает обработанные пути + quality info
|
||||
4. **ProductPhoto.save()** получает результат:
|
||||
```python
|
||||
processed_paths = {
|
||||
'original': 'products/2/7/original.jpg',
|
||||
'quality_level': 'poor',
|
||||
'quality_warning': True,
|
||||
}
|
||||
```
|
||||
5. **Сохраняет в БД:**
|
||||
```python
|
||||
photo.image = 'products/2/7/original.jpg'
|
||||
photo.quality_level = 'poor'
|
||||
photo.quality_warning = True
|
||||
photo.save()
|
||||
```
|
||||
|
||||
### Результат в БД:
|
||||
```
|
||||
ProductPhoto:
|
||||
- id: 7
|
||||
- product_id: 2
|
||||
- image: products/2/7/original.jpg
|
||||
- quality_level: 'poor' 🔴
|
||||
- quality_warning: True ← Требует обновления!
|
||||
- order: 0
|
||||
```
|
||||
|
||||
## Гибкость конфигурации
|
||||
|
||||
### Пример 1: Вы изменили max_width с 2160 на 3000
|
||||
```python
|
||||
# В settings.py
|
||||
IMAGE_PROCESSING_CONFIG = {
|
||||
'formats': {
|
||||
'original': {
|
||||
'max_width': 3000, # Было 2160
|
||||
'max_height': 3000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Система АВТОМАТИЧЕСКИ пересчитает:
|
||||
# excellent: 0.95 * 3000 = 2850px
|
||||
# good: 0.70 * 3000 = 2100px
|
||||
# acceptable: 0.40 * 3000 = 1200px
|
||||
# poor: 0.20 * 3000 = 600px
|
||||
|
||||
# Код не менялся! ✓
|
||||
```
|
||||
|
||||
### Пример 2: Вы изменили пороги качества
|
||||
```python
|
||||
# Было:
|
||||
IMAGE_QUALITY_LEVELS = {
|
||||
'excellent': 0.95,
|
||||
'good': 0.70,
|
||||
}
|
||||
|
||||
# Стало:
|
||||
IMAGE_QUALITY_LEVELS = {
|
||||
'excellent': 0.90, # Жестче
|
||||
'good': 0.60, # Жестче
|
||||
}
|
||||
|
||||
# Система АВТОМАТИЧЕСКИ переклассифицирует новые загрузки
|
||||
# Старые фото останутся как есть (можно переклассифицировать через management команду)
|
||||
```
|
||||
|
||||
## Что дальше (Фаза 2)
|
||||
|
||||
После создания миграций, нужно реализовать:
|
||||
|
||||
### Phase 2: Admin интерфейс
|
||||
1. **Фильтры в админке**:
|
||||
- По качеству (excellent, good, acceptable, poor, very_poor)
|
||||
- Товары требующие обновления фото (quality_warning=True)
|
||||
|
||||
2. **Визуальные индикаторы**:
|
||||
- Цветные иконки в списке товаров (🟢 Отлично, 🟡 Хорошо, 🟠 Приемлемо, 🔴 Плохо)
|
||||
- Action для поиска товаров требующих обновления
|
||||
|
||||
3. **Админ-дисплеи**:
|
||||
- Форматирование качества в таблицах
|
||||
- Цветные бэджи
|
||||
|
||||
### Phase 3: Фронтенд UI
|
||||
1. **Форма загрузки**:
|
||||
- Preview фото с индикатором качества
|
||||
- Сообщение о рекомендации
|
||||
- Информация о размерах
|
||||
|
||||
2. **Список товаров**:
|
||||
- Иконка качества для каждого фото
|
||||
- Подсказка при наведении
|
||||
|
||||
## Структура файлов (после миграции)
|
||||
|
||||
```
|
||||
myproject/
|
||||
├── myproject/
|
||||
│ └── settings.py ← IMAGE_QUALITY_LEVELS, IMAGE_QUALITY_LABELS
|
||||
├── products/
|
||||
│ ├── models/
|
||||
│ │ └── photos.py ← ProductPhoto, ProductKitPhoto, ProductCategoryPhoto с новыми полями
|
||||
│ ├── validators/
|
||||
│ │ └── image_validators.py ← Новый файл! Вся гибкая логика
|
||||
│ ├── utils/
|
||||
│ │ └── image_processor.py ← Обновлен process_image()
|
||||
│ └── migrations/
|
||||
│ └── XXXX_add_photo_quality_assessment.py ← НУЖНА ВАША МИГРАЦИЯ!
|
||||
```
|
||||
|
||||
## Коммит
|
||||
```
|
||||
622e17a feat: Реализовать систему оценки качества фотографий товаров (Фаза 1)
|
||||
```
|
||||
|
||||
## Следующие шаги
|
||||
|
||||
1. **Создать миграцию** через:
|
||||
```bash
|
||||
python manage.py makemigrations products --name add_photo_quality_assessment
|
||||
```
|
||||
|
||||
2. **Применить миграцию**:
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
3. **Протестировать вычисление качества**:
|
||||
```python
|
||||
python manage.py shell
|
||||
>>> from products.validators.image_validators import get_image_quality_level
|
||||
>>> get_image_quality_level(546, 546)
|
||||
('poor', True)
|
||||
>>> get_image_quality_level(2160, 2160)
|
||||
('excellent', False)
|
||||
```
|
||||
|
||||
4. **Загрузить фото к товару** и проверить что quality_level и quality_warning автоматически заполнены в админке
|
||||
|
||||
5. **Приступить к Фазе 2** - реализовать admin интерфейс
|
||||
|
||||
---
|
||||
|
||||
**Фаза 1 завершена! 🎉 Система полностью готова к расширению.**
|
||||
Reference in New Issue
Block a user