Django-无法使用信号删除对象更改时的旧文件 [英] Django - Unable to delete old file on object change using signals
问题描述
我有以下信号要从硬盘上删除旧的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 ModelForm
s, 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屋!