2013-03-22 76 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