Reputation: 9353
I'm using Django to create a stock photo site, I have an ImageField in my model, the problem is that when the user updates the image field, the original image file isn't deleted from the hard disk.
How can I delete the old images after an update?
Upvotes: 52
Views: 41275
Reputation: 25
How I solved a similar problem
from django.conf import settings
BASE_DIR = settings.BASE_DIR
try:
os.remove(f'{BASE_DIR}/{MYMODEL.fileField.url}')
except:
pass
Upvotes: 0
Reputation: 4449
Use django-cleanup
pip install django-cleanup
settings.py
INSTALLED_APPS = (
...
'django_cleanup.apps.CleanupConfig', # should be placed after your apps
)
Upvotes: 82
Reputation: 1
What I did is saving the path to the old image and if form is valid I would delete the old one.
if request.method == 'POST':
old_image = ""
if request.user.profile.profile_picture:
old_image = request.user.profile.profile_picture.path
form = UpdateProfileForm(request.POST,request.FILES,instance = profile)
if form.is_valid():
if os.path.exists(old_image):
os.remove(old_image)
form.save()
It is a little messy , but you do not install third parties or anythin
Upvotes: 0
Reputation: 48972
You'll have to delete the old image manually.
The absolute path to the image is stored in your_image_field.path
. So you'd do something like:
os.remove(your_image_field.path)
But, as a convenience, you can use the associated FieldFile object, which gives easy access to the underlying file, as well as providing a few convenience methods. See http://docs.djangoproject.com/en/dev/ref/models/fields/#filefield-and-fieldfile
Upvotes: 23
Reputation: 11
try this, it will work even if old file is deleted
def logo_file(instance, filename):
try:
this = business.objects.get(id=instance.id)
if this.logo is not None:
path = "%s" % (this.logo)
os.remove(path)
finally:
pass..
code will work even without "try .. finally" but it will generate problem if file was accidently deleted. changed: move model matching inside "try" so it will not throw any error at user signup Let me know if there are any problems.
Upvotes: 1
Reputation: 629
Completing Chris Lawlor's answer, tried this and works.
from YOURAPP.settings import BASE_DIR
try:
os.remove(BASE_DIR + user.userprofile.avatarURL)
except Exception as e:
pass
The URL has a pattern of /media/mypicture.jpg
Upvotes: 0
Reputation: 721
You can define pre_save
reciever in models:
@receiver(models.signals.pre_save, sender=UserAccount)
def delete_file_on_change_extension(sender, instance, **kwargs):
if instance.pk:
try:
old_avatar = UserAccount.objects.get(pk=instance.pk).avatar
except UserAccount.DoesNotExist:
return
else:
new_avatar = instance.avatar
if old_avatar and old_avatar.url != new_avatar.url:
old_avatar.delete(save=False)
My avatrs has unique url for each person like "avatars/ceb47779-8833-4719-8711-6f4e5cabb2b2.png". If user upload new image with different extension like jpg, delete_file_on_change_extension reciever remove old image, before save new with url "avatars/ceb47779-8833-4719-8711-6f4e5cabb2b2.jpg" (in this case). If user uploads new image with same extension django overwrite old image on storage (disk), because images paths are the same. This works fine with AWS S3 django-storage.
Upvotes: 11
Reputation: 1605
Before updating the model instance, you can use the delete method of FileField
object. For example, if the FileField
or ImageField
is named as photo
and your model instance is profile
, then the following will remove the file from disk
profile.photo.delete(False)
For more clarification, here is the django doc
Upvotes: 19
Reputation: 9767
Here is an app that deletes orphan files by default: django-smartfields. It will remove files whenever:
It is possible to turn that cleanup feature off using an argument: ImageField(keep_orphans=True)
on per field basis, or globally in settings SMARTFIELDS_KEEP_ORPHANS = True
.
from django.db import models
from smartfields import fields
class MyModel(models.Model):
image = fields.ImageField()
document = fields.FileField()
Upvotes: 4
Reputation: 675
Use this custom save method in your model:
def save(self, *args, **kwargs):
try:
this = MyModelName.objects.get(id=self.id)
if this.MyImageFieldName != self.MyImageFieldName:
this.MyImageFieldName.delete()
except: pass
super(MyModelName, self).save(*args, **kwargs)
It works for me on my site. This problem was bothering me as well and I didn't want to make a cleanup script instead over good bookkeeping in the first place. Let me know if there are any problems with it.
Upvotes: 22