views:

215

answers:

1

Let's say that I have a 'Scores' table with fields 'User','ScoreA', 'ScoreB', 'ScoreC'. In a leaderboard view I fetch and order a queryset by any one of these score fields that the visitor selects. The template paginates the queryset. The table is updated by a job on regular periods (a django command triggered by cron).

I want to add a 'rank' field to the queryset so that I will have 'rank', 'User', 'ScoreA', 'ScoreB', 'ScoreC'. Moreover I want to remain database-independent (postgre is an option and for the time being it does not support row_number).

A solution may be that I can modify the job, so that it also computes and writes three different ranks in three new fields ('rankA', 'rankB', 'rankC').

I hope there is a (much) better solution?

+1  A: 

Why can't you compute the rank in the template?

{% for row in results_to_display %}
    <tr><td>{{forloop.counter}}</td><td>{{row.scorea}}</td>...
{% endfor %}

Or, you can compute the rank in the view function.

def fetch_ranked_scores( request ):
    query = Score.objects.filter( ... ).orderby( scorea )
    scores = [ r, s.scorea for r, s in enumerate(query) ]
    return render_to_response ( template, { 'results_to_display':scores } )

Or, you can compute the ranking in the model.

 class Score( models.Model ):
     ScoreA = models.IntegerField( ... )
     def ranked_by_a( self ):
         return enumerate( self.objects.filter(...).orderby( scorea ) )

I think there are many, many ways to do this.

S.Lott
Let's say I have a ten thousand objects which I paginate into 50 pages. In the first method, wouldn't the rank restart for each page? And wouldn't the calculation in the second and the third methods be repeated for each request?
shanyu
@ozgur: Correct. Redoing the calculation in the view function or the model definition is essentially zero cost. No additional database activity, no real complexity.
S.Lott
@ozgur: If handling 10,000 objects spread across 50 pages (who reads all 50?) is important, please update your question with these new facts.
S.Lott
Hmm. Between fetching 10,000 objects with values precalculated from db and fetching 10,000 objects and calculating the ranks for each request, I think the performance gauge is in the favor of the first. Am I missing something here?
shanyu
@ozgur: Incrementing a counter during the fetch has zero cost relative to the fetch. The DB order-by operation totally dominates the timeline. Anything you do during the view function to increment a counter is effectively zero cost. Too small to measure. Hardly worth even thinking about.
S.Lott
Thanks a lot. This has been insightful.
shanyu