从磁盘删除外键上的图像

时间:2014-11-20 15:52:48

标签: python django

models.py:

class Car(models.Model):
    ...

class Pictures(models.Model):
    car = models.ForeignKey(Car, related_name='pictures')
    width = models.PositiveIntegerField(editable=False, default=780)
    height = models.PositiveIntegerField(editable=False, default=585)
    image = models.ImageField(upload_to = get_file_path, max_length=64, height_field='height', width_field='width')

    def __unicode__(self):
        return str(self.id)

    def delete(self, *args, **kwargs): 
        storage, path = self.image.storage, self.image.path
        super(Pictures, self).delete(*args, **kwargs)
        storage.delete(path)

效果很好(我从管理面板中删除了一张图片,这张图片会自动从磁盘中删除)。

但是当我通过管理面板删除Car对象时,图像不会从磁盘中删除。

如何解决这个问题?

谢谢!

2 个答案:

答案 0 :(得分:1)

我确定这里的问题是ORM使用ON DELETE CASCADE让数据库句柄删除关系,这意味着你的delete方法不会被调用。

您可能只应用您在此处使用的相同技术并执行此操作:

class Car(models.Model):
    ...

    def delete(self, *args, **kwargs): 
        for picture in self.pictures.all():
            storage, path = picture.image.storage, picture.image.path
            storage.delete(path)
        super(Car, self).delete(*args, **kwargs)

但是,最好使用信号而不是覆盖delete方法https://docs.djangoproject.com/en/dev/ref/signals/#post-delete

  

请注意,使用QuerySet批量删除对象时,不一定要调用对象的delete()方法。为确保执行自定义删除逻辑,您可以使用pre_delete和/或post_delete信号。

答案 1 :(得分:0)

我开始研究这个问题,发现了一些关于管理和删除对象的有趣事情。

从admin中删除对象时,将调用以下函数,

django / contrib / admin / options.py - > delete_model()

反过来调用obj.delete(),其中obj是当前被删除的对象。

对象的delete方法然后运行以下代码,

collector = Collector(using=using)
collector.collect([self])
collector.delete()

收集器对象现在有一个属性'data',其中包含所有相关对象。 当collector.delete()运行时,它执行函数query.delete_batch(pk_list, self.using),该函数使用参数pk_list执行批量删除,该参数是要删除的相关对象的主键列表。批量删除功能又不会调用每个相关对象的删除方法。

这里的好处是会为所有相关对象调用pre_save和post_save信号,因此我们可以将自定义删除代码移动到图片模型的pre_save或post_save信号中。

这应该有效,但我没有机会进行测试。