Django - 无法使用信号删除对象更改的旧文件

我有以下信号可以从我的硬盘中删除旧的 postcover 和 postcover_tn(缩略图)。如果我只是通过表单删除文件并调用 save() ,这工作正常,但是如果我想用新文件覆盖旧文件,我上传的旧文件仍在我的 fs 上,知道如何解决这个问题吗? :


signals.py


@receiver(models.signals.pre_save, sender=Post)

def post_auto_delete_files_on_change(sender, instance, **kwargs):

    """

    Deletes old file from filesystem

    when corresponding object is updated

    with new file.

    """

    if not instance.pk:

        return False


    try:

        old_postcover = sender.objects.get(pk=instance.pk).postcover

        old_postcover_tn = sender.objects.get(pk=instance.pk).postcover_tn

    except sender.DoesNotExist:

        return False

    if not old_postcover:

        return


    new_postcover = instance.postcover

    if not old_postcover == new_postcover:

        if os.path.isfile(old_postcover.path):

            os.remove(old_postcover.path)

    new_postcover_tn = instance.postcover_tn

    if not old_postcover_tn == new_postcover_tn:

        if os.path.isfile(old_postcover.path):

            os.remove(old_postcover.path)

postcover_tn 是在 Post 的 save() 上生成的,如果你想知道的话。


一只斗牛犬
浏览 79回答 2
2回答

四季花海

我让它像这样工作:models.py:def save(self, *args, **kwargs):    super(Post, self).save(*args, **kwargs)    if self.postcover:        if not (self.postcover_tn and os.path.exists(self.postcover_tn.path)):            image = Image.open(self.postcover)            outputIoStream = BytesIO()            baseheight = 400            hpercent = baseheight / image.size[1]            wsize = int(image.size[0] * hpercent)            imageTemproaryResized = image.resize((wsize, baseheight))            imageTemproaryResized.save(outputIoStream, format='PNG')            outputIoStream.seek(0)            self.postcover = InMemoryUploadedFile(outputIoStream, 'ImageField',                                                  "%s.png" % self.postcover.name.split('.')[0], 'image/png',                                                  sys.getsizeof(outputIoStream), None)            image = Image.open(self.postcover)            outputIoStream = BytesIO()            baseheight = 175            hpercent = baseheight / image.size[1]            wsize = int(image.size[0] * hpercent)            imageTemproaryResized = image.resize((wsize, baseheight))            imageTemproaryResized.save(outputIoStream, format='PNG')            outputIoStream.seek(0)            self.postcover_tn = InMemoryUploadedFile(outputIoStream, 'ImageField',                                                  "%s.png" % self.postcover.name.split('.')[0], 'image/png',                                                  sys.getsizeof(outputIoStream), None)    elif self.postcover_tn:        self.postcover_tn.delete()    super(Post, self).save(*args, **kwargs)signals.py@receiver(models.signals.pre_save, sender=Post)def post_auto_delete_files_on_change(sender, instance, **kwargs):"""Deletes old file from filesystemwhen corresponding object is updatedwith new file."""if not instance.pk:    return Falsetry:    old_postcover = sender.objects.get(pk=instance.pk).postcover    old_postcover_tn = sender.objects.get(pk=instance.pk).postcover_tnexcept sender.DoesNotExist:    return Falseif not old_postcover:    returnnew_postcover = instance.postcovernew_postcover_tn = instance.postcover_tnif not old_postcover == new_postcover:    if os.path.isfile(old_postcover.path):        os.remove(old_postcover.path)        if old_postcover_tn == new_postcover_tn:            if os.path.isfile(old_postcover_tn.path):                os.remove(old_postcover_tn.path)

白猪掌柜的

这是问题所在由于您正在处理保存后信号,因此在信号处理程序执行之前,实例上的数据已经插入到数据库中。这意味着在你上面sender.objects.get(pk=instance.pk).postcover的instance.postcover代码中获取相同的东西——新保存的 postcover。所以,你old_postcover在代码中命名的东西实际上是新的 postcover。真正的旧后封面已被永久覆盖,并且仍在您的文件系统中。题外话现在,这部分代码的主体......if not old_postcover == new_postcover:    if os.path.isfile(old_postcover.path):        os.remove(old_postcover.path)        os.remove(old_postcover_tn.path)...永远不会运行,因为old_postcover和new_postcover确实是一回事。如何解决这个问题?您可以使用预保存信号处理程序。在处理程序中,您从数据库中获取旧的 postcoversender.objects.get(pk=instance.pk).postcover(在检查之后,就像您在代码中所做的那样,以确保实例确实有一个 pk)。然后你删除这个旧的postcover,你就完成了。此解决方案的问题走这条路我可以立即看到的问题是,您正在删除旧数据而不知道新数据是否会被数据库首先接受。但看好的一面但是,如果您只通过ModelForms 更改 postcovers,则is_valid()对表单上的方法的调用会在实例上执行所有验证,因此您可以确信在处理程序执行时,实例上的新数据已经已验证并将被数据库接受。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python