django-cleanup

9.0.0 · active · verified Mon Apr 13

django-cleanup is a lightweight Django library that automatically deletes files associated with `FileField` and `ImageField` when their corresponding model instances are deleted or when the file itself is changed. This prevents orphaned files from cluttering storage. It integrates seamlessly into existing Django projects with minimal configuration, supporting bulk deletions and various storage backends (e.g., local filesystem, Amazon S3). The current version is 9.0.0, released on September 18, 2024, and it aims to maintain compatibility with currently supported Django and Python versions.

Warnings

Install

Imports

Quickstart

After installation, add `django_cleanup.apps.CleanupConfig` to your `INSTALLED_APPS`. `django-cleanup` will then automatically handle file deletion for any `FileField` or `ImageField` on your models when a model instance is deleted, or when a file in a field is replaced. No additional code is needed in your models or views for basic functionality.

import os
import django
from django.conf import settings
from django.db import models

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

# Minimal Django settings for demonstration
if not settings.configured:
    settings.configure(
        INSTALLED_APPS=[
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django_cleanup.apps.CleanupConfig',
            'myapp' # Your app where models reside
        ],
        DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},
        MEDIA_ROOT=os.path.join(os.getcwd(), 'media_test'),
        DEFAULT_AUTO_FIELD='django.db.models.AutoField',
    )
django.setup()

# Create a dummy app to hold models
class MyAppConfig(django.apps.AppConfig):
    name = 'myapp'
    label = 'myapp'

# Add dummy app to apps registry
if not django.apps.apps.get_app_config('myapp'):
    django.apps.apps.populate(settings.INSTALLED_APPS)

# Define a simple model with a FileField
class MyModel(models.Model):
    name = models.CharField(max_length=100)
    image = models.ImageField(upload_to='images')

    def __str__(self):
        return self.name

# Ensure media directory exists for testing
os.makedirs(settings.MEDIA_ROOT, exist_ok=True)

# Simulate model usage
print(f"Media root: {settings.MEDIA_ROOT}")

# 1. Create instance and save a dummy file
instance = MyModel(name='Test Item')
# Create a dummy image file
dummy_image_path = os.path.join(settings.MEDIA_ROOT, 'images', 'test_image.jpg')
os.makedirs(os.path.dirname(dummy_image_path), exist_ok=True)
with open(dummy_image_path, 'w') as f:
    f.write('dummy image content')

instance.image.name = 'images/test_image.jpg'
instance.save()
print(f"File exists after creation: {os.path.exists(dummy_image_path)}")

# 2. Update instance with a new file (old one should be deleted)
new_dummy_image_path = os.path.join(settings.MEDIA_ROOT, 'images', 'new_test_image.jpg')
with open(new_dummy_image_path, 'w') as f:
    f.write('new dummy image content')

old_image_name = instance.image.name
instance.image.name = 'images/new_test_image.jpg'
instance.save()

print(f"Old file '{old_image_name}' exists after update: {os.path.exists(os.path.join(settings.MEDIA_ROOT, old_image_name))}")
print(f"New file exists after update: {os.path.exists(new_dummy_image_path)}")

# 3. Delete instance (associated file should be deleted)
instance_pk = instance.pk
instance.delete()

print(f"New file exists after instance deletion: {os.path.exists(new_dummy_image_path)}")

# Clean up test media directory (optional)
import shutil
shutil.rmtree(settings.MEDIA_ROOT)
print("Cleaned up media_test directory.")

view raw JSON →