Helaas is het geen mogelijke operatie sinds (voor mij) de postgresql WHERE
bewerking (filteren/uitsluiten) verkleint de rijen voordat de aggregatiefuncties eraan kunnen werken.
De enige oplossing die ik heb gevonden is om eenvoudig de rangorde te berekenen voor alle Person
met een aparte queryset en vervolgens, om uw queryset te annoteren met deze resultaten.
Dit antwoord (zie de verbeterde methode) legt uit hoe je "een queryset kunt annoteren met extern voorbereide gegevens in een dictaat".
Dit is de implementatie die ik voor uw modellen heb gemaakt:
class PersonQuerySet(models.QuerySet):
def total_scores(self):
# compute the global ranking
ranks = (Person.objects
.annotate(total_score=models.Sum('session__gamesession__score'))
.annotate(rank=models.Window(expression=DenseRank(),
order_by=models.F('total_score').decs()))
.values('pk', 'rank'))
# extract and put ranks in a dict
rank_dict = dict((e['pk'], e['rank']) for e in ranks)
# create `WHEN` conditions for mapping filtered Persons to their Rank
whens = [models.When(pk=pk, then=rank) for pk, rank in rank_dict.items()]
# build the query
return (self.annotate(rank=models.Case(*whens, default=0,
output_field=models.IntegerField()))
.annotate(total_score=models.Sum('session__gamesession__score')))
Ik heb het getest met Django 2.1.3 en Postgresql 10.5, dus de code kan voor u licht veranderen.
Geef gerust een versie die compatibel is met Django 1.11!