Django-无法使用信号删除对象更改时的旧文件 [英] Django - Unable to delete old file on object change using signals

查看:51
本文介绍了Django-无法使用信号删除对象更改时的旧文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下信号要从硬盘上删除旧的postcover和postcover_tn(缩略图).如果我只是删除表单中的文件并调用save(),则此方法工作正常,但是如果我想用新文件覆盖旧文件,而我上传的旧文件仍在我的文件系统中,您知道如何解决此问题吗?:

I have the following signal to delete the old postcover and postcover_tn (thumbnail) from my hard disk. This is working fine if I just delete the files trough my form and call save() but if I want to overwrite the old files with the new ones I upload the old ones are are still on my fs, any idea how to fix this?:

signals.py

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()上生成的,即使您可能对此有所怀疑.

postcover_tn gets generated on save() of Post, just if you might wonder about that.

推荐答案

这是问题所在

由于您要处理后保存信号,因此在执行信号处理程序之前,实例上的数据已插入数据库中.

Here's the Problem

Since you're handling a post save signal, the data on the instance has already been inserted into the database before the signal handler executes.

这意味着您上面的代码中的 sender.objects.get(pk = instance.pk).postcover instance.postcover 会提取相同的内容—新保存的postcover.

This means that sender.objects.get(pk=instance.pk).postcover and instance.postcover in your code above fetch the same thing — the newly saved postcover.

因此,您要在代码中命名 old_postcover 的东西实际上是新的postcover .真正的旧后封面已被永久覆盖,仍在您的文件系统上.

So, that thing you're naming old_postcover in your code, is actually the new postcover. The real old postcover has been overwritten for good, and is still on your File System.

现在,这部分代码的主体...

Now, the body of this part of the code...

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 确实是同一回事.

... never gets to run, because old_postcover and new_postcover are indeed the same thing.

您可以使用预保存信号处理程序.

You could use a pre save signal handler.

在处理程序中,使用 sender.objects.get(pk = instance.pk).postcover 从数据库中获取旧的postcover (检查后就像您一样)在您的代码中执行,以确保实例确实具有pk).

In the handler, you grab the old postcover from the database with sender.objects.get(pk=instance.pk).postcover (after checking, like you did in your code, to ensure the instance does really have a pk).

然后您删除此旧的postcover,就完成了.

Then you delete this old postcover, and you're done.

沿这条路线我可以立即看到的问题是,您正在删除旧数据,而首先不知道数据库是否会接受新数据.

The problem I can immediately see with going this route is that you're deleting old data without knowing whether the new data will be accepted by the database in the first place.

但是,如果仅通过 ModelForm s来更改后发现,则对表单上的 is_valid()方法的调用将对实例执行所有验证,因此,您可以确信在处理程序执行时,实例上的新数据已经过验证,并且将被数据库接受.

However, if you'll only ever be changing postcovers through ModelForms, the call to the is_valid() method on the form performs all validation on the instance, so then you can be confident that at the point the handler executes, the new data on the instance has been validated and will be accepted by the database.

这篇关于Django-无法使用信号删除对象更改时的旧文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆