[实验] Django 自定义逻辑删除 (通过自定义 manager 管理器实现) (并非真的删除数据)

注意:

本实验是接着 《Django 通过自定义 manger 管理器进行自定义查询》而继续的

正文:

步骤一:准备测试数据

[root@mariadb ~]# mysql -uroot -p
MariaDB [(none)]> use test;
MariaDB [test]> update test_student SET isdelete=0 WHERE test_student.isdelete=1;
MariaDB [test]> quit;

步骤二:通过自定义 manager 管理器对某个数据进行单个的逻辑删除

2.1 创建 1 个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......

修改为:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    #objects = CustomManager()

    #show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete

    def delete(self, using=None, keep_parents=False):
        self.isdelete = True
        self.save()

......

(补充:这里以将 delete 重写成将 isdelete 设置为 True 为例)

2.2 进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *

2.3 通过自定义 manager 管理器查询数据

>>> Student.objects.all()
<QuerySet [<Student: student:False>, <Student: student:False>, <Student: student:False>]>

2.4 通过自定义 manager 管理器逻辑删除第 1 条数据(将第 1 条数据的 isdelete=False 修改成 isdelete=True)

>>> Student.objects.first().delete()

2.5 通过自定义 manager 管理器查询删除后的数据

>>> Student.objects.all()
<QuerySet [<Student: student:True>, <Student: student:False>, <Student: student:False>]>

(补充:这里第一条数据 isdelete=True)

步骤三:通过自定义 manager 管理器对一类数据进行批量的逻辑删除

3.1 创建 1 个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)
   
class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    #objects = CustomManager()

    #show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete

    def delete(self, using=None, keep_parents=False):
        self.isdelete = True
        self.save()

......

修改为:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class DeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)
   
class BatchDelManager(Manager):
    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=False)

    def filter(self, *args, **kwargs):
        #1. Get the record that needs to be deleted
        delList = Manager.get_queryset(self)

        #2. Define the closure method to modify isdelete = true
        def delete1(delqueryset):
            for dq in delqueryset:
                dq.isdelete = True
                dq.save()
        #3. Create an instance method dynamically, declare that delete has a delete method, call interface is delete (delist), call the delete1 object to execute
        import types
        delList.delete = types.MethodType(delete1,delList)

        return delList

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = BatchDelManager()

    show = DeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete

    def delete(self, using=None, keep_parents=False):
        self.isdelete = True
        self.save()

......


补充:
1) 这里以添加 1 个将父类的 all 重写成将所有 isdelete=True 的数据修改成 isdelete=False 的 BatchDelManager(Manager) 对象并在 Student 类中使用 objects 调用为例
2) 这里的实现方法是:动态创建 1 个实例方法,对外声明 delete 有 1 个 delete 方法调用接口是 delete(deList) ,调用 delete1 对象进行执行
3) 这里的 DeletedManager(Manager) 会查看所有 isdelete=True 的数据,并通过 Student 类中的 show 调用
4) 只要子类重写了父类的方法,就不会掉用父类的方法了,而是调用子类的方法
5) 闭包的作用是内部执行 1 个结果,对外还是 1 个外部函数的 1 个调用
6) python2 使用是 new 模块的 instancemethod 属性实现此功能,而 python3 使用是 types 模块的 MethodType属性实现此功能

3.2 进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *

3.3 查看所有 isdelete=False 的数据

>>> Student.objects.all()
<QuerySet [<Student: student:False>, <Student: student:False>]>

(补充:这里的 objects 已经经过了重写,所以只能显示 isdelete=False 的数据)

3.4 通过自定义 manager 管理器对一类数据进行批量的逻辑删除(将所有 isdelete=False 的数据修改成 isdelete=True)

>>> Student.objects.filter().delete()

3.5 查看所有 isdelete=False 的数据

>>> Student.objects.all()
<QuerySet []>

(补充:此时已经没有 isdelete=False 的数据)

3.6 查看所有 isdelete=True 的数据

>>> Student.show.all()
<QuerySet [<Student: student:True>, <Student: student:True>, <Student: student:True>]>