Отправка поля из ListAPIView в сериализатор в Django Rest Framework

Я создаю представление таблицы лидеров для REST API, который я разрабатываю в DRF. Мне нужна небольшая помощь в снижении неэффективности.

views.py

class LeaderboardAPIView(ListAPIView):
    serializer_class = UserSerializerLeaderboard
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        queryset = User.objects.all()
        queryset = list(queryset)
        queryset.sort(key=operator.attrgetter("total_karma"), reverse=True)
        queryset = queryset[:10]
        return queryset

serializers.py

class UserSerializerLeaderboard(serializers.ModelSerializer):
    score = serializers.SerializerMethodField(read_only=True)
    place = serializers.SerializerMethodField(read_only=True)

    def get_score(self, obj):
        return obj.total_karma

    def get_place(self, obj):
        return "1"

    class Meta:
        model = User
        fields = ("score", "place")

В настоящее время метод get_place возвращает значение 1. Я бы хотел, чтобы он возвращал фактическое место, на котором находится пользователь, отсортированное по баллам. Я знаю, что уже вычисляю это в наборе запросов, поэтому я не хочу повторять это неэффективно. Как я могу отправить место пользователя в сериализатор напрямую, а не повторять вычисления в методе?

Вы можете использовать функцию window function для аннотирования каждой строки в вашем наборе запросов с ее позицией/номером строки

Измените свойство total_karma и используемые методы на аннотации в вашем наборе запросов, чтобы вы могли упорядочить по этому полю и получить доступ к вычисленному результату из возвращаемых объектов без необходимости вычислять его снова

from django.db.models import Window, F, Sum
from django.db.models.functions import RowNumber


class LeaderboardAPIView(ListAPIView):
    serializer_class = UserSerializerLeaderboard
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        queryset = User.objects.all()
        queryset = queryset.annotate(
            post_score=Sum('postvote__vote'),
            comment_score=Sum('commentvote__vote')
        )
        queryset = queryset.annotate(
            total_karma=F('post_score') + F('comment_score')
        )
        queryset = queryset.order_by(
            '-total_karma'
        ).annotate(ruw_num=Window(
            expression=RowNumber(),
            order_by=F('total_karma').desc()
        ))[:10]
        return queryset

Serializer

class UserSerializerLeaderboard(serializers.ModelSerializer):
    score = serializers.SerializerMethodField(read_only=True)
    place = serializers.SerializerMethodField(read_only=True)

    def get_score(self, obj):
        return obj.total_karma

    def get_place(self, obj):
        return obj.ruw_num

    class Meta:
        model = User
        fields = ("score", "place")
Вернуться на верх