# Стратегия хранения и обработки изображений
## Обзор системы
Система автоматически хранит одно большое оригинальное изображение и создает несколько оптимизированных версий для разных сценариев использования в приложении.
**Преимущества:**
- ✅ Оригинальное изображение сохраняется в полном качестве
- ✅ Автоматическое создание всех размеров при загрузке
- ✅ Оптимизация под разные части приложения (списки, карточки, просмотр)
- ✅ Быстрая загрузка из-за меньшего размера файлов
- ✅ Экономия трафика и дискового пространства
---
## Размеры изображений
| Размер | Размер (px) | Использование |
|--------|------------|---------------|
| **thumbnail** | 150×150 | Каталоги, списки товаров, сетки |
| **medium** | 400×400 | Карточки товаров, превью в админке |
| **large** | 800×800 | Полноразмерный просмотр на фронте |
| **original** | Без изменений* | Архив, печать, экспорт |
\* *Сохраняется в JPEG с качеством 90 для оптимизации*
---
## Структура хранения файлов
```
media/
├── products/
│ ├── originals/ # Оригинальные изображения товаров
│ │ └── product_name_12345.jpg
│ ├── thumbnails/ # Миниатюры (150x150)
│ │ └── product_name_12345.jpg
│ ├── medium/ # Средние (400x400)
│ │ └── product_name_12345.jpg
│ └── large/ # Большие (800x800)
│ └── product_name_12345.jpg
│
├── kits/
│ ├── originals/ # Оригинальные изображения комплектов
│ ├── thumbnails/
│ ├── medium/
│ └── large/
│
└── categories/
├── originals/ # Оригинальные изображения категорий
├── thumbnails/
├── medium/
└── large/
```
---
## Использование в шаблонах (templates)
### Товары
```django
{% load static %}
{% for product in products %}
{% if product.photos.first %}

{% endif %}
{% endfor %}
{% if product.photos.first %}

{% endif %}
{% for photo in product.photos.all %}
{% endfor %}
```
### Комплекты (букеты)
```django
```
### Категории
```django
```
---
## Использование в представлениях (views)
```python
from products.models import Product, ProductPhoto
def product_detail(request, pk):
product = Product.objects.get(pk=pk)
# Получить первое фото
main_photo = product.photos.first()
if main_photo:
context = {
'product': product,
'thumbnail_url': main_photo.get_thumbnail_url(),
'medium_url': main_photo.get_medium_url(),
'large_url': main_photo.get_large_url(),
'original_url': main_photo.get_original_url(),
}
return render(request, 'product_detail.html', context)
```
---
## API фото моделей
### Методы для получения URL
Каждая фото-модель (`ProductPhoto`, `ProductKitPhoto`, `ProductCategoryPhoto`) имеет методы:
```python
photo = ProductPhoto.objects.first()
# Получить URL нужного размера
photo.get_thumbnail_url() # → /media/products/thumbnails/photo_12345.jpg
photo.get_medium_url() # → /media/products/medium/photo_12345.jpg
photo.get_large_url() # → /media/products/large/photo_12345.jpg
photo.get_original_url() # → /media/products/originals/photo_12345.jpg
# Прямой доступ к изображению
photo.image # → путь к оригиналу в БД
photo.image.url # → URL оригинала
```
### Пример полного использования
```python
from products.models import Product
from products.utils.image_service import ImageService
product = Product.objects.get(pk=1)
photo = product.photos.first()
# Способ 1: через методы модели
thumbnail = photo.get_thumbnail_url()
medium = photo.get_medium_url()
large = photo.get_large_url()
original = photo.get_original_url()
# Способ 2: через ImageService (если нужна большая гибкость)
from products.utils.image_service import ImageService
all_urls = ImageService.get_all_urls(photo.image.name)
# → {
# 'original': '/media/products/originals/...',
# 'thumbnail': '/media/products/thumbnails/...',
# 'medium': '/media/products/medium/...',
# 'large': '/media/products/large/...'
# }
```
---
## Загрузка изображений
### Через админку Django
1. Откройте админку: `http://localhost:8000/admin/`
2. Перейдите в раздел "Товары", "Комплекты" или "Категории"
3. Нажмите на объект или создайте новый
4. В разделе "Фото" нажмите "Добавить фото"
5. Загрузьте изображение (JPEG или PNG)
6. После сохранения система автоматически создаст все размеры
### Процесс при загрузке
1. Система получает загруженное изображение
2. Проверяет его валидность (должно быть JPEG или PNG)
3. Конвертирует в RGB если нужно (для PNG с прозрачностью)
4. Создает 4 версии:
- **original**: сохраняет в JPEG (quality=90)
- **thumbnail**: изменяет размер до 150×150
- **medium**: изменяет размер до 400×400
- **large**: изменяет размер до 800×800
5. Все версии сохраняются в правильные папки
6. В БД хранится путь только к оригиналу
---
## Management команды
### Обработка существующих изображений
Если вы загрузили изображения ДО внедрения этой системы, используйте команду:
```bash
# Обработать все изображения
python manage.py process_images
# Обработать только товары
python manage.py process_images --model ProductPhoto
# Обработать только комплекты
python manage.py process_images --model ProductKitPhoto
# Обработать только категории
python manage.py process_images --model ProductCategoryPhoto
```
Команда:
- Найдет все существующие изображения
- Создаст все недостающие размеры
- Покажет прогресс обработки
- Выведет количество успешно обработанных и ошибок
---
## Автоматическое удаление
При удалении фото все его версии удаляются автоматически:
```python
photo = ProductPhoto.objects.get(pk=1)
photo.delete() # Удалит оригинал + thumbnail + medium + large
```
Это происходит благодаря переопределенному методу `delete()` в моделях.
---
## Обновление изображения
При загрузке нового изображения для существующего фото:
1. Система обнаруживает, что `image` поле изменилось
2. Старые версии удаляются (оригинал + все размеры)
3. Создаются новые версии для нового изображения
```python
photo = ProductPhoto.objects.get(pk=1)
photo.image = request.FILES['new_image']
photo.save() # Старые версии удалены, созданы новые
```
---
## Оптимизация и производительность
### Как работает кэширование путей
URL изображения рассчитывается динамически на основе пути к оригиналу:
```
Оригинал: products/originals/flower_12345.jpg
↓ Динамический расчет пути
Миниатюра: products/thumbnails/flower_12345.jpg
Средний: products/medium/flower_12345.jpg
Большой: products/large/flower_12345.jpg
```
Это не требует хранения 4 путей в БД - экономим место и упрощаем код.
### Параметры сжатия
- **Алгоритм**: LANCZOS (лучше всего сохраняет качество)
- **Качество JPEG**: 90 (оптимальный баланс между качеством и размером)
- **Оптимизация**: включена (`optimize=True`)
---
## Типичные размеры файлов
При загрузке изображения 2000×2000 px (∼2-3 МБ):
| Версия | Размер | Экономия |
|--------|--------|---------|
| original | ∼150-200 КБ | - |
| thumbnail | ∼5-8 КБ | 95% |
| medium | ∼15-25 КБ | 85% |
| large | ∼50-80 КБ | 65% |
| **Итого** | **∼230-310 КБ** | **~90%** |
---
## Возможные доработки в будущем
1. **Redis кэш URL**: кэшировать сгенерированные URL для еще большей производительности
2. **WebP формат**: сохранять в WebP для еще большей оптимизации
3. **Responsive images**: служить разные размеры в зависимости от устройства
4. **CDN интеграция**: заливать изображения на CDN для быстрой доставки
5. **Водяной знак**: добавлять водяной знак при экспорте
6. **Batch обработка**: обрабатывать несколько изображений параллельно
---
## Решение проблем
### Изображение не показывается в админке
Проверьте:
1. Изображение загружено (есть путь в БД)
2. MEDIA_URL и MEDIA_ROOT настроены правильно в settings.py
3. Django runserver запущен (в продакшене нужно настроить serving)
### Некоторые размеры не созданы
Запустите management команду:
```bash
python manage.py process_images
```
### Слишком долгая загрузка изображения
- Проверьте размер загружаемого файла (обычно <5 МБ)
- На сервере может быть медленнее - это нормально
- Рассмотрите асинхронную обработку через Celery (будущая доработка)
---
## Версия и требования
- Django 5.2+
- Pillow (любая последняя версия)
- Python 3.8+
---
## История изменений
### v1.0 (2025-10-22)
- Первая версия системы хранения изображений
- Поддержка товаров, комплектов и категорий
- Автоматическое создание 4 размеров
- Management команда для обработки существующих данных
- Интеграция с админкой Django