我正在使用以下设置在 Django 中实现软删除。我对幕后的 Django 不是很熟悉,所以我很感激任何关于我可能遇到的陷阱的反馈。我对 QuerySet 进行子类化特别不舒服。
基本思想是第一次调用delete
on aMyModel
会改变当前的日期时间MyModel
。date_deleted
一秒钟delete
实际上会删除该对象。(捕获 adelete
需要两个覆盖,一个在对象上,一个在 上QuerySet
,这可以绕过对象的delete
方法。)由于默认管理器会隐藏已删除的对象,因此已删除的对象会消失,并且必须通过deleted_objects
管理器显式请求。
使用此设置需要定义DeletionQuerySet
和DeletionManager
添加date_deleted
、objects
和deleted_objects
到您的模型。
谢谢,
PS,忘了提到这种从默认管理器中过滤对象的方法是强烈反对的!
class DeletionQuerySet(models.query.QuerySet):
def delete(self):
prev_deleted = self.filter(date_deleted__isnull=False)
prev_deleted.actual_delete()
prev_undeleted = self.filter(date_deleted__isnull=True)
prev_undeleted.update(date_deleted=datetime.datetime.now())
def actual_delete(self):
super(DeletionQuerySet, self).delete()
class DeletionManager(models.manager.Manager):
# setting use_for_related_fields to True for a default manager ensures
# that this manager will be used for chained lookups, a la double underscore,
# and therefore that deleted Entities won't popup unexpectedly.
use_for_related_fields = True
def __init__(self, hide_deleted=False, hide_undeleted=False):
super(DeletionManager, self).__init__()
self.hide_deleted = hide_deleted
self.hide_undeleted = hide_undeleted
def get_query_set(self):
qs = DeletionQuerySet(self.model)
if self.hide_deleted:
qs = qs.filter(date_deleted__isnull=True)
if self.hide_undeleted:
qs = qs.filter(date_deleted__isnull=False)
return qs
class MyModel(models.Model):
# Your fields here...
date_deleted = models.DateTimeField(null=True)
#the first manager defined in a Model will be the Model's default manager
objects = DeletionManager(hide_deleted=True)
deleted_objects = DeletionManager(hide_undeleted=True)
def delete(self):
if self.date_deleted is None:
self.date_deleted = datetime.datetime.now()
self.save()
else:
super(Agreement, self).delete()