使用django F()对象更新多个列

时间:2013-03-22 15:33:09

标签: python mysql django

我有一个模型,可以按每列一个整数统计数据存储统计信息。我有一个处理所述统计数据更新的视图,如下所示:

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 个答案:

答案 0 :(得分: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)

答案 1 :(得分:2)

一种选择是逐个更新字段。

此代码将一次更新所有字段(因此它可能很慢,db-access-wise),但它是安全的(没有死锁,没有丢失更新)。

user_stats = PlayerStats.objects.get(user=user)
for stat, increment in new_stats.iteritems():
    user_stats.update(**{ stat: F(stat) + increment })