'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:
- 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
- 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 |