Desværre er det ikke en mulig operation, da (for mig) postgresql WHERE
operation (filtrer/ekskluder) indsnævrer rækkerne, før aggregeringsfunktionerne kan arbejde på dem.
Den eneste løsning, jeg fandt, er simpelthen at beregne rangeringen for alle Person
med et separat forespørgselssæt og derefter for at annotere dit forespørgselssæt med disse resultater.
Dette svar (se den forbedrede metode) forklarer, hvordan man "annoterer et forespørgselssæt med eksternt forberedte data i en diktat".
Her er den implementering, jeg lavede til dine modeller:
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')))
Jeg testede det med Django 2.1.3 og Postgresql 10.5, så koden kan ændre sig let for dig.
Del gerne en version, der er kompatibel med Django 1.11!