26

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...

2
  • what is your error message? Commented Oct 12, 2015 at 11:51
  • I am not getting any, the files are just not being deleted from the media folder... Commented Oct 12, 2015 at 11:54

3 Answers 3

47

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

Sign up to request clarification or add additional context in comments.

9 Comments

Is post_delete preferable? If I overide delete() as above, the thumbnail is deleted but the related images are not, unless its a problem with the view
I personally prefer signals.
Thanks, the delete() override works well, I couldn't get post_delete to successfully delete the images, only the thumbnail
post_delete seems preferable because the override of method delete() doesn't work for me with the delete admin action.
Worth mentioning that deleting the file using os.remove wouldn't work depending on your file storage (e.g. it wouldn't on S3 or Cloudfiles). It is more appropriate to use the file field's delete method instead.
|
5

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)

Comments

0

To effectively delete files from your system try:

files = modelName.objects.all().get(columnName=criteria)

files.columnNameFile.delete() files.columnNameFile2.delete() . . .

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.