import os from django.core.management.base import BaseCommand from apps.parks.models import ParkPhoto from apps.rides.models import RidePhoto from django.conf import settings import shutil class Command(BaseCommand): help = "Move photo files to their normalized locations" def handle(self, *args, **kwargs): self.stdout.write("Moving photo files to normalized locations...") # Get all photos park_photos = ParkPhoto.objects.all() ride_photos = RidePhoto.objects.all() # Track processed files to clean up later processed_files = set() # Process park photos for photo in park_photos: try: # Get current file path current_name = photo.image.name current_path = os.path.join(settings.MEDIA_ROOT, current_name) # Try to find the actual file if not os.path.exists(current_path): # Check if file exists in the old location structure parts = current_name.split("/") if len(parts) >= 2: content_type = "park" identifier = photo.park.slug # Look for any files in that directory old_dir = os.path.join( settings.MEDIA_ROOT, content_type, identifier ) if os.path.exists(old_dir): files = [ f for f in os.listdir(old_dir) if not f.startswith(".") # Skip hidden files and not f.startswith("tmp") # Skip temp files and os.path.isfile(os.path.join(old_dir, f)) ] if files: current_path = os.path.join(old_dir, files[0]) # Skip if file still not found if not os.path.exists(current_path): self.stdout.write(f"Skipping {current_name} - file not found") continue # Get content type and object content_type_model = "park" obj = photo.park identifier = getattr(obj, "slug", obj.id) # Get photo number photo_number = ParkPhoto.objects.filter( park=photo.park, created_at__lte=photo.created_at, ).count() # Create new filename _, ext = os.path.splitext(current_path) if not ext: ext = ".jpg" ext = ext.lower() new_filename = f"{identifier}_{photo_number}{ext}" # Create new path new_relative_path = f"{content_type_model}/{identifier}/{new_filename}" new_full_path = os.path.join(settings.MEDIA_ROOT, new_relative_path) # Create directory if it doesn't exist os.makedirs(os.path.dirname(new_full_path), exist_ok=True) # Move the file if current_path != new_full_path: shutil.copy2( current_path, new_full_path ) # Use copy2 to preserve metadata processed_files.add(current_path) else: processed_files.add(current_path) # Update database photo.image.name = new_relative_path photo.save() self.stdout.write(f"Moved {current_name} to {new_relative_path}") except Exception as e: self.stdout.write(f"Error moving park photo {photo.id}: {str(e)}") continue # Process ride photos for photo in ride_photos: try: # Get current file path current_name = photo.image.name current_path = os.path.join(settings.MEDIA_ROOT, current_name) # Try to find the actual file if not os.path.exists(current_path): # Check if file exists in the old location structure parts = current_name.split("/") if len(parts) >= 2: content_type = parts[0] # 'park' or 'ride' identifier = parts[1] # e.g., 'alton-towers' # Look for any files in that directory old_dir = os.path.join( settings.MEDIA_ROOT, content_type, identifier ) if os.path.exists(old_dir): files = [ f for f in os.listdir(old_dir) if not f.startswith(".") # Skip hidden files and not f.startswith("tmp") # Skip temp files and os.path.isfile(os.path.join(old_dir, f)) ] if files: current_path = os.path.join(old_dir, files[0]) # Skip if file still not found if not os.path.exists(current_path): self.stdout.write(f"Skipping {current_name} - file not found") continue # Get content type and object content_type_model = "ride" obj = photo.ride identifier = getattr(obj, "slug", obj.id) # Get photo number photo_number = RidePhoto.objects.filter( ride=photo.ride, created_at__lte=photo.created_at, ).count() # Create new filename _, ext = os.path.splitext(current_path) if not ext: ext = ".jpg" ext = ext.lower() new_filename = f"{identifier}_{photo_number}{ext}" # Create new path new_relative_path = f"{content_type_model}/{identifier}/{new_filename}" new_full_path = os.path.join(settings.MEDIA_ROOT, new_relative_path) # Create directory if it doesn't exist os.makedirs(os.path.dirname(new_full_path), exist_ok=True) # Move the file if current_path != new_full_path: shutil.copy2( current_path, new_full_path ) # Use copy2 to preserve metadata processed_files.add(current_path) else: processed_files.add(current_path) # Update database photo.image.name = new_relative_path photo.save() self.stdout.write(f"Moved {current_name} to {new_relative_path}") except Exception as e: self.stdout.write(f"Error moving ride photo {photo.id}: {str(e)}") continue # Clean up old files self.stdout.write("Cleaning up old files...") for content_type in ["park", "ride"]: base_dir = os.path.join(settings.MEDIA_ROOT, content_type) if os.path.exists(base_dir): for root, dirs, files in os.walk(base_dir): for file in files: file_path = os.path.join(root, file) if file_path not in processed_files: try: os.remove(file_path) self.stdout.write(f"Removed old file: {file_path}") except Exception as e: self.stdout.write( f"Error removing {file_path}: {str(e)}" ) self.stdout.write("Finished moving photo files and cleaning up")