4

There is a similar question here but that is from 2011 and Django 1.2. Many things have changed since then. I'm using Django 1.9.

I'm wondering how should I do this correctly, without any risks of messing up the filesystem. I have an ImageField in a model:

class CartaMagicPy(models.Model):
    imagen = models.ImageField(null=True, upload_to=ubicar_magicpy)

On a first moment, the image is saved. But then, the user crops the image and I get a new image assigned to the same ImageField.

The old image is not deleted from the filesystem. How can I delete it? The problem is that model_object.imagen.path after being updated contains the path to the new image. And if I delete it before I update it with the new image, I risk that maybe the save could fail and then I end up with no image at all. Is there a combination of post-save signals I could use? Any advice will help.

Community
  • 1
  • 1
Alejandro Veintimilla
  • 10,743
  • 23
  • 91
  • 180
  • 2
    Possible duplicate of [How do I get Django Admin to delete files when I remove an object from the database/model?](http://stackoverflow.com/questions/5372934/how-do-i-get-django-admin-to-delete-files-when-i-remove-an-object-from-the-datab) – raphv Jul 06 '16 at 19:49

3 Answers3

8

As seen in this answer, "there's an app for that": django-cleanup.

If you prefer to implement it yourself, the accepted answer to the question @raphv linked in the comment gives some good pointers.

A good solution for updated change followup is to use model signals; I tend to use post_init and post_save, in this case to delete the old image file after the change has been made. Something like so:

from django.db.models.signals import post_init, post_save
from django.dispatch import receiver

from myapp.models import CartaMagicPy


@receiver(post_init, sender= CartaMagicPy)
def backup_image_path(sender, instance, **kwargs):
    instance._current_imagen_file = instance.imagen


@receiver(post_save, sender= CartaMagicPy)
def delete_old_image(sender, instance, **kwargs):
    if hasattr(instance, '_current_imagen_file'):
        if instance._current_imagen_file != instance.imagen.path:
            instance._current_imagen_file.delete(save=False)

This also seems to be generally what the linked package above does, plus some additional safety checks and cleanup.

Community
  • 1
  • 1
tutuDajuju
  • 10,307
  • 6
  • 65
  • 88
1

I am not sure, but you can try this

use Django-cleanup

pip install django-cleanup

settings.py

INSTALLED_APPS = ( ... 'django_cleanup', # should go after your apps ... )

Raj Shah
  • 668
  • 1
  • 9
  • 23
0

We could optimize if the image accepts null values with the following code.

@receiver(post_init, sender= CartaMagicPy)
def backup_image_path(sender, instance, **kwargs):
    instance._current_imagen_file = instance.imagen


@receiver(post_save, sender=CartaMagicPy)
def delete_old_image(sender, instance, **kwargs):
    if hasattr(instance, '_current_imagen_file'):
        if instance.imagen:
            if instance._current_imagen_file != instance.imagen.path:
                instance._current_imagen_file.delete(save=False)
        else:
            if instance._current_imagen_file:
                instance._current_imagen_file.delete()