4

So here are my models:

class Puzzles(models.Model):
    user = models.ForeignKey(User)
    puzzle = models.CharField(max_length=200)


class Scores(models.Model):
   user = models.ForeignKey(User)
   puzzle = models.ForeignKey(Puzzles)
   score = models.IntegerField(default=0)

So a user will have multiple scores. For a leaderboard page I want to output the users with the top overall score(added from all of the different scores). I'm really lost on what the python code would be to do this.

Any help appreciated, Thanks!

Sliq
  • 15,937
  • 27
  • 110
  • 143
Sean Peterson
  • 368
  • 4
  • 15
  • 1
    You might want to consider using the singular for your model names—`Puzzle` and `Score`—to be more consistent with Django style. It's up to you, of course. – Kevin Christopher Henry Aug 13 '13 at 06:06

3 Answers3

11

The easiest way to do this is with annotation.

from django.db.models import Sum

best = User.objects.annotate(total_score=Sum('scores__score')).order_by('-total_score')[0:10]

The documentation has an example that's pretty on point.

Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
  • 1
    "Cannot resolve keyword 'scores' into field. Choices are: id, puzzle, score, user" So I'm getting this error, and of course if i do this: Sum('score')), It won't sum the scores – Sean Peterson Aug 13 '13 at 07:35
  • If you renamed the `Scores` model (as I suggested above) or set the `related_name` attribute on the `user` field then the name will be different. – Kevin Christopher Henry Aug 13 '13 at 19:38
0

Is that a leaderboard page for all puzzles or just one? If for all you can try something like:

Score.objects.all().order_by('score')[:10] # limit 10
dan-klasson
  • 13,734
  • 14
  • 63
  • 101
  • So that's what I have right now. The problem is, that since the user has multiple scores associated with them, the scores need to be added up then displayed to the leaderboard. Otherwise it won't be a total score and user may have multiple entries on the leaderboard page – Sean Peterson Aug 13 '13 at 01:38
0

I think the best way to do this would be to make user profile model with a totalscore field. Then you can use a signal tied to the saving of score models to update the totalscore field. See below for help on using signals.

django how do i send a post_save signal when updating a user? https://docs.djangoproject.com/en/dev/ref/signals/

Then, you can simply do UserProfile.objects.all().order_by('totalscore')

Edit: Here is some information on user profiles. They should have a one-to-one with a User, and can then contain any custom fields that you like. Django user profile

Community
  • 1
  • 1
Peacemaker636
  • 97
  • 1
  • 1
  • 8