I have a model - Product, which contains a thumbnail image. I have another model which contains images associated with the product - ProductImage. I want to delete both the thumbnail and the images from the server when the product instance is deleted, and for a while this seemed to worked, but not anymore.
Relevant code...
Class Product(models.Model):
title = Charfield
thumbnail = ImageField(upload_to='thumbnails/', verbose_name='thumbnail', blank=True, )
Class ProductImage(models.Model):
product = models.ForeignKey(plant, default=None, related_name='images')
image = models.ImageField(upload_to='images/', verbose_name='image',)
The following delete method (in the product class) was working, but I changed my code and it no longer works - and from what i have read it is best practice to use post_delete, rather then override delete()
def delete(self):
images = ProductImage.objects.filter(product=self)
if images:
for image in images:
image.delete()
super(Product, self).delete()
How can I rewrite a delete method which will achieve what I want? I have tried to use post_delete but so far I have been unsuccessful because I am not sure how to apply it when it comes to deleting the ProductImage instance...
The django-cleanup app automatically deletes files for FileField , ImageField and subclasses. When a FileField 's value is changed and the model is saved, the old file is deleted. When a model that has a FileField is deleted, the file is also deleted.
remove() method in Python can be used to remove files, and the os. rmdir() method can be used to delete an empty folder. The shutil. rmtree() method can be used to delete a folder along with all of its files.
However, there is one thing that Django no longer does starting with version 1.3: automatically deleting files from a model when the instance is deleted.
Handling Files in Django is pretty easy: you can add them to a model with only a line (for a brush-up on Django models, you can check out our article on handling data web frameworks ), and the framework will handle everything for you – validations, uploading, type checking. Even serving them takes very little effort.
This is the object that actually understands things like file systems, opening and reading files, etc. Django’s default file storage is given by the DEFAULT_FILE_STORAGE setting; if you don’t explicitly provide a storage system, this is the one that will be used.
If you want to handle “static files” (JS, CSS, etc.), see How to manage static files (e.g. images, JavaScript, CSS). By default, Django stores files locally, using the MEDIA_ROOT and MEDIA_URL settings.
And here's an example with the post_delete
:
import os
from django.db import models
def _delete_file(path):
""" Deletes file from filesystem. """
if os.path.isfile(path):
os.remove(path)
@receiver(models.signals.post_delete, sender=ProductImage)
def delete_file(sender, instance, *args, **kwargs):
""" Deletes image files on `post_delete` """
if instance.image:
_delete_file(instance.image.path)
@receiver(models.signals.post_delete, sender=Product)
def delete_file(sender, instance, *args, **kwargs):
""" Deletes thumbnail files on `post_delete` """
if instance.thumbnail:
_delete_file(instance.thumbnail.path)
Overriding the delete()
method:
class Product(models.Model):
...
def delete(self):
images = ProductImage.objects.filter(product=self)
for image in images:
image.delete()
self.thumbnail.delete()
super(Product, self).delete()
class ProductImage(models.Model):
...
def delete(self):
self.image.delete()
super(ProductImage, self).delete()
Read about Cascade
delete: docs
In 1.11 Django. Code work!
import os
from django.db import models
from django.utils import timezone
from django.db.models.signals import pre_delete
from django.dispatch.dispatcher import receiver
class Post(models.Model):
category = models.ForeignKey(Category, verbose_name='Категория')
title = models.CharField('Заголовок', max_length=200, unique=True)
url = models.CharField('ЧПУ', max_length=200, unique=True)
photo = models.ImageField('Изображение', upload_to="blog/images/%Y/%m/%d/", default='', blank=True)
content = models.TextField('Контент')
created_date = models.DateTimeField('Дата', default=timezone.now)
def _delete_file(path):
# Deletes file from filesystem.
if os.path.isfile(path):
os.remove(path)
@receiver(pre_delete, sender=Post)
def delete_img_pre_delete_post(sender, instance, *args, **kwargs):
if instance.photo:
_delete_file(instance.photo.path)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With