Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete files from filesystem using post_delete - Django 1.8

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

like image 417
tim Avatar asked Oct 12 '15 11:10

tim


People also ask

What is Django-cleanup?

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.

How do you delete a file in Python?

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.

Does Django automatically delete files from a model when it's deleted?

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.

How to handle files in Django?

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.

What is the default file system in Django?

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.

How do I manage static files in Django?

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.


2 Answers

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

like image 56
sobolevn Avatar answered Oct 02 '22 18:10

sobolevn


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)
like image 32
Сергей Зеленчук Avatar answered Oct 02 '22 18:10

Сергей Зеленчук