Niestety nie jest to możliwa operacja, ponieważ (dla mnie) postgresql WHERE
operacja (filtrowanie/wykluczanie) zawęża wiersze, zanim funkcje agregacji będą mogły na nich pracować.
Jedynym rozwiązaniem, które znalazłem, jest po prostu obliczenie rankingu dla wszystkich Person
za pomocą oddzielnego zestawu zapytań, a następnie, aby dodać adnotacje do swojego zestawu zapytań tymi wynikami.
Ta odpowiedź (zobacz ulepszoną metodę) wyjaśnia, jak "dodawać w dykcie adnotację do zestawu zapytań za pomocą zewnętrznie przygotowanych danych".
Oto implementacja, którą wykonałem dla twoich modeli:
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')))
Przetestowałem go z Django 2.1.3 i Postgresql 10.5, więc kod może się nieznacznie zmienić.
Zapraszam do udostępnienia wersji zgodnej z Django 1.11!