Отправка поля из 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")