Как ранжировать студентов по общему количеству баллов в Django QuerySet при фильтрации результатов

Я работаю над Django-приложением, в котором мне нужно ранжировать студентов на основе их общих баллов, а затем фильтровать результаты. Я хочу ранжировать всех студентов на основе их общих баллов, но показывать только студентов, которые являются детьми определенного пользователя (руководителя).

class StudentQuerySet(SetFieldQuerySetMixin, models.QuerySet):
    """QuerySet for Student model"""

    def with_points(self) -> Self:
        """Adds a field indicating total points of a student."""
        return self.annotate(
            total_points=Coalesce(
                models.Sum("attendances__feedback__overall"), Value(0)
            )
        )

    def with_rank(self) -> Self:
        """Adds a field indicating rank of a student."""
        self = self.with_points()

        return self.annotate(
            rank=models.Window(
                expression=models.functions.Rank(),
                order_by=models.F("total_points").desc(),
            )
        )

class StudentLeaderboardMeListView(generics.ListAPIView):
    serializer_class = StudentLeaderboardSerializer
    permission_classes = [IsSupervisor]
    filter_backends = (DjangoFilterBackend,)
    filterset_class = StudentFilter

    def get_queryset(self):
        all_students = Student.objects.all().with_rank()
        top_3_ids = all_students.order_by("rank")[:3].values_list(
            "id", flat=True
        )
        queryset = all_students.exclude(id__in=top_3_ids).filter(
            parent=self.request.user
        )
        queryset = self.filter_queryset(queryset)
        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Код правильно ранжирует всех студентов на основе их общих баллов, но на ранжирование влияет последующая фильтрация (exclude(id__in=top_3_ids).filter(parent=self.request.user)). Мне нужно убедиться, что рейтинг вычисляется на основе всех студентов до применения фильтра. По сути, ранжирование не должно меняться на основе отфильтрованных результатов.

Как сделать так, чтобы рейтинг вычислялся по всему набору данных студентов, независимо от последующей фильтрации? Мне нужно, чтобы рейтинг rank вычислялся по всем студентам, но при этом можно было отфильтровать и отобразить студентов, которые являются детьми вошедшего в систему руководителя.

Я нашел решение. Просто нужно использовать django-cte библиотеку.

from django_cte import CTEManager, CTEQuerySet

class StudentQuerySet(SetFieldQuerySetMixin, CTEQuerySet, models.QuerySet):
    ...

class StudentManager(CTEManager, models.Manager):
    ...

а также на вид get_queryset() вот так

def get_queryset(self):
    all_students = Student.objects.all().with_rank()
    student_ranks = With(all_students)
    result = (
    student_ranks.queryset()
        .with_cte(student_ranks)
        .filter(parent=self.request.user, rank__gt=3)
    )
    queryset = self.filter_queryset(result)
    return queryset
Вернуться на верх