欢迎访问宙启技术站
智能推送

django之自定义软删除Model的方法

发布时间:2023-05-15 22:31:13

Django是一款开发快速、且易于扩展和维护的Python网站开发框架。它提供了一套完备的ORM框架,可以方便地和多种数据库进行交互。但是,在使用Django进行开发的过程中,我们可能需要针对一些数据模型(Model)实现软删除的功能,也就是不实际删除数据,而是将其标记为已删除。

为什么需要软删除?

软删除之所以需要,主要是为了满足以下几个需求:

- 数据的历史记录

如果直接将某条数据从数据库中删除,那么在以后需要查看数据的历史记录时,就会变得非常困难。而软删除则可以保留数据的历史记录,方便后续查看。

- 数据恢复

在软删除的情况下,即使数据已经被标记为已删除,但是我们仍然可以通过某些方法来恢复被删除的数据。

- 数据的完整性

在有些业务场景下,我们需要保证某些数据不能被删除,例如订单数据等。如果我们采用了软删除的方式,就可以设置相关数据不能被软删除,保证数据的完整性。

如何实现软删除?

在Django中,实现软删除的方式有很多种,以下是一些常见的方法。

方法一:使用软删除标志位

我们可以在Model中添加一个Boolean类型的字段,例如deleted,用来表示数据是否被删除。在查询数据时,我们只需要将查询条件中加上该字段不等于True的条件即可。

下面是一个示例:

class MyModel(models.Model):
    # ...
    deleted = models.BooleanField(default=False)

查询数据时:

MyModel.objects.filter(deleted=False)

这样的方式虽然简单,但是其中存在一个问题,那就是在操作删除和恢复时,我们有可能会忘记修改deleted字段。这就会导致数据的误删除或者误恢复。

方法二:使用Django自带的软删除功能

从Django 2.2开始,框架自带了软删除的功能。我们只需要在Model中继承SoftDeletionModelMixin类,即可实现软删除的功能。

下面是一个示例:

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import UserManager
from django.utils import timezone

class MyModel(models.Model):
    # ...
    deleted_at = models.DateTimeField(null=True, default=None, blank=True)

    objects = UserManager()

    class Meta:
        abstract = True

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

    class Meta:
        abstract = True

    objects = models.Manager()
    active_objects = SoftDeletionManager()

    def delete(self, using=None, keep_deleted=False):
        if not keep_deleted:
            self.deleted_at = timezone.now()
            self.save(using=using)
        else:
            super(SoftDeletionModelMixin, self).delete(using=using)

    def undelete(self, using=None):
        self.deleted_at = None
        self.save(using=using)

    def hard_delete(self, using=None):
        super(SoftDeletionModelMixin, self).delete(using=using)

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

在继承SoftDeletionModelMixin的Model中,我们添加了一个deleted_at字段,它用来存储删除的时间。并且重写了delete方法,当调用删除方法时,它会将deleted_at字段设置为当前时间,而不是直接从数据库中删除数据。如果我们需要恢复数据,只需要将deleted_at字段设置为None即可。

查询数据时,我们只需要使用active_objects属性来获取未被删除的数据,例如:

MyModel.active_objects.all()

这样的方式虽然相对于手动加标志位来说,要安全可靠一些,但是需要我们手动调用delete和undelete方法进行删除和恢复操作。

方法三:使用第三方软删除库

除了上述两种方式之外,还有一些第三方库也提供了软删除的实现,例如django-softdelete和django-paranoia。使用这些库的方式与使用Django自带的软删除功能类似,但是不同库的具体实现方式也有所不同,需要根据具体需求进行选择。

总结

软删除是一种非常常见的功能需求,可以保留数据的历史记录,实现数据恢复,以及维护数据的完整性。在Django中,我们可以采用添加标志位、继承框架提供的SoftDeletionModelMixin或者使用第三方软删除库来实现软删除的功能。需要根据具体业务需求和安全考虑来选择合适的方式。