django 中的软删除对象

2024-02-25

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

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

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

我已经尝试过中建议的内容使用自定义模型删除方法进行级联删除 https://stackoverflow.com/questions/29856011/cascading-delete-w-custom-model-delete-method,但这会严重破坏事情 - 除此之外它提倡使用已弃用的 use_for_lated_fields 管理器属性。

我开始认为,如果不影响 Django 私有的主要部分,我想要实现的目标是不可能的 - 很奇怪,因为这种软删除行为是许多 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
    

Ideas?

EDIT:所有这一切的要点(除了更彻底地搜索打包解决方案:-))是可以覆盖删除并使其正确,但这对于胆小的人来说并不容易。我将使用的包 - django-softdelete,我的起点的演变,从http://codespatter.com/2009/07/01/django-model-manager-soft-delete-how-to-customize-admin/ 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 软删除 https://github.com/scoursen/django-softdelete是一个为 Django 实现软删除的库,具有级联功能。它还存储变更集,并允许恢复删除(例如恢复整个级联)。

我不确定它的维护状态和质量如何,但它至少可以作为灵感,即使它本身不是解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

django 中的软删除对象 的相关文章

  • Django 似乎以 UTC 格式显示日期时间

    In settings py I have TIME ZONE Asia Singapore USE I18N True USE L10N True USE TZ True 如果用户 居住在新加坡 输入2013 10 07 01 00 A
  • django在服务器上同步数据库时出错

    我有一个完整运行的区域设置 django 应用程序 但我在迁移到 site5 服务器时遇到了麻烦 当我启动 django 时syncdb命令 我所有模型的表都已创建 但是然后 我猜当它创建关系表时 我收到以下错误 mysql excepti
  • 在 Django 1.7 中使用 html 发送电子邮件

    In 发送邮件 我们有一个新参数 html message Docs https docs djangoproject com en dev topics email send mail I have 电子邮件 html文件 我想发送我的消
  • 如何使用 django-sitetree?

    我正在尝试使用Django 站点树 https github com idlesign django sitetree但我不明白如何执行第 3 步 转到 Django 管理站点并添加一些树和树项目 如何在管理面板中制作站点树 我相信第一步是
  • Django / PIL - 上传图像时保存缩略图版本

    这是我的 forms py class UploadImageForm forms ModelForm class Meta model UserImages fields photo 这是我的 models py class UserIm
  • 类型错误:“WindowsPath”类型的参数不可迭代 - 在 django python 中[重复]

    这个问题在这里已经有答案了 每当我运行服务器或在终端中执行任何命令时 此错误都会显示在终端中 服务器正在运行并且网页工作正常 但是当我退出服务器或运行任何命令 如 python manage py migrate 时 会显示此错误 Watc
  • Django 尝试使用错误的数据库用户

    已解决 我使用的是 USERNAME 而不是之前尝试使用 Postgres 驱动程序时使用的 USER 我正在尝试将我的 django 项目连接到 RDS MySQL 数据库 我可以在 MySQL Workbench 和 mysql 命令行
  • 如何确定 Django 中用户何时出现空闲超时?

    我想审核用户在我的 Django 应用程序中遇到空闲超时的情况 换句话说 如果用户的会话 cookie 的过期日期超过了 settings py 中找到的 SESSION COOKIE AGE 用户将被重定向到登录页面 当这种情况发生时 也
  • Django 迁移 - 禁用系统检查

    我从 Django 1 7 升级到 Django 1 9 我有多次迁移 自从升级以来 我无法再创建新的数据库 问题是 django manage py migrate 运行检查 检查导入应用程序 URL 这些最终导入查找数据库的代码 我可以
  • Django的注释框架和CSRF

    据我了解 Django的评论框架 https docs djangoproject com en 1 4 ref contrib comments 专为匿名公众评论而设计 就像您通常在博客或文章下面看到的那样 换句话说 任何人都可以发表评论
  • 使用 Django ModelForm 上传个人资料图片

    我环顾过相关问题 但似乎没有一个答案有效 我正在尝试上传用户的个人资料图像并让它替换 覆盖 当前图像 保存图像后 我想将文件名更改为用户 ID 图像将以当前形式上传 但不会替换现有图像 例如 它将保存为 2 1 png class Phot
  • djangorest框架:从序列化器validate()方法设置字段级错误

    我有一个序列化程序 它根据其他字段的值验证字段 在错误响应中 我想将每个字段错误显示为字段错误 而不是显示 non field errors 下的所有内容 如果我提出错误 就会发生这种情况对象级验证方法中的 ValidationError
  • 如何将我自己的文件添加到 django 'static' 文件夹

    我读了django静态文件文档 https docs djangoproject com en 1 7 howto static files 并使我的 django 静态文件设置如下 设置 py PROJECT PATH os path r
  • 如何为 bcrypt.hashpw 设置盐?

    salt yhnqazolr123098765 password bcrypt hashpw password salt repeatpassword bcrypt hashpw repeatpassword salt 我在第二行遇到错误
  • Django Rest Framework 分页设置 - 内容范围

    6 30 15 我怎样才能让这个问题变得更好并且对其他人更有帮助 反馈会有帮助 谢谢 我使用 DRF 作为 Dojo Dgrid Web 应用程序的服务器端 Dojo 需要来自服务器的内容范围或范围响应 目前它不发送任何内容 因此 dgri
  • 在 MacOSX10.6 上运行 python 服务器时 MySQLdb 错误

    运行我的服务器 python manage py runserver 产生以下错误 django core exceptions ImproperlyConfigured 加载 MySQLdb 模块时出错 没有名为 MySQLdb 的模块
  • 如何在 Django Admin 的“更改”页面中显示内嵌上传的图像?

    我正在尝试在中显示内联上传的图像 变更列表 页面在 Django 管理中 这是我的代码如下 models py from django db import models class Product models Model name mod
  • Django:管理中的 AJAX ManyToManyField

    我要显示ManyToManyFields 在 admin 中就像filter horizontal确实如此 但会在用户在过滤器字段中键入内容时填充选项 有很多选项 一次性加载它们需要很多时间 I found django ajax 过滤字段
  • Django REST序列化器:创建对象而不保存

    我已经开始使用 Django REST 框架 我想做的是使用一些 JSON 发布请求 从中创建一个 Django 模型对象 然后使用该对象而不保存它 我的 Django 模型称为 SearchRequest 我所拥有的是 api view
  • 如何在 Django 中使用并发进程记录到单个文件而不使用独占锁

    给定一个在多个服务器上同时执行的 Django 应用程序 该应用程序如何记录到单个共享日志文件 在网络共享中 而不保持该文件以独占模式永久打开 当您想要利用日志流时 这种情况适用于 Windows Azure 网站上托管的 Django 应

随机推荐