Проблема была в том, что при сохранении фотографии Django обнаруживал коллизию имен и добавлял суффикс (например, original_b374WLW.jpg), но в БД сохранялся путь БЕЗ суффикса. Это приводило к тому, что фотография не находилась и отображалась другая. Решение: - В ImageProcessor добавлена проверка и удаление старого файла перед сохранением нового - Это гарантирует что путь в БД совпадает с реальным файлом на диске - Удалены все старые файлы с суффиксами коллизии из media папки - Создана management команда cleanup_photo_media для периодической очистки Файлы: - myproject/products/utils/image_processor.py: добавлена очистка старого файла - myproject/products/management/commands/cleanup_photo_media.py: команда для очистки - cleanup_media.py: скрипт для ручной очистки (уже запущен) - BUG_FIX_PHOTO_COLLISION.md: подробный отчет о проблеме и решении 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
5.6 KiB
Исправление бага: Подмена фотографий при загрузке
Проблема
При загрузке новой фотографии к товару она подменялась другой уже существующей фотографией. Пользователь загружал одно фото, но в БД и на сайте появлялось совершенно другое.
Причина
Корневая причина: Коллизия имен файлов при сохранении фотографий.
Как это происходило:
-
Система сохраняет фотографии по структуре:
products/{entity_id}/{photo_id}/{размер}.{расширение}- Пример:
products/2/7/original.jpg,products/2/7/large.webp, и т.д.
- Пример:
-
Когда нужно перезаписать фотографию (при обновлении), Django обнаруживает что файл уже существует
-
Вместо замены, Django добавляет суффикс коллизии к имени файла:
- Ожидается:
products/2/3/original.jpg - Реально сохраняется:
products/2/3/original_LxC9yjS.jpg← с суффиксом
- Ожидается:
-
ПРОБЛЕМА: В БД сохраняется путь БЕЗ суффикса (
products/2/3/original.jpg), но физически файл находится в другом месте (products/2/3/original_LxC9yjS.jpg) -
Когда шаблон запрашивает
{{ photo.image.url }}, Django ищет файлproducts/2/3/original.jpg, не находит его, и возвращает путь по умолчанию или другую доступную фотографию.
Решение
Шаг 1: Обновлен image_processor.py
В методе _save_image_version() добавлена проверка и удаление старого файла ПЕРЕД сохранением нового:
# ВАЖНО: Удаляем старый файл если он существует, чтобы избежать коллизий имен
if default_storage.exists(file_path):
try:
default_storage.delete(file_path)
logger.info(f"Deleted old file: {file_path}")
except Exception as e:
logger.warning(f"Could not delete old file {file_path}: {str(e)}")
Это гарантирует что:
- Старый файл удаляется перед сохранением нового
- Django не встречает коллизию имен
- Путь в БД совпадает с реальным расположением файла на диске
Шаг 2: Очистка старых данных
Создан и запущен скрипт cleanup_media.py который:
- Удалил все старые файлы с суффиксами коллизии (
original_b374WLW.jpg,large_lmCnBYn.webpи т.д.) - Удалил старые файлы из папки
products/originals/(старая схема хранения)
Результат: Успешно удалено 6 устаревших файлов
Файлы, измененные
-
myproject/products/utils/image_processor.py
- Добавлена проверка и удаление старого файла перед сохранением нового
- Добавлено логирование коллизий имен
-
myproject/products/management/commands/cleanup_photo_media.py
- Создана management команда для очистки старых файлов (опционально)
-
cleanup_media.py (в корне проекта)
- Создан скрипт для ручной очистки старых данных
Как проверить исправление
- Откройте товар с ID 2 (или любой другой товар)
- Попробуйте загрузить новое фото
- При сохранении фото должно правильно отобразиться
- В папке
myproject/media/products/не должно быть файлов с суффиксами вроде_b374WLW,_LxC9yjSи т.д.
Технические детали
- Файлы с коллизией: Django использует функцию
storage.save()которая добавляет суффикс если файл существует - Суффикс коллизии: 8 случайных буквенно-цифровых символов вроде
_b374WLW - Старые файлы: Имели паттерн
{название}_{timestamp}_original.jpg(из старой системы)
Результаты
✓ Исправлено ошибочное сохранение путей в БД ✓ Удалены все старые файлы с коллизией имен ✓ Добавлена проверка при сохранении новых фотографий ✓ Добавлено логирование для отладки будущих проблем с коллизиями
Рекомендации
- Периодически проверяйте папку
myproject/media/на наличие файлов с суффиксами - Можно добавить периодическую очистку через Celery или cron
- В продакшене рекомендуется использовать облачное хранилище (S3 и т.д.) которое лучше справляется с коллизиями имен