'In django after deleting the posts the post images are still in the directory

In django my posts are deleted but the files are not. I have a image field in the model which i want to deelete whenever the author deletes it. I'm using generics class based views delete.. so when i delete the post the posts are deleted but the image isn't deleted from the directory. i'v tried in many ways but its not working. my models.py:

class postManager(models.Manager):
  def repost(self, author, parent_obj):
    if parent_obj.parent:
        og_parent = parent_obj.parent
    else:
        og_parent = parent_obj


    obj = self.model(
            parent = og_parent,
            author = author,
            content = og_parent.content,
            image = og_parent.image,
        )
    obj.save()
    return obj



class post(models.Model):
    parent = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True)
    title = models.CharField(max_length=100)
    image = models.ImageField(upload_to='post_pics', null=True, blank=True)
    video = models.FileField(upload_to='post_videos', null=True, blank=True)
    content = models.TextField()
    likes = models.ManyToManyField(User, related_name='likes', blank=True)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    objects = postManager()

    def __str__(self):
        return self.title

my views.py:

@login_required
def post_list(request):
    count_filter = Q(likes=request.user)
    like_case = Count('likes', filter=count_filter, output_field=BooleanField())

    posts = post.objects.annotate(is_liked=like_case).all().order_by('-date_posted')


    return render(request, 'blog/home.html', {'posts': posts, })

class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = post
fields = ['content', 'image', 'video']
success_url = '/'

def test_func(self):
    post = self.get_object()
    if self.request.user == post.author:
        return True
    return False

my urls.py:

path('post/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'),

i"m using the parent in model so, on delete(self) argument is not working.



Solution 1:[1]

This is normal behaviour because the instances of post only store a path to the file, like a string, not the actual file. The actual file is stored on a filesystem.

To delete the actual file upon deletion of an instance of post, you have some choices:

1. Override the delete function e.g.

def delete(self, using=None, keep_parents=False):
    self.image.delete()
    super().delete()

2. Add a post delete signal Although there is nothing inherently wrong with using signals, you should consider two points before using them:

  1. A signal can be sent multiple times for a single action, so you have to handle any code that might raise errors if run more than once on a single instance (e.g. attempting to delete a non existent file)
try:
    os.remove(filename)
except OSError:
    pass
  1. Because a signal is not within the expected flow of code, if it has a bug, it can be tricky to trace it down for less experienced developers

3. Use a package such as django-cleanup

Solution 2:[2]

you can try this:

 def delete(self, using=None):
    os.unlink(self.image.path)
    super(post,self).delete()

Solution 3:[3]

You could use post_delete signal.

In your models.py:

from django.db.models.signals import post_delete

@receiver(post_delete, sender=post)
def photo_post_delete_handler(sender, **kwargs):
    photo = kwargs['instance']
    if photo.image:
        storage, path = photo.image.storage, photo.image.path
        storage.delete(path)

Solution 4:[4]

For me post_delete was deleting the image but the object not not deleted strangely. After using the pre_delete signal issue was solved. If anyone knows the reason for this behavior then please explain. Thank you.

from django.db.models.signals import pre_save, pre_delete
from django.dispatch.dispatcher import receiver
@receiver(pre_delete, sender=Item)
def image_delete_handler(sender, instance, *args, **kwargs):
    if instance.image and instance.image.url:
        instance.image.delete()

Solution 5:[5]

Use "django-cleanup" package to automatically remove uploaded files for FileField, ImageField and subclasses when they are deleted and updated. And setting "django-cleanup" is easy.

First, install "django-cleanup":

pip install django-cleanup

Then, set it to the bottom of "INSTALLED_APPS" in "settings.py". That's it:

INSTALLED_APPS = (
    ...,
    'django_cleanup.apps.CleanupConfig',
)

This is the github link for "django-cleanup" This is the pypi link for "django-cleanup"

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nader Alexan
Solution 2 Ashish
Solution 3 Renato Mareti?
Solution 4 Sardar Faisal
Solution 5 Kai - Kazuya Ito