同表Django ORM软删除方法好吗?

发布于 2024-07-25 08:38:06 字数 2483 浏览 13 评论 0原文

我使用以下设置在 Django 中实现软删除。 我对 Django 的底层不太熟悉,所以我很感激任何有关我可能遇到的问题的反馈。 我对对 QuerySet 进行子类化特别不舒服。

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

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

I'm using the following setup to implement soft deletes in Django. I'm not very familiar with Django under the hood so I'd appreciate any feedback on gotchas I might encounter. I'm particular uncomfortable subclassing a QuerySet.

The basic idea is that the first call to delete on a MyModel changes MyModel's date_deleted to the current datetime. A second delete will actually delete the object. (Catching a delete requires two overrides, one on the object and one on the QuerySet, which can bypass an object's delete method.) Since the default manager will hide deleted objects, deleted objects disappear and must be explicitly requested via the deleted_objects manager.

Using this setup requires defining DeletionQuerySet and DeletionManager and adding date_deleted, objects, and deleted_objects to your model(s).

Thanks,

P.S., forgot to mention that this method of filtering objects out of the default manager is 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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

谷夏 2024-08-01 08:38:06

我认为任何当前使用的流行技术都无法实现与问题域无关的通用软删除。
我认为它更多地与历史/面向历史的数据库系统相关,而不是与我们所使用的数据库系统相关。
我建议你不要规避 django 的删除(这是硬删除)。 保持原样。

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

在这方面,请尝试为您的特定域问题找到与删除相同的同义词,并从一开始就执行此操作该项目。

因为抱怨 IsVisible、IsUnpublished (甚至 IsDeleted)搞乱了你的查询,他们抱怨你必须始终小心地包含它们......

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

干杯。

I think anything with current in use, popular, technologies, there is no way to have problem domain agnostic, generic soft deletes.
I think it is more linked to historical/history oriented database systems than to what we are used.
I recommend you to not circumvent django's delete (which is a hard delete). Keep as is.

The "delete" that you most likely will have in our system, is in 90% of the case, a visual delete ...

In this regard, try to find synonyms with delete for your specific domain problem and do this from the start of the project.

Because complain that a IsVisible, IsUnpublished (even IsDeleted) mess up your queries, they complain that you must always be careful to include them...

But this is obviously ignorance of the domain problem, if the domain has objects that can be made invisible, or become unpublished - of course when you query the list of all the objects you want to display, you should FROM THE START, QUERY ALL THE OBJECTS that are not visible and unpublished because this is how your domain problem is solved in a complete form.

Cheers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文