在Django中重写QuerySet.delete()

在Django中重写QuerySet.delete(),django,Django,我有一个Django模型,它将设置作为应用程序功能的核心。您不应该删除此模型。我正在尝试在整个应用程序中强制执行此操作。我在admin中禁用了delete函数,也在模型上禁用了delete方法,但是QuerySet有自己的delete方法。例如: MyModel.objects.all()[0].delete() # Overridden, does nothing MyModel.objects.all().delete() # POOF! 具有讽刺意味的是,Django文档说,为什么de

我有一个Django模型,它将设置作为应用程序功能的核心。您不应该删除此模型。我正在尝试在整个应用程序中强制执行此操作。我在admin中禁用了delete函数,也在模型上禁用了delete方法,但是QuerySet有自己的delete方法。例如:

MyModel.objects.all()[0].delete() # Overridden, does nothing

MyModel.objects.all().delete() # POOF!
具有讽刺意味的是,Django文档说,为什么delete()是QuerySet上的方法而不是Manager上的方法:

这是一种安全机制,可防止您意外请求Entry.objects.delete(),并删除所有条目

至少可以说,如何包含
.all()
是一种“安全机制”是值得怀疑的。相反,这实际上创建了一个无法通过常规方式关闭的后门(覆盖管理器)


有人知道如何在像QuerySet这样的核心上重写此方法,而不必对源代码进行修补吗

通过覆盖
管理器.get\u query\u set()
方法,可以覆盖
管理器的
默认
查询集

例子: 现在,
MyModel.objects.all()

有关更多信息:

mixin方法

使用@manji发布的类似配方

class DeactivateQuerySet(models.query.QuerySet):
    '''
    QuerySet whose delete() does not delete items, but instead marks the
    rows as not active, and updates the timestamps
    '''
    def delete(self):
        self.deactivate()

    def deactivate(self):
        deleted = now()
        self.update(active=False, deleted=deleted)

    def active(self):
        return self.filter(active=True)


class DeactivateManager(models.Manager):
    '''
    Manager that returns a DeactivateQuerySet,
    to prevent object deletion.
    '''
    def get_query_set(self):
        return DeactivateQuerySet(self.model, using=self._db)

    def active(self):
        return self.get_query_set().active()
并创建一个mixin:

class DeactivateMixin(models.Model):
    '''
    abstract class for models whose rows should not be deleted but
    items should be 'deactivated' instead.

    note: needs to be the first abstract class for the default objects
    manager to be replaced on the subclass.
    '''
    active = models.BooleanField(default=True, editable=False, db_index=True)
    deleted = models.DateTimeField(default=None, editable=False, null=True)
    objects = DeactivateManager()

    class Meta:
        abstract = True
其他有趣的东西

好吧,这对我来说是个大问题。我自己应该想到这一点,但谢谢你补充了我衰老的大脑的缺陷;)。django 1.6+中的方法被称为
get\u queryset(self)
。您可以删除上面的管理器类,只需执行以下操作:
objects=MyQuerySet.as\u manager()
从现在(Django 1.11)“get\u queryset”方法看起来像
def get\u queryset(self):返回MyQuerySet(model=self.model,using=self.\u db,hints=self.\u hints)
class DeactivateMixin(models.Model):
    '''
    abstract class for models whose rows should not be deleted but
    items should be 'deactivated' instead.

    note: needs to be the first abstract class for the default objects
    manager to be replaced on the subclass.
    '''
    active = models.BooleanField(default=True, editable=False, db_index=True)
    deleted = models.DateTimeField(default=None, editable=False, null=True)
    objects = DeactivateManager()

    class Meta:
        abstract = True