J
J
Jekson2018-10-22 09:22:50
Django
Jekson, 2018-10-22 09:22:50

How to properly set post_save signal to delete an image?

There is a model with the img field (user photo)

class Profile(models.Model):
    img = models.ImageField(upload_to=user_directory_path, verbose_name='Ваше фото')

# user image file will be uploaded to
def user_directory_path(instance, filename):
    return 'images/{0}/{1}'.format(instance.name, filename)

I want to setup deleting the old file in the img field when the user uploads a new avatar. To do this, I made signals
# Delete old profile img file
@receiver(post_init, sender=Profile)
def backup_image_path(sender, instance, **kwargs):
    if instance.img:
        instance._current_imagen_file = instance.img

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

If you upload a new photo, then the old one is deleted, but if I don’t make any changes to the user profile from the admin panel, I just click on save, then the file is also deleted.
As far as I remember, I did not have such a problem when I uploaded to the root of the img folder, it appeared when I added def user_directory_path
What's wrong with the code?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey Gornostaev, 2018-10-22
@Lepilov

It's better to use pre_save to be able to compare the old and new value of the img field:

@receiver(pre_save, sender=Profile)
def my_handler(sender, instance, **kwargs):
    if instance.pk:
        old = Profile.objects.get(pk=instance.pk)
        path = old.img.path
        if path != instance.img.path:
            os.remove(path)

But it is even better to do such things with the help of a background job that periodically deletes files that are not referenced in the database.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question