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