【发布时间】:2010-11-04 22:29:33
【问题描述】:
我正在使用以下设置在 Django 中实现软删除。我对幕后的 Django 不是很熟悉,所以我很感激任何关于我可能遇到的陷阱的反馈。我对 QuerySet 进行子类化特别不舒服。
基本思想是在MyModel 上第一次调用delete 会将MyModel 的date_deleted 更改为当前日期时间。第二个delete 将实际删除该对象。 (捕获delete 需要两个覆盖,一个在对象上,一个在QuerySet 上,这可以绕过对象的delete 方法。)由于默认管理器会隐藏已删除的对象,因此已删除的对象会消失,必须显式请求通过deleted_objects 经理。
使用此设置需要定义 DeletionQuerySet 和 DeletionManager 并将 date_deleted、objects 和 deleted_objects 添加到您的模型中。
谢谢,
P.S.,忘了说这种从默认管理器中过滤对象的方法是strongly discouraged!
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()
【问题讨论】:
-
一个问题是级联删除。此设置不会通知外键删除。如果相关实体试图按照他们的(显然是有效的)外键回到
MyModel,他们将一无所获。即使程序员要实现级联软删除,当模型的默认管理器相互隐藏删除的记录时,软删除的模型如何相互引用? -
在这里查看我的答案。它对我们来说效果很好,只需在我们希望排除已删除模型的查询中使用 object_soft 而不是对象。这样外键查找仍然可以发生。 stackoverflow.com/questions/42123972/…
标签: django django-models django-orm soft-delete