Sayangnya, ini bukan operasi yang mungkin karena (bagi saya) postgresql WHERE
operasi (filter/kecualikan) mempersempit baris sebelum fungsi agregasi dapat bekerja pada baris tersebut.
Satu-satunya solusi yang saya temukan adalah menghitung peringkat untuk semua Person
dengan queryset terpisah dan kemudian, untuk membubuhi keterangan queryset Anda dengan hasil ini.
Jawaban ini (lihat metode yang ditingkatkan) menjelaskan cara "menganotasi kumpulan kueri dengan data yang disiapkan secara eksternal dalam dict".
Inilah implementasi yang saya buat untuk model Anda:
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')))
Saya mengujinya dengan Django 2.1.3 dan Postgresql 10.5, jadi kodenya mungkin sedikit berubah untuk Anda.
Jangan ragu untuk berbagi versi yang kompatibel dengan Django 1.11!