How to delete files from filesystem using post_delete - Django 1.8
Asked Answered
F

3

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

Francenefrances answered 12/10, 2015 at 11:46 Comment(2)
what is your error message?Lakeshialakey
I am not getting any, the files are just not being deleted from the media folder...Francenefrances
L
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

Lakeshialakey answered 12/10, 2015 at 12:21 Comment(9)
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 viewFrancenefrances
I personally prefer signals.Lakeshialakey
Thanks, the delete() override works well, I couldn't get post_delete to successfully delete the images, only the thumbnailFrancenefrances
I am trying the post-delete signal approach but I can't get that method to trigger at all. Do I have to register the method somehow or has this changed in Django 1.9 perhaps?Lochner
@jonalv, I guess nothing has really changed: docs.djangoproject.com/en/1.9/ref/signals/#post-deleteLakeshialakey
post_delete seems preferable because the override of method delete() doesn't work for me with the delete admin action.Babbette
if I put post_delete in my models.py file then it throws error at sender, Error:NameError: name 'Product' is not defined. so how to resolve itHalide
Very helpful, appreciate the help..Taryn
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.Humfrey
N
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)
Nikkinikkie answered 16/8, 2017 at 0:13 Comment(0)
P
0

To effectively delete files from your system try:

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

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

Pentheus answered 18/2, 2022 at 20:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.