gzzzur gzzzur - 2 months ago 18
MySQL Question

Update multiple columns using django F() object

I have a model that stores stats on a one integer stat per column basis. I have a view that handles the update of said stats, like so:

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)


I basically get a dicitonary of stats that I need to to add to the current stats stored in the database.

I really don´t want to pull all of the data out of the model and then update it again, as I would like to do this on the database level, if possible.

A colleague suggested that I use django´s F() object in order to push this out of the view code, mostly in order to keep it thread-safe and avoid any mysql deadlocks (the stats table is potentially being updated continually by different threads)

The dictionary contains keys that mirror those used in the database, so at the moment I´m doing it like this:


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)


Anybody have any pointers as to how to achieve this by using the F() object?

okm okm
Answer

To update using models.F, you need to construct something like

qs.update(field_1=models.F('field_1')+field_1_delta,
          field_2=models.F('field_2')+field_2_delta, 
          ...)

For you code, it might be

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)
Comments