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

The*_*Hog 7 python django django-models

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

能够:

SmsToken.objects.all().delete()
Run Code Online (Sandbox Code Playgroud)

不能:

SmsTokent.objects.last().delete()
Run Code Online (Sandbox Code Playgroud)

码:

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)
Run Code Online (Sandbox Code Playgroud)

Som*_*Foo 8

在调用时: SmsToken.objects.all().delete()您正在调用queryset的delete方法.

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

在django 1.9 queryset delete方法之后返回没有删除的项目.REF

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

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

另请注意,querset的delete方法和实例的delete方法不同.

delete()[on a querset]方法执行批量删除,不会在模型上调用任何delete()方法[instance method].但是,它会为所有已删除的对象(包括级联删除)发出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.
Run Code Online (Sandbox Code Playgroud)

注意:我正在捕获泛型异常,因为我的try块中唯一的代码是delete.如果您希望使用其他代码,则必须仅捕获特定的例外.


Kev*_*nry 5

我假设它SoftDeletableModel来自django-model-utils包?如果是这样,该模型的目的是使用is_removed字段标记实例而不是实际删除它们.因此,可以预期调用delete()模型实例 - 这是你得到的last()- 实际上不会删除任何东西.

SoftDeletableModel 提供一个objects属性,其中一个管理器将其结果限制为未删除的对象,并覆盖delete()将对象标记为已删除而不是实际删除它们.

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

class NexchangeManager(SoftDeletableManagerMixin, models.Manager):
    # your custom code
Run Code Online (Sandbox Code Playgroud)