Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# (c) 2018-2020
2# MPIB <https://www.mpib-berlin.mpg.de/>,
3# MPI-CBS <https://www.cbs.mpg.de/>,
4# MPIP <http://www.psych.mpg.de/>
5#
6# This file is part of Castellum.
7#
8# Castellum is free software; you can redistribute it and/or modify it
9# under the terms of the GNU Affero General Public License as published
10# by the Free Software Foundation; either version 3 of the License, or
11# (at your option) any later version.
12#
13# Castellum is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16# Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public
19# License along with Castellum. If not, see
20# <http://www.gnu.org/licenses/>.
22"""
23Since Django 1.3, media files are no longer deleted with the
24corresponding model.
26https://docs.djangoproject.com/en/stable/releases/1.3/#deleting-a-model-doesn-t-delete-associated-files
27"""
30import os
32from django.apps import apps
33from django.conf import settings
34from django.core.management.base import BaseCommand
35from django.db.models import FileField
38def iter_models():
39 for app_config in apps.get_app_configs():
40 for model in app_config.get_models():
41 yield model
44def iter_file_fields(model):
45 for field in model._meta.get_fields():
46 if isinstance(field, FileField):
47 yield field
50def iter_media_files():
51 for root, dirs, files in os.walk(settings.MEDIA_ROOT):
52 for filename in files:
53 yield os.path.join(root, filename)
56def get_used_files():
57 files = []
58 for model in iter_models():
59 for field in iter_file_fields(model):
60 files += model.objects.values_list(field.name, flat=True)
61 return [os.path.join(settings.MEDIA_ROOT, f) for f in files if f]
64class Command(BaseCommand):
65 help = 'Remove unused uploaded files.'
67 def handle(self, *args, **options):
68 used_files = get_used_files()
69 for path in iter_media_files():
70 if path not in used_files:
71 print('Deleting', path)
72 os.unlink(path)