【问题标题】:Same Table Django ORM Soft Delete Method Okay?同表 Django ORM 软删除方法好吗?
【发布时间】:2010-11-04 22:29:33
【问题描述】:

我正在使用以下设置在 Django 中实现软删除。我对幕后的 Django 不是很熟悉,所以我很感激任何关于我可能遇到的陷阱的反馈。我对 QuerySet 进行子类化特别不舒服。

基本思想是在MyModel 上第一次调用delete 会将MyModeldate_deleted 更改为当前日期时间。第二个delete 将实际删除该对象。 (捕获delete 需要两个覆盖,一个在对象上,一个在QuerySet 上,这可以绕过对象的delete 方法。)由于默认管理器会隐藏已删除的对象,因此已删除的对象会消失,必须显式请求通过deleted_objects 经理。

使用此设置需要定义 DeletionQuerySetDeletionManager 并将 date_deletedobjectsdeleted_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


【解决方案1】:

我认为任何具有当前使用、流行的技术的东西,都没有办法让问题域不可知的通用软删除。 我认为它与历史/面向历史的数据库系统的联系比我们所使用的更多。 我建议您不要规避 django 的删除(这是硬删除)。保持原样。

您最有可能在我们的系统中进行的“删除”,在 90% 的情况下是可视删除...

在这方面,请尝试为您的特定域问题找到删除的同义词,并从项目开始就这样做。

因为抱怨 IsVisible、IsUnpublished(甚至 IsDeleted)会弄乱您的查询,所以他们抱怨您必须始终小心包含它们...

但这显然是对域问题的无知,如果域中存在可以使不可见或未发布的对象 - 当然当您查询要显示的所有对象的列表时,您应该从头开始,查询所有不可见和未发布的对象,因为这是以完整形式解决您的域问题的方式。

干杯。

【讨论】:

    猜你喜欢
    • 2021-12-19
    • 2011-02-02
    • 2019-02-21
    • 1970-01-01
    • 2021-01-15
    • 2020-09-12
    • 1970-01-01
    • 2018-05-30
    • 2020-01-05
    相关资源
    最近更新 更多