亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Django - 無法使用信號刪除對象更改的舊文件

Django - 無法使用信號刪除對象更改的舊文件

一只斗牛犬 2022-07-19 15:24:48
我有以下信號可以從我的硬盤中刪除舊的 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() 上生成的,如果你想知道的話。
查看完整描述

2 回答

?
四季花海

TA貢獻1811條經驗 獲得超5個贊

我讓它像這樣工作:


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)


查看完整回答
反對 回復 2022-07-19
?
白豬掌柜的

TA貢獻1893條經驗 獲得超10個贊

這是問題所在

由于您正在處理保存后信號,因此在信號處理程序執行之前,實例上的數據已經插入到數據庫中。


這意味著在你上面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()對表單上的方法的調用會在實例上執行所有驗證,因此您可以確信在處理程序執行時,實例上的新數據已經已驗證并將被數據庫接受。


查看完整回答
反對 回復 2022-07-19
  • 2 回答
  • 0 關注
  • 103 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號