# Стратегия хранения и обработки изображений ## Обзор системы Система автоматически хранит одно большое оригинальное изображение и создает несколько оптимизированных версий для разных сценариев использования в приложении. **Преимущества:** - ✅ Оригинальное изображение сохраняется в полном качестве - ✅ Автоматическое создание всех размеров при загрузке - ✅ Оптимизация под разные части приложения (списки, карточки, просмотр) - ✅ Быстрая загрузка из-за меньшего размера файлов - ✅ Экономия трафика и дискового пространства --- ## Размеры изображений | Размер | Размер (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 %} {{ product.name }} {% endif %}
{% endfor %}
{% if product.photos.first %} {{ product.name }} {% endif %}
``` ### Комплекты (букеты) ```django {{ kit.name }} {{ kit.name }} {{ kit.name }} ``` ### Категории ```django {{ category.name }} {{ category.name }} ``` --- ## Использование в представлениях (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