iT邦幫忙

2024 iThome 鐵人賽

DAY 7
1
自我挑戰組

學習網頁開發系列 第 7

Django Model SoftDelete

  • 分享至 

  • xImage
  •  

很多時候,使用者在刪除某筆資料時,伺服端不會馬上刪除資料,而是保留此資料一段時間,這樣假如使用者反悔的話,還有機會救回來。
Django 的實作中,我們可以在每個想要如此定義的 Model 寫定相關邏輯與操作,如下:

from django.db import models
class ExampleModel(models.Model):
    name = models.CharField(null=False)
    is_deleted = models.BooleanField(default=False)
    
    def delete(self, soft=True):
        if soft:
            self.is_deleted = True
            self.save()
        else:
            super().delete()

delete 為內建的方法,這裡我們自己寫了 delete 覆寫了它,從中增加了一些判斷,讓軟刪除得以像一般刪除一樣執行。

假如我們想要讓眾多模型都可以軟刪除,又不想重複寫得話,可以使用 Abstract Models 來設計:

from django.db import models
class SoftDeleteModel(models.Model):
    is_deleted = models.BooleanField(default=False)
    
    def delete(self, soft=True):
        if soft:
            self.is_deleted = True
            self.save()
        else:
            super().delete()
    
    class Meta:
        abstract = True

class ExampleModel(SoftDeleteModel):
    name = models.CharField(null=False)

再來,為了開發人員寫程式時不用多花心思設立許多 if else 判斷(或是 ORM 的 filter),可以自定義 models.Manager 在每個流程中暗自加上 filter 效果。使得軟刪除的資料在預設下是拿不到的。

from django.db import models
# 增加自訂義 manager
class SoftDeleteManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_deleted=True)

class SoftDeleteModel(models.Model):
    is_deleted = models.BooleanField(default=False)
    
    # 蓋過預設的 objects manager
    objects = SoftDeleteManager()
    
    def delete(self, soft=True):
        if soft:
            self.is_deleted = True
            self.save()
        else:
            super().delete()
    
    class Meta:
        abstract = True

class ExampleModel(SoftDeleteModel):
    name = models.CharField(null=False)
    
ExampleModel.objects.all() 
# 只會拿到還沒被軟刪除的資料,即使寫法跟預設一樣

設定可以很多,也可以寫讓軟刪除復原的方法,程式上都行,主要考量還是業務邏輯。以下是我自己使用的模板:

from django.db import models
from django.utils import timezone


class SoftDeleteManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(deleted_at=None)


class DeletedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().exclude(deleted_at=None)


class SoftDeleteModel(models.Model):
    deleted_at = models.DateTimeField(default=None, null=True)

    objects = SoftDeleteManager()
    deleted_objects = DeletedManager()
    all_objects = models.Manager()

    def delete(self, soft=True):
        if soft:
            self.deleted_at = timezone.now()
            self.save()
        else:
            super().delete()

    def revive(self):
        self.deleted_at = None
        self.save()

    def is_deleted(self):
        return self.deleted_at is not None

    class Meta:
        abstract = True

上一篇
Django Model 繼承的方法
下一篇
WSGI 和 ASGI
系列文
學習網頁開發13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言