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

时间:2022-09-11 17:44:14

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.

我正在使用以下设置在Django中实现软删除。我对Django不太熟悉,所以我很感激我可能遇到的任何反馈。我特别不喜欢继承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.

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

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

使用此设置需要定义DeletionQuerySet和DeletionManager,并将date_deleted,objects和deleted_objects添加到模型中。

Thanks,

P.S., forgot to mention that this method of filtering objects out of the default manager is strongly discouraged!

P.S.,忘了提到强烈不鼓励这种从默认管理器中过滤对象的方法!

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()

1 个解决方案

#1


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.

我认为目前使用的任何东西,流行的,技术,没有办法有问题领域不可知,通用软删除。我认为它与历史/历史数据库系统的关系比我们使用的更多。我建议你不要绕过django的删除(这是一个很难删除)。保持原样。

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

您最有可能在我们的系统中拥有的“删除”是90%的情况,一个视觉删除...

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...

因为抱怨IsVisible,IsUnpublished(甚至是IsDeleted)搞砸了你的查询,他们抱怨你必须小心地包括它们......

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.

#1


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.

我认为目前使用的任何东西,流行的,技术,没有办法有问题领域不可知,通用软删除。我认为它与历史/历史数据库系统的关系比我们使用的更多。我建议你不要绕过django的删除(这是一个很难删除)。保持原样。

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

您最有可能在我们的系统中拥有的“删除”是90%的情况,一个视觉删除...

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...

因为抱怨IsVisible,IsUnpublished(甚至是IsDeleted)搞砸了你的查询,他们抱怨你必须小心地包括它们......

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.