2013-03-22 2 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 (таблица статистики может быть обновлена постоянно разными потоками)

словарь содержит ключи, которые отражают те, которые используются в базе данных, поэтому в момент я делаю это так:

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

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

Смежные вопросы