Django F()对象和自定义保存了怪异

时间:2014-03-05 14:23:14

标签: python django django-models

我一直在使用Django F()对象来更新我的模型,以避免竞争条件。

我的模型也有自定义保存方法(我希望反叛者的范围从0到100)。

以下是一些示例代码:

class World(models.Model):
    ...
    world.rebels = models.IntegerField(default=0)
    ...

    def save(self, *args, **kwargs):
        ...
        if self.rebels > 100:
            self.rebels = 100
        elif self.rebels < 0:
            self.rebels = 0  
        ...
        super(World, self).save(*args, **kwargs)

现在我有一个功能可以为反叛计数添加数量。

world = World.objects.get(worldid=1)
rebchange = 0

print world.rebels
>>> 0

world.rebels = F('rebels') + rebchange

print world.rebels
>>> (+: (DEFAULT: ), 0)

world.save()

print world.rebels
>>> 100

多奇怪吧?增量完全是错误的值!然后,我使用涉及self.rebels的条件注释掉了自定义保存方法,然后模型将正确的值保存到数据库中。 显然,(+: (DEFAULT: ), 0) > 100不知何故True,并触发更改为100。

我已将自定义保存方法更改为:

def save(self, fsave=False, *args, **kwargs):
    if fsave == False:
        ...
        if self.rebels > 100:
            self.rebels = 100
        elif self.rebels < 0:
            self.rebels = 0  
        ...
    super(World, self).save(*args, **kwargs)

在我的函数中,然后我调用world.save()两次:

world = World.objects.get(worldid=1)
rebchange = 0
world.rebels = F('rebels') + rebchange
world.save(fsave=True)
world.save()

print world.rebels
>>> 0

为了能够在保存F()对象时避免我的自定义保存,然后使用正确的值强制执行自定义保存。

这是预期的行为,如果是这样,是否有更简单的方法来完成我想要做的事情?

1 个答案:

答案 0 :(得分:2)

在比较Python中的不同类型时,数字总是在其他对象之前排序。因此,100总是低于F()对象。

你确实需要进行特殊情况测试;您可以改为测试self.rebelsF的实例:

def save(self, *args, **kwargs):
    ...
    if not isinstance(self.rebels, F):
        if self.rebels > 100:
            self.rebels = 100
        elif self.rebels < 0:
            self.rebels = 0  
    ...
    super(World, self).save(*args, **kwargs)

Python 2支持排序混合类型列表,同时保证稳定的排序顺序。

因为这种行为可能导致细微的意外错误(与您的情况完全相同),所以Python 3中已删除此行为,并且仅支持明确支持比较的类型。