Django - 无法使用信号删除对象更改时的旧文件
Django - Unable to delete old file on object change using signals
我有以下信号要从我的硬盘中删除旧的封底和 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() 上生成的,如果您可能对此感到疑惑的话。
问题来了
由于您正在处理 post 保存 信号,因此在信号处理程序执行之前,实例上的数据已经插入到数据库中。
这意味着上面代码中的 sender.objects.get(pk=instance.pk).postcover
和 instance.postcover
获取相同的东西——新保存的 postcover.
因此,您在代码中命名为 old_postcover
的那个东西实际上是 new postcover。真正的 old 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
确实是一回事。
如何解决这个问题?
您可以使用预保存信号处理程序。
在处理程序中,您使用 sender.objects.get(pk=instance.pk).postcover
从数据库中获取 old postcover(检查后,就像您在代码中所做的那样,以确保实例确实有 pk)。
然后删除这个旧的 post封面,就大功告成了。
这个解决方案的问题
走这条路我可以立即看到的问题是,您在删除旧数据时并不知道数据库是否会首先接受新数据。
但往好的方面看
但是,如果您只是通过 ModelForm
更改 post 封面,则对表单上的 is_valid()
方法的调用将对实例执行所有验证,因此那么您可以确信在处理程序执行时,实例上的新数据已经过验证并将被数据库接受。
我是这样工作的:
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 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
new_postcover_tn = instance.postcover_tn
if 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)
@mfonism 感谢您的提示,它们确实帮助我理解了。
我有以下信号要从我的硬盘中删除旧的封底和 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() 上生成的,如果您可能对此感到疑惑的话。
问题来了
由于您正在处理 post 保存 信号,因此在信号处理程序执行之前,实例上的数据已经插入到数据库中。
这意味着上面代码中的 sender.objects.get(pk=instance.pk).postcover
和 instance.postcover
获取相同的东西——新保存的 postcover.
因此,您在代码中命名为 old_postcover
的那个东西实际上是 new postcover。真正的 old 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
确实是一回事。
如何解决这个问题?
您可以使用预保存信号处理程序。
在处理程序中,您使用 sender.objects.get(pk=instance.pk).postcover
从数据库中获取 old postcover(检查后,就像您在代码中所做的那样,以确保实例确实有 pk)。
然后删除这个旧的 post封面,就大功告成了。
这个解决方案的问题
走这条路我可以立即看到的问题是,您在删除旧数据时并不知道数据库是否会首先接受新数据。
但往好的方面看
但是,如果您只是通过 ModelForm
更改 post 封面,则对表单上的 is_valid()
方法的调用将对实例执行所有验证,因此那么您可以确信在处理程序执行时,实例上的新数据已经过验证并将被数据库接受。
我是这样工作的:
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 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
new_postcover_tn = instance.postcover_tn
if 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)
@mfonism 感谢您的提示,它们确实帮助我理解了。