{"id":5185,"library":"django-cleanup","title":"django-cleanup","description":"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.","status":"active","version":"9.0.0","language":"en","source_language":"en","source_url":"https://github.com/un1t/django-cleanup","tags":["django","files","cleanup","storage","orm","automatic-file-management"],"install":[{"cmd":"pip install django-cleanup","lang":"bash","label":"Install via pip"}],"dependencies":[{"reason":"Core framework dependency, follows Django's supported versions.","package":"Django","optional":false},{"reason":"Runtime environment","package":"python","optional":false,"version_constraint":">=3.8"}],"imports":[{"note":"Primary configuration is via settings.py. For versions 8.x and earlier, 'django_cleanup' was sufficient. For 9.0.0 and later, it is recommended to use 'django_cleanup.apps.CleanupConfig'.","symbol":"django_cleanup","correct":"INSTALLED_APPS = ['...', 'django_cleanup']"},{"note":"While 'django_cleanup' still works, explicit use of CleanupConfig is generally recommended for application configuration classes in modern Django. The GitHub README for v9.0.0 explicitly shows 'django_cleanup.apps.CleanupConfig'.","wrong":"INSTALLED_APPS = ['...', 'django_cleanup'] # For v9.0.0+","symbol":"CleanupConfig","correct":"INSTALLED_APPS = ['...', 'django_cleanup.apps.CleanupConfig']"},{"note":"Signals can be imported for custom interactions before or after a file is deleted by django-cleanup.","symbol":"cleanup_pre_delete, cleanup_post_delete","correct":"from django_cleanup.signals import cleanup_pre_delete, cleanup_post_delete"}],"quickstart":{"code":"import os\nimport django\nfrom django.conf import settings\nfrom django.db import models\n\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')\n\n# Minimal Django settings for demonstration\nif not settings.configured:\n    settings.configure(\n        INSTALLED_APPS=[\n            'django.contrib.auth',\n            'django.contrib.contenttypes',\n            'django_cleanup.apps.CleanupConfig',\n            'myapp' # Your app where models reside\n        ],\n        DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},\n        MEDIA_ROOT=os.path.join(os.getcwd(), 'media_test'),\n        DEFAULT_AUTO_FIELD='django.db.models.AutoField',\n    )\ndjango.setup()\n\n# Create a dummy app to hold models\nclass MyAppConfig(django.apps.AppConfig):\n    name = 'myapp'\n    label = 'myapp'\n\n# Add dummy app to apps registry\nif not django.apps.apps.get_app_config('myapp'):\n    django.apps.apps.populate(settings.INSTALLED_APPS)\n\n# Define a simple model with a FileField\nclass MyModel(models.Model):\n    name = models.CharField(max_length=100)\n    image = models.ImageField(upload_to='images')\n\n    def __str__(self):\n        return self.name\n\n# Ensure media directory exists for testing\nos.makedirs(settings.MEDIA_ROOT, exist_ok=True)\n\n# Simulate model usage\nprint(f\"Media root: {settings.MEDIA_ROOT}\")\n\n# 1. Create instance and save a dummy file\ninstance = MyModel(name='Test Item')\n# Create a dummy image file\ndummy_image_path = os.path.join(settings.MEDIA_ROOT, 'images', 'test_image.jpg')\nos.makedirs(os.path.dirname(dummy_image_path), exist_ok=True)\nwith open(dummy_image_path, 'w') as f:\n    f.write('dummy image content')\n\ninstance.image.name = 'images/test_image.jpg'\ninstance.save()\nprint(f\"File exists after creation: {os.path.exists(dummy_image_path)}\")\n\n# 2. Update instance with a new file (old one should be deleted)\nnew_dummy_image_path = os.path.join(settings.MEDIA_ROOT, 'images', 'new_test_image.jpg')\nwith open(new_dummy_image_path, 'w') as f:\n    f.write('new dummy image content')\n\nold_image_name = instance.image.name\ninstance.image.name = 'images/new_test_image.jpg'\ninstance.save()\n\nprint(f\"Old file '{old_image_name}' exists after update: {os.path.exists(os.path.join(settings.MEDIA_ROOT, old_image_name))}\")\nprint(f\"New file exists after update: {os.path.exists(new_dummy_image_path)}\")\n\n# 3. Delete instance (associated file should be deleted)\ninstance_pk = instance.pk\ninstance.delete()\n\nprint(f\"New file exists after instance deletion: {os.path.exists(new_dummy_image_path)}\")\n\n# Clean up test media directory (optional)\nimport shutil\nshutil.rmtree(settings.MEDIA_ROOT)\nprint(\"Cleaned up media_test directory.\")","lang":"python","description":"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."},"warnings":[{"fix":"Ensure 'django_cleanup.apps.CleanupConfig' is the last entry in `INSTALLED_APPS` in your `settings.py`.","message":"The `django_cleanup.apps.CleanupConfig` must be placed *last* in your `INSTALLED_APPS` setting. This ensures that it can correctly discover all `FileField`s across all your applications and that file deletion integrity within transactions is maintained, even if other apps' signal handlers raise exceptions.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use a transactional database. If not possible, ensure robust backup strategies and understand the implications of rollbacks on file integrity. Consider alternative manual cleanup solutions if this is a critical concern.","message":"If your project uses a database that does not support transactions, or if a transaction rolls back, files *may* be lost without their corresponding model instance being fully deleted or updated. While `django-cleanup` mitigates this using `post_save` and `post_delete` signals, it's a known limitation to be aware of if your database setup is unusual.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure all models within your Django apps are correctly defined or imported within their respective `models.py` or `models/__init__.py` files to guarantee they are registered with Django's ORM.","message":"`django-cleanup` relies on Django's application registry to discover models and their `FileField`s. If your models are not properly loaded (e.g., if they are not defined or imported in your app's `models.py` or `models/__init__.py`), `django-cleanup` may not be able to discover them and thus won't remove files as expected.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Be aware that default files are not managed. If a file associated with a `FileField` needs to be cleaned up, it should not be set as the field's `default`.","message":"Files that are explicitly set as a `FileField`'s `default` value will *not* be deleted by `django-cleanup`. This is by design to prevent accidental deletion of common default files that might be referenced by many instances.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-13T00:00:00.000Z","next_check":"2026-07-12T00:00:00.000Z"}