重写model.Manager方法后,Django无法删除单个对象

时间:2017-03-16 08:11:40

标签: python django django-models

我正在尝试在django manager(models.Manager)上重写get_by_natural_key方法。添加模型(NexchangeModel)后,我可以删除所有()对象,但单个 - 不能。

可以:

SmsToken.objects.all().delete()

不能:

SmsTokent.objects.last().delete()

代码:

from django.db import models
from core.common.models import SoftDeletableModel, TimeStampedModel, UniqueFieldMixin

class NexchangeManager(models.Manager):
    def get_by_natural_key(self, param):
        qs = self.get_queryset()
        lookup = {qs.model.NATURAL_KEY: param}
        return self.get(**lookup)


class NexchangeModel(models.Model):
    class Meta:
        abstract = True
    objects = NexchangeManager()

class SmsToken(NexchangeModel, SoftDeletableModel, UniqueFieldMixin):
    sms_token = models.CharField(
        max_length=4, blank=True)
    user = models.ForeignKey(User, related_name='sms_token')
    send_count = models.IntegerField(default=0)

2 个答案:

答案 0 :(得分:8)

当你打电话时: SmsToken.objects.all().delete()您正在调用查询集的删除方法。

但在SmsTokent.objects.last().delete()上你正在调用实例的删除方法。

django 1.9 queryset delete方法返回没有删除的项目。 REF

  

在Django 1.9中更改:   删除了描述已删除对象数的返回值。

但是在实例delete方法上,Django已经知道只会删除一行。

另请注意,querset的删除方法和实例的删除方法不同。

  

delete()[on a querset]方法执行批量删除,并且不会在模型[instance method]上调用任何delete()方法。但是,它会为所有已删除的对象(包括级联删除)发出pre_delete和post_delete信号。

因此,您不能依赖该方法的响应来检查删除是否正常。但就蟒蛇的哲学而言,请求宽恕而不是许可"。这意味着您可以依赖异常来查看删除是否以其应有的方式正常工作。 Django的ORM将引发适当的异常并在发生任何故障时进行适当的回滚。

所以你可以这样做:

try:
    instance.delete()/querset.delete()
except Exception as e:
    # some code to notify failure / raise to propagate it
    # you can avoid this try..except if you want to propagate exceptions as well.

注意:我正在捕获通用的Exception,因为我的try块中的唯一代码是delete。如果您希望获得其他代码,则必须仅捕获特定的例外。

答案 1 :(得分:5)

我认为SoftDeletableModel来自django-model-utils包裹?如果是这样,该模型的purpose将标记具有is_removed字段的实例,而不是实际删除它们。因此,可以预期在模型实例上调用delete() - 这是从last()得到的 - 实际上不会删除任何内容。

SoftDeletableModel provides objects属性manager将其结果限制为未删除的对象,并覆盖delete()以将对象标记为已删除实际上删除它们。

问题是您已将自己的经理定义为objects,因此SoftDeletableModel经理未被使用。您的自定义管理器实际上是从数据库中批量删除对象,这与执行软删除的目标相反。解决此问题的方法是让您的自定义管理器继承自SoftDeletableManagerMixin

class NexchangeManager(SoftDeletableManagerMixin, models.Manager):
    # your custom code