在现代软件中我们对数据的重视程度逐渐提高,数据可谓是现代软件的灵魂,这导致我们在删除数据时不能是真正意义上的删除数据而是一种逻辑删除也叫软删除,接下来我们就来用Python实现软删除

软删除 V1.0

class TestModel(Model):
    name = models.CharField(max_length=50, null=True, verbose_name='更新人')
    is_valid = models.BooleanField(default=True, verbose_name='数据有效/无效', db_index=True)
    
xm = TestModel.objects.create({'name':'小明'})
xl = TestModel.objects.create({'name':'小刘'})

TestModel.objects.count() # 2

xl.is_valid= False

TestModel.objects.filter(is_valid=True).count() # 1

如上操作我们就实现了最基础的数据软删除,这也导致了一个问题,在查询时我们不得不每次都加上.filter(is_valid=True)来过滤失效的数据,这样会让我们的代码臃肿且难以维护,难道没有什么方法可以更方便使用软删除吗?

Of course,Django ORM 为我们提供了模型管理类,在此之前我们需要了解一下什么是模型管理类,先来看一段简单的代码。

TestModel.objects.all()

大家有没有疑惑过为什么我们一定要这样xxxxx.objects.xxxx使用objects来操作数据库,而不是使用更加方便快捷的Model.create()来操作数据库呢

其实其中的objects就是一个模型管理类models.Manager,模型管理类可以实现很多内容,现在我们用它来实现更为优雅的软删除功能

自定义一个QuerySet,QuerySet是模型管理类中针对查询的处理类,继承于models.QuerySet

class ValidQueryset(models.QuerySet):
    def filter(self, *args, **kwargs):
        is_valid = kwargs.pop('is_valid', True)
        if isinstance(is_valid, bool):
            kwargs['is_valid'] = is_valid
        return super().filter(*args, **kwargs)

再实现模型管理类,继承models.Manage

class ValidManage(models.Manager):
    _queryset_class = ValidQueryset

将模型管理类添加至模型

class TestModel(Model):
    name = models.CharField(max_length=50, null=True, verbose_name='更新人')
    is_valid = models.BooleanField(default=True, verbose_name='数据有效/无效', db_index=True)
    
    objects = BaseManage()

这样我们就可以优雅的使用软删除了

xm = TestModel.objects.create({'name':'小明'})
xl = TestModel.objects.create({'name':'小刘'})

TestModel.objects.count() # 2

xl.is_valid= False

# TestModel.objects.filter(is_valid=True).count() # 1
TestModel.objects.count() # 1

细心的小伙伴可能发现了一个问题,这样我们每个模型都要去重写覆盖objects,现在我们来一劳永逸的解决这个问题。

class ValidQueryset(models.QuerySet):
    def filter(self, *args, **kwargs):
        is_valid = kwargs.pop('is_valid', True)
        if isinstance(is_valid, bool):
            kwargs['is_valid'] = is_valid
        return super().filter(*args, **kwargs)


class ValidManage(models.Manager):
    _queryset_class = ValidQueryset


class BaseValidModel(models.Model):
    name = models.CharField(max_length=50, null=True, verbose_name='更新人')
    is_valid = models.BooleanField(default=True, verbose_name='数据有效/无效', db_index=True)

    objects = ValidManage()

    class Meta:
        abstract = True

这样以后我们就需要继承BaseValidModel就可以实现优雅的软删除了

但是这里有一个坑,软删除的自动过滤无法应用于外键查询,如model.fk_filed.all(),这样fk_filed查出来的数据还是会包含is_valid=False的数据


文章到此结束,希望对各位有所帮助,我是老四,我们下一篇见