Как удалить файлы из файловой системы с помощью post_delete — Django 1.8

У меня есть модель - Продукт, который содержит миниатюру изображения. У меня есть другая модель, которая содержит изображения, связанные с продуктом — ProductImage. Я хочу удалить как миниатюру, так и изображения с сервера при удалении экземпляра продукта, и какое-то время это, казалось, работало, но не больше.

Соответствующий код...

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',)

Следующий метод удаления (в классе продукта) работал, но я изменил свой код, и он больше не работает, и из того, что я прочитал, лучше всего использовать post_delete, а не переопределять delete()

def delete(self):
    images = ProductImage.objects.filter(product=self)
    if images:
        for image in images:
            image.delete()
    super(Product, self).delete()

Как я могу переписать метод удаления, который достигнет того, чего я хочу? Я пытался использовать post_delete, но пока безуспешно, потому что я не уверен, как его применять, когда дело доходит до удаления экземпляра ProductImage...


person tim    schedule 12.10.2015    source источник
comment
какое у вас сообщение об ошибке?   -  person sobolevn    schedule 12.10.2015
comment
Я ничего не получаю, файлы просто не удаляются из папки мультимедиа...   -  person tim    schedule 12.10.2015


Ответы (2)


А вот пример с 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)

Переопределение метода delete():

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()

Прочитайте об Cascade удалении: документы

person sobolevn    schedule 12.10.2015
comment
post_delete предпочтительнее? Если я переопределю delete(), как указано выше, миниатюра будет удалена, а связанные изображения — нет, если только это не проблема с видом. - person tim; 12.10.2015
comment
Я лично предпочитаю сигналы. - person sobolevn; 12.10.2015
comment
Спасибо, переопределение delete() работает хорошо, я не смог заставить post_delete успешно удалить изображения, только эскиз - person tim; 12.10.2015
comment
Я пытаюсь использовать подход с сигналом после удаления, но я вообще не могу заставить этот метод запускаться. Нужно ли как-то регистрировать метод или, возможно, это изменилось в Django 1.9? - person jonalv; 10.05.2016
comment
post_delete кажется предпочтительным, потому что переопределение метода delete() не работает для меня с удалением действия администратора. - person Davide Brunato; 06.02.2018
comment
если я помещу post_delete в свой файл models.py, он выдаст ошибку отправителю, Error:NameError: имя «Продукт» не определено. так как это решить - person chirag soni; 07.05.2019

В 1.11 Джанго. Код работает!

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)
person Сергей Зеленчук    schedule 16.08.2017