2017-03-16 75 views
7

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

可以:

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) 
+0

当您尝试时会发生什么情况? –

+0

on all()我得到删除消息:例如:(1,{'accounts.SmsToken':1})。在last()上没有(None),但它也应该给出类似的消息(刚刚删除的记录pk)。 –

+1

'all()'返回一个'QuerySet','last()'一个实例。因此,我不会因为不同的行为而感到惊讶,因为第一个删除函数是Manager/QuerySet中的一个,而第二个删除函数是您的模型之一。当然,这并不能解释为什么删除不起作用... – arie

回答

8

当你在呼唤: SmsToken.objects.all().delete()您呼叫的查询集的删除方法。

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

django 1.9 queryset delete之后,方法返回删除项目的数目。 REF

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

但是例如delete方法Django已经知道只有一行会被删除。

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

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

所以你不能依靠方法的响应来检查删除工作是否正常。但是就Python的哲学而言,“请求宽恕而不是允许”。这意味着您可以依靠例外来查看删除操作是否正常进行。 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. 

注:我追赶通用的异常,因为在我的try块的唯一代码是delete。如果你想有其他的代码,那么你只能捕获特定的异常。

5

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

SoftDeletableModelprovides一个objects属性与manager限制其结果未去除的对象,并覆盖delete()作为除去,而不是实际删除它们来标记对象。

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

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