How to get Django admin to delete files when deleting an object from a database / model?

I use 1.2.5 with the standard ImageField and use the built-in storage server. Files load normally, but when I delete an entry from admin, the actual file on the server is not deleted.

+72
file django django-models storage imagefield
Mar 21 '11 at 1:19
source share
12 answers

You can get a pre_delete or post_delete (see @toto_tico's comment below) and call the delete method on the FileField object this way (in models.py):

 class MyModel(models.Model): file = models.FileField() ... # Receive the pre_delete signal and delete the file associated with the model instance. from django.db.models.signals import pre_delete from django.dispatch.dispatcher import receiver @receiver(pre_delete, sender=MyModel) def mymodel_delete(sender, instance, **kwargs): # Pass false so FileField doesn't save the model. instance.file.delete(False) 
+84
Jan 14 '13 at 1:11
source share

Django 1.5 solution: I use post_delete for various reasons that are internal to my application.

 from django.db.models.signals import post_delete from django.dispatch import receiver @receiver(post_delete, sender=Photo) def photo_post_delete_handler(sender, **kwargs): photo = kwargs['instance'] storage, path = photo.original_image.storage, photo.original_image.path storage.delete(path) 

I am stuck at the bottom of the models.py file.

the original_image field is an ImageField in my Photo model.

+32
May 08 '13 at 14:15
source share

Try django-cleanup

 pip install django-cleanup 

settings.py

 INSTALLED_APPS = ( ... 'django_cleanup', # should go after your apps ) 
+29
Mar 17 '15 at 17:21
source share

This code works well on Django 1.4 also with the Admin panel.

 class ImageModel(models.Model): image = ImageField(...) def delete(self, *args, **kwargs): # You have to prepare what you need before delete the model storage, path = self.image.storage, self.image.path # Delete the model before the file super(ImageModel, self).delete(*args, **kwargs) # Delete the file after the model storage.delete(path) 

It is important to get the repository and the path to deleting the model, or the latter will be saved in case it is deleted.

+17
Jul 04 2018-12-12T00:
source share

You need to delete the actual file with delete and update .

 from django.db import models class MyImageModel(models.Model): image = models.ImageField(upload_to='images') def remove_on_image_update(self): try: # is the object in the database yet? obj = MyImageModel.objects.get(id=self.id) except MyImageModel.DoesNotExist: # object is not in db, nothing to worry about return # is the save due to an update of the actual image file? if obj.image and self.image and obj.image != self.image: # delete the old image file from the storage in favor of the new file obj.image.delete() def delete(self, *args, **kwargs): # object is being removed from db, remove the file from storage first self.image.delete() return super(MyImageModel, self).delete(*args, **kwargs) def save(self, *args, **kwargs): # object is possibly being updated, if so, clean up. self.remove_on_image_update() return super(MyImageModel, self).save(*args, **kwargs) 
+7
Sep 18 '15 at 1:30
source share

You can use the pre_delete or post_delete signal:

https://docs.djangoproject.com/en/dev/topics/signals/

Of course, the same reasons that the automatic removal of FileField was removed also apply here. If you delete the file referenced elsewhere, you will have problems.

In my case, this seemed appropriate, because I had a special file model to manage all my files.

Note. For some reason post_delete does not work correctly. The file was deleted, but the database record remained, which is exactly the opposite of what I would expect, even in the face of errors. pre_delete works fine though.

+6
Nov 08 '11 at 16:50
source share

Maybe a little late. But the easiest way for me is to use the post_save signal. Just remember that signals are excluded even during the QuerySet deletion process, but the [model] .delete () method is not excluded during the QuerySet deletion process, so it is not the best option to cancel it.

kernel /models.py:

 from django.db import models from django.db.models.signals import post_delete from core.signals import delete_image_slide SLIDE1_IMGS = 'slide1_imgs/' class Slide1(models.Model): title = models.CharField(max_length = 200) description = models.CharField(max_length = 200) image = models.ImageField(upload_to = SLIDE1_IMGS, null = True, blank = True) video_embed = models.TextField(null = True, blank = True) enabled = models.BooleanField(default = True) """---------------------------- SLIDE 1 -------------------------------------""" post_delete.connect(delete_image_slide, Slide1) """--------------------------------------------------------------------------""" 

core /signals.py

 import os def delete_image_slide(sender, **kwargs): slide = kwargs.get('instance') try: os.remove(slide.image.path) except: pass 
+2
Aug 16 '13 at 2:26
source share

This functionality will be removed in Django 1.3, so I would not rely on it.

You can override the delete method of the model in question to delete the file before completely deleting the record from the database.

Edit:

Here is a brief example.

 class MyModel(models.Model): self.somefile = models.FileField(...) def delete(self, *args, **kwargs): somefile.delete() super(MyModel, self).delete(*args, **kwargs) 
+1
Mar 21 2018-11-11T00:
source share

Using post_delete is definitely the right way. Sometimes, although everything may go wrong, and the files are not deleted. Of course, you have a bunch of old files that were not deleted before using post_delete. I created a function that deletes files for objects based on if the object reference file does not exist, then delete the object if the file does not have an object and then delete, it can also be deleted based on the "active" flag for object .. Something I added to most of my models. You must give it the objects you want to check, the path to the object files, the file field and the flag to delete inactive objects:

 def cleanup_model_objects(m_objects, model_path, file_field='image', clear_inactive=False): # PART 1 ------------------------- INVALID OBJECTS #Creates photo_file list based on photo path, takes all files there model_path_list = os.listdir(model_path) #Gets photo image path for each photo object model_files = list() invalid_files = list() valid_files = list() for obj in m_objects: exec("f = ntpath.basename(obj." + file_field + ".path)") # select the appropriate file/image field model_files.append(f) # Checks for valid and invalid objects (using file path) if f not in model_path_list: invalid_files.append(f) obj.delete() else: valid_files.append(f) print "Total objects", len(model_files) print "Valid objects:", len(valid_files) print "Objects without file deleted:", len(invalid_files) # PART 2 ------------------------- INVALID FILES print "Files in model file path:", len(model_path_list) #Checks for valid and invalid files invalid_files = list() valid_files = list() for f in model_path_list: if f not in model_files: invalid_files.append(f) else: valid_files.append(f) print "Valid files:", len(valid_files) print "Files without model object to delete:", len(invalid_files) for f in invalid_files: os.unlink(os.path.join(model_path, f)) # PART 3 ------------------------- INACTIVE PHOTOS if clear_inactive: #inactive_photos = Photo.objects.filter(active=False) inactive_objects = m_objects.filter(active=False) print "Inactive Objects to Delete:", inactive_objects.count() for obj in inactive_objects: obj.delete() print "Done cleaning model." 

Here is how you can use it:

 photos = Photo.objects.all() photos_path, tail = ntpath.split(photos[0].image.path) # Gets dir of photos path, this may be different for you print "Photos -------------->" cleanup_model_objects(photos, photos_path, file_field='image', clear_inactive=False) # image file is default 
+1
Jun 05 '14 at 23:22
source share

make sure you write " self " before the file. so the example above should be

 def delete(self, *args, **kwargs): self.somefile.delete() super(MyModel, self).delete(*args, **kwargs) 

I forgot the ā€œIā€ in front of my file, and this did not work, because it was viewed in the global namespace.

0
Mar 27 '13 at 17:15
source share

If you already have the number of unused files in your project and you want to delete them, you can use the django utility django-unused-media

0
Jan 11 '17 at 18:50
source share

I may have a special case, since I use the upload_to parameter in my field with the names of dynamic directories, but the solution I found is to use os.rmdir.

In models:

 import os 

...

 class Some_Model(models.Model): save_path = models.CharField(max_length=50) ... def delete(self, *args,**kwargs): os.rmdir(os.path.join(settings.MEDIA_ROOT, self.save_path) super(Some_Model,self).delete(*args, **kwargs) 
-one
Feb 17 '13 at 23:01
source share



All Articles