我一直在使用 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() 对象时避免我的自定义保存,然后使用正确的值强制执行我的自定义保存。
这是预期的行为吗?如果是,是否有更简单的方法来完成我想要做的事情?
最佳答案
在 Python 中比较不同类型时,数字始终排在其他对象之前。因此,100
始终低于 F()
对象。
您确实需要为此进行特殊情况测试;您可以改为测试 self.rebels
是否是 F
的实例:
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 中已删除此行为,并且仅支持显式支持比较的类型。
关于python - Django F() 对象和自定义保存怪异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22200450/