From 26146ac639721e915ad63111dbd4cd8fc05e5807 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Sun, 23 Nov 2025 21:42:21 +0300 Subject: [PATCH] Add automatic cleanup of empty photo directories after deletion. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When photos are deleted, now automatically removes empty photo_id directories after all image versions are removed. Uses safe empty directory checks and handles tenant-aware file storage correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- myproject/products/utils/image_processor.py | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/myproject/products/utils/image_processor.py b/myproject/products/utils/image_processor.py index 8b33cca..9498c13 100644 --- a/myproject/products/utils/image_processor.py +++ b/myproject/products/utils/image_processor.py @@ -293,10 +293,43 @@ class ImageProcessor: logger.info(f"Saved {image_format} image: {saved_path} (quality: {quality})") return saved_path + @staticmethod + def _cleanup_empty_directory(dir_path): + """ + Удаляет директорию, если она пуста. Используется для очистки после удаления файлов. + + Args: + dir_path: Путь к директории относительно MEDIA_ROOT (без tenant_id префикса) + + Returns: + bool: True если директория была удалена, False иначе + """ + if not dir_path: + return False + + try: + # Получаем полный путь с учетом tenant_id (TenantAwareFileSystemStorage добавляет его) + full_path = default_storage.path(dir_path) + + # Проверяем что путь существует и это директория + if os.path.isdir(full_path): + # Проверяем что директория пуста + if not os.listdir(full_path): + os.rmdir(full_path) + logger.info(f"Removed empty directory: {dir_path}") + return True + else: + logger.debug(f"Directory not empty, skipping: {dir_path}") + return False + except Exception as e: + logger.warning(f"Could not remove directory {dir_path}: {str(e)}") + return False + @staticmethod def delete_all_versions(base_path, original_image_path, entity_id=None, photo_id=None): """ Удаляет все версии изображения (original, large, medium, thumb). + После удаления всех файлов удаляет пустую директорию photo_id. Args: base_path: Базовый путь (например, 'products') @@ -332,3 +365,7 @@ class ImageProcessor: logger.warning(f"File not found: {file_path}") except Exception as e: logger.error(f"Error deleting {file_path}: {str(e)}", exc_info=True) + + # Очищаем пустую директорию фотографии (photo_id) + photo_dir = f"{base_path}/{entity_id}/{photo_id}" + ImageProcessor._cleanup_empty_directory(photo_dir)