使用django F()对象更新多个列
我有一个模型,它把统计数据存储在每一列一个整数的方式里。我有一个视图,用来处理这些统计数据的更新,代码大概是这样的:
class PlayerStats(models.Model):
#In game stats - these represent the actual keys sent by the game
NumberOfJumps = models.IntegerField(default=0)
NumberOfDoubleJumps = models.IntegerField(default=0)
NumberOfSilverPickups = models.IntegerField(default=0)
NumberOfGoldPickups = models.IntegerField(default=0)
NumberOfHealthPickups = models.IntegerField(default=0)
简单来说,我会得到一个包含需要添加到数据库当前统计数据的字典。
我其实不想把所有数据从模型中取出来再更新,因为我希望能直接在数据库层面上完成这个操作,如果可以的话。
我的同事建议我使用django的F()对象,这样可以把这个操作从视图代码中分离出来,主要是为了保持线程安全,避免mysql的死锁(因为统计表可能会被不同的线程不断更新)。
这个字典里的键和数据库中使用的键是一样的,所以目前我这样做:
def update_stats(new_stats):
player_stats = PlayerStats(user=user, **new_stats)
old_stats = player_stats.values()[0]
updated_stats = {}
for stat in new_stats:
if old_stat[stat]:
updated_stats[stat] = old_stats[stat] + new_stats[stat]
PlayerStats.objects.filter(user=user).update(**updated_stats)
有没有人能给我一些建议,如何使用F()对象来实现这个操作呢?
2 个回答
2
一种选择是逐个更新字段。
这段代码不会一次性更新所有字段(所以在数据库访问方面可能会比较慢),但它是安全的(不会出现死锁,也不会丢失更新)。
user_stats = PlayerStats.objects.get(user=user)
for stat, increment in new_stats.iteritems():
user_stats.update(**{ stat: F(stat) + increment })
4
要使用 models.F
来更新数据,你需要构建一个类似这样的东西:
qs.update(field_1=models.F('field_1')+field_1_delta,
field_2=models.F('field_2')+field_2_delta,
...)
对于你的代码来说,可能是这样的:
new_stats = {
'NumberOfHealthPickups': 99
# ...
}
updated_stats = {}
for stat in new_stats:
updated_stats[stat] = models.F(stat) + new_stats[stat]
PlayerStats.objects.filter(user=user).update(**updated_stats)