gpt4 book ai didi

django - django中的软删除对象

转载 作者:行者123 更新时间:2023-12-04 12:45:16 24 4
gpt4 key购买 nike

我正在尝试为 Django 模型实现一个通用的软删除模式。

模型有一个 is_deleted 字段,它将已删除的对象保留在 DB 中,但出于所有实际目的将它们隐藏:应遵循所有常规规则级联等,但实际删除除外。但是,管理应用程序应该仍然能够处理已删除的对象,以便删除(肯定将它们丢弃)或恢复它们。 (见下面的代码)

问题:这会破坏级联。我期望发生的事情是通过我在模型和自定义查询集上覆盖的方法级联发生的。实际发生的情况是它们被默认的查询集/管理器绕过,而默认的查询集/管理器也恰好使用了快速的 _raw_delete 内部 API。因此,级联删除不会发生,或者如果我在我的模型上调用 super().delete() 方法(然后是 save() ),则会对相关对象执行标准删除。

我已经尝试了 Cascading Delete w/ Custom Model Delete Method 中的建议, 但这严重破坏了事情 - 除了它提倡使用已弃用的 use_for_related_fields 管理器属性。

我开始认为,如果不影响 Django 私有(private)的主要分离,我想要实现的目标是不可能的 - 很奇怪,因为这种软删除行为是许多 DBMS 情况下的标准模式。

这就是我现在的位置:

  • 我为具有 is_deleted 字段的对象创建了一个自定义管理器和查询集:
    from django.db import models
    from django.db.models.query import QuerySet


    class SoftDeleteQuerySet(QuerySet):
    #https://stackoverflow.com/questions/28896237/override-djangos-model-delete-method-for-bulk-deletion
    def __init__(self,*args,**kwargs):
    return super(self.__class__,self).__init__(*args,**kwargs)

    def delete(self,*args,**kwargs):
    for obj in self: obj.delete()

    #http://codespatter.com/2009/07/01/django-model-manager-soft-delete-how-to-customize-admin/
    # but use get_queryset, not get_query_set !!!
    class SoftDeleteManager(models.Manager):
    """ Use this manager to get objects that have a is_deleted field """
    def get_queryset(self,*args,**kwargs):
    return SoftDeleteQuerySet(model=self.model, using=self._db, hints=self._hints).filter(is_deleted=False)

    def all_with_deleted(self,*args,**kwargs):
    return SoftDeleteQuerySet(model=self.model, using=self._db, hints=self._hints).filter()

    def deleted_set(self,*args,**kwargs):
    return SoftDeleteQuerySet(model=self.model, using=self._db, hints=self._hints).filter(is_deleted=True)

    def get(self, *args, **kwargs):
    """ if a specific record was requested, return it even if it's deleted """
    return self.all_with_deleted().get(*args, **kwargs)

    def filter(self, *args, **kwargs):
    """ if pk was specified as a kwarg, return even if it's deleted """
    if 'pk' in kwargs:
    return self.all_with_deleted().filter(*args, **kwargs)
    return self.get_queryset().filter(*args, **kwargs)
  • 添加了一个基本模型来使用它:
    class SoftDeleteModel(models.Model):

    objects=SoftDeleteManager()
    is_deleted = models.BooleanField(default=False, verbose_name="Is Deleted")

    def delete(self,*args,**kwargs):
    if self.is_deleted : return
    self.is_deleted=True
    self.save()


    def erase(self,*args,**kwargs):
    """
    Actually delete from database.
    """
    super(SoftDeleteModel,self).delete(*args,**kwargs)

    def restore(self,*args,**kwargs):
    if not self.deleted: return
    self.is_deleted=False
    self.save()


    def __unicode__(self): return "%r %s of %s"%(self.__class__,str(self.id))

    class Meta:
    abstract = True
  • 和管理类来处理删除、恢复等:
    # for definitive deletion of models in admin
    def erase_model(modeladmin,request,queryset):
    """
    Completely remove models from db
    """
    for obj in queryset:
    obj.erase(user=request.user)

    def restore_model(modeladmin,request,queryset):
    """
    Restore a softdeletd model set
    """
    for obj in queryset:
    obj.restore(user=request.user)

    #http://codespatter.com/2009/07/01/django-model-manager-soft-delete-how-to-customize-admin/
    # but the method is now get_queryset.

    class SoftDeleteAdmin(admin.ModelAdmin):
    list_display = ('pk', '__unicode__', 'is_deleted',)
    list_filter = ('is_deleted',)
    actions=[erase_model, restore_model]

    def get_queryset(self, request):
    """ Returns a QuerySet of all model instances that can be edited by the
    admin site. This is used by changelist_view. """
    # Default: qs = self.model._default_manager.get_query_set()
    qs = self.model._default_manager.all_with_deleted()
    #TR()
    # TODO: this should be handled by some parameter to the ChangeList.
    ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
    if ordering:
    qs = qs.order_by(*ordering)
    return qs

    queryset=get_queryset

  • 想法?

    编辑:所有这一切的要点(除了更彻底地搜索打包的解决方案:-))是可以覆盖删除并使其正确,但这并不容易,对于微弱的哈特来说。我将要使用的包 - django-softdelete,我的起点的演变,从 http://codespatter.com/2009/07/01/django-model-manager-soft-delete-how-to-customize-admin/ 撕下来- 使用通过 Contenttype API 计算的 ChangeSet。

    除此之外,有几种情况根本不调用覆盖的 delete()(基本上,每次发生组删除时,django 都会采用跳过 model.delete() 头部的快捷方式)。

    在我看来,这是一个设计错误。如果覆盖它需要如此数量的大脑爆炸,model.delete() 实际上应该是 model._delete()。

    最佳答案

    也许你可以使用 django-paranoid

    类似于rails 的acts_as_paranoid 并且易于使用。

    您只需要使用 ParanoidModel 扩展模型。

    要查看已删除的对象,您可以使用 objects_with_deleted:

    MyModel.objects_with_deleted.last()

    如果你想硬删除一个对象,你只应该使用 True 参数:
    m = MyModel.objects.last()
    m.delete(True)

    关于django - django中的软删除对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50213991/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com