Вы можете использовать SerializerMethodField
в ChatSerializer
следующим образом:
messages = serializers.SerializerMethodField()
def get_messages(self, chat):
qs = Message.objects.filter(chat=chat).order_by('-date')[:50]
return MessageSerializer(instance=qs, many=True).data
Это запускает отдельный запрос для каждого Chat
экземпляра, но выбирает только необходимое количество строк. Вы должны настроить имена полей (chat
, date
) в зависимости от обстоятельств.
Альтернативный синтаксис @spiritsree нацелен на результаты в одном и том же SQL, используя неявную, а не явную фильтрацию:
qs = chat.messages.order_by('-date')[:50]
Единственное, чего следует избегать, это использовать prefetch_related('messages')
в queryset
из ViewSet
, который возвращает список Chat
, так как эта предварительная выборка не будет использоваться вообще и будет отбирать все сообщения из базы данных только для отказаться от использования.
Альтернатива подзапроса , отклоненная в другом ответе как медленная, на самом деле довольно интересна. Это сэкономит вам столько же обращений к базе данных, сколько и чатов. Однако взамен база данных должна выполнить вдвое больше внутренних запросов.
Из-за того, что лишние запросы достаточно легки (выбирая небольшое количество сообщений по идентификатору и упорядочивая их), сохраненные обходные пути могут легко восполнить их. В моих быстрых тестах этот метод был более чем в 10 раз быстрее, чем при использовании SerializerMethodField
. Это может зависеть в некоторой степени от данных; Проверьте сами:
from rest_framework import viewsets
from django.db.models import Prefetch, Subquery, OuterRef
class ChatViewSet(viewsets.ModelViewSet):
prefetch = Prefetch(
'messages',
queryset=Message.objects
.filter(id__in=Subquery(Message.objects
.filter(chat=OuterRef('chat_id'))
.order_by('-date')
.values_list('id', flat=True)[:4]))
.order_by('-date')
)
queryset = Chat.objects.prefetch_related(prefetch)