5

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?

2 Answers 2

4
+50

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)
Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly what I was looking for, since I need to touch the database as little as possible.
2

One option is to update the fields one by one.

This code will not update all fields at once (so it might be slow, db-access-wise), but it is safe (no deadlocks, no lost updates).

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

1 Comment

That level of db access is not acceptable in my case, but thanks anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.