Проблема была в том, что при сохранении фотографии 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>
91 lines
5.6 KiB
Markdown
91 lines
5.6 KiB
Markdown
# Исправление бага: Подмена фотографий при загрузке
|
||
|
||
## Проблема
|
||
При загрузке новой фотографии к товару она подменялась другой уже существующей фотографией. Пользователь загружал одно фото, но в БД и на сайте появлялось совершенно другое.
|
||
|
||
## Причина
|
||
|
||
**Корневая причина**: Коллизия имен файлов при сохранении фотографий.
|
||
|
||
### Как это происходило:
|
||
|
||
1. Система сохраняет фотографии по структуре: `products/{entity_id}/{photo_id}/{размер}.{расширение}`
|
||
- Пример: `products/2/7/original.jpg`, `products/2/7/large.webp`, и т.д.
|
||
|
||
2. Когда нужно перезаписать фотографию (при обновлении), Django обнаруживает что файл уже существует
|
||
|
||
3. Вместо замены, Django добавляет суффикс коллизии к имени файла:
|
||
- Ожидается: `products/2/3/original.jpg`
|
||
- Реально сохраняется: `products/2/3/original_LxC9yjS.jpg` ← с суффиксом
|
||
|
||
4. **ПРОБЛЕМА**: В БД сохраняется путь БЕЗ суффикса (`products/2/3/original.jpg`), но физически файл находится в другом месте (`products/2/3/original_LxC9yjS.jpg`)
|
||
|
||
5. Когда шаблон запрашивает `{{ photo.image.url }}`, Django ищет файл `products/2/3/original.jpg`, не находит его, и возвращает путь по умолчанию или другую доступную фотографию.
|
||
|
||
## Решение
|
||
|
||
### Шаг 1: Обновлен `image_processor.py`
|
||
|
||
В методе `_save_image_version()` добавлена проверка и удаление старого файла ПЕРЕД сохранением нового:
|
||
|
||
```python
|
||
# ВАЖНО: Удаляем старый файл если он существует, чтобы избежать коллизий имен
|
||
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 устаревших файлов
|
||
|
||
## Файлы, измененные
|
||
|
||
1. **myproject/products/utils/image_processor.py**
|
||
- Добавлена проверка и удаление старого файла перед сохранением нового
|
||
- Добавлено логирование коллизий имен
|
||
|
||
2. **myproject/products/management/commands/cleanup_photo_media.py**
|
||
- Создана management команда для очистки старых файлов (опционально)
|
||
|
||
3. **cleanup_media.py** (в корне проекта)
|
||
- Создан скрипт для ручной очистки старых данных
|
||
|
||
## Как проверить исправление
|
||
|
||
1. Откройте товар с ID 2 (или любой другой товар)
|
||
2. Попробуйте загрузить новое фото
|
||
3. При сохранении фото должно правильно отобразиться
|
||
4. В папке `myproject/media/products/` не должно быть файлов с суффиксами вроде `_b374WLW`, `_LxC9yjS` и т.д.
|
||
|
||
## Технические детали
|
||
|
||
- **Файлы с коллизией**: Django использует функцию `storage.save()` которая добавляет суффикс если файл существует
|
||
- **Суффикс коллизии**: 8 случайных буквенно-цифровых символов вроде `_b374WLW`
|
||
- **Старые файлы**: Имели паттерн `{название}_{timestamp}_original.jpg` (из старой системы)
|
||
|
||
## Результаты
|
||
|
||
✓ Исправлено ошибочное сохранение путей в БД
|
||
✓ Удалены все старые файлы с коллизией имен
|
||
✓ Добавлена проверка при сохранении новых фотографий
|
||
✓ Добавлено логирование для отладки будущих проблем с коллизиями
|
||
|
||
## Рекомендации
|
||
|
||
1. Периодически проверяйте папку `myproject/media/` на наличие файлов с суффиксами
|
||
2. Можно добавить периодическую очистку через Celery или cron
|
||
3. В продакшене рекомендуется использовать облачное хранилище (S3 и т.д.) которое лучше справляется с коллизиями имен
|