2013-03-22 48 views
4

我有一个模型,以每个列为基础在一个整数统计信息上存储统计信息。我有一个处理的更新视图所说的统计,像这样:使用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) 

我基本上得到我需要到添加存储在数据库中的当前状态统计数据的dicitonary。

我真的不想从模型中提取所有数据,然后再次更新,因为如果可能,我希望在数据库级别执行此操作。

一位同事建议我使用django的F()对象,以便将其从视图代码中推出,主要是为了保持它的线程安全并避免任何mysql死锁(stats表可能正在更新不断被不同的线程)

字典包含反映这些数据库中使用,所以在目前I'm做这样的键:

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()对象?

回答

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) 
+0

这正是我所期待的,因为我需要尽可能少地触摸数据库。 – gzzzur 2013-04-02 11:16:58

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 }) 
+0

的数据库访问级别是不是在我的情况下可以接受的,但无论如何感谢。 – gzzzur 2013-04-02 11:14:51