Разбить отношения на страницы в Django REST Framework?

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

Чтобы продемонстрировать использование примеров, аналогичных приведенным в документации:

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

Пример сериализованного вывода для альбома:

{
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse'
    'tracks': [
        {'order': 1, 'title': 'Public Service Annoucement'},
        {'order': 2, 'title': 'What More Can I Say'},
        {'order': 3, 'title': 'Encore'},
        ...
    ],
}

Это становится проблематичным, если в альбоме, скажем, сотни треков. Есть ли способ разбить «треки» на страницы в этом случае?

В идеале я знаю, что в подобных случаях «треки» должны указывать на URL-адрес API, который просто возвращает треки для определенного альбома, который, в свою очередь, можно легко разбить на страницы. Обратной стороной этого подхода является дополнительный запрос (и, следовательно, задержка и т. д.), необходимый для получения даже первых нескольких дорожек. В нашем случае важно, чтобы мы могли получить хотя бы несколько треков с помощью одного запроса к API альбома, а затем динамически загружать остальные треки по мере необходимости.

Предлагает ли DRF какую-либо конкретную функцию или шаблон для этого? Или есть обходные пути?


person Deepak Prakash    schedule 25.03.2013    source источник
comment
Примечание для дальнейшего использования. Это было рассмотрено в этой теме на Список рассылки Django REST framework.   -  person Tom Christie    schedule 27.03.2013
comment
Вы можете обратиться к моему ответу на ту же проблему здесь введите здесь описание ссылки   -  person Abdelrahmen Ayman    schedule 05.04.2018


Ответы (3)


Ответ, скопированный из ссылки Тома выше, на случай будущей битовой гнили:

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title')

class PaginatedTrackSerializer(pagination.PaginationSerializer):
    class Meta:
        object_serializer_class = TrackSerializer

class AlbumSerializer(serializers.ModelSerializer):

    tracks = serializers.SerializerMethodField('paginated_tracks')


    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')


    def paginated_tracks(self, obj):
        paginator = Paginator(obj.tracks.all(), 10)
        tracks = paginator.page(1)

        serializer = PaginatedTrackSerializer(tracks)
        return serializer.data
person Malcolm Box    schedule 08.05.2014
comment
Но как получить параметр размера страницы и параметр страницы внутри paginated_tracks? - person scott; 14.05.2014
comment
Ладно, я понял. request = self.context['request'] - person scott; 14.05.2014
comment
К сведению: Paginator от from django.core.paginator import Paginator. - person Chemical Programmer; 23.12.2015

Начиная с DRF 3.1, PaginationSerializer не поддерживается. Вот решение.


settings.py

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 5
}

serializers.py

from myapp.models import Album, Track
from rest_framework import pagination, serializers

class AlbumSerializer(serializers.HyperlinkedModelSerializer):
    tracks = serializers.SerializerMethodField('paginated_tracks')

    class Meta:
        model = Album

    def paginated_tracks(self, obj):
        tracks = Track.objects.filter(album=obj)
        paginator = pagination.PageNumberPagination()
        page = paginator.paginate_queryset(tracks, self.context['request'])
        serializer = TrackSerializer(page, many=True, context={'request': self.context['request']})
        return serializer.data

class TrackSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Track

ИЛИ вы можете заменить def paginated_tracks на

from rest_framework.settings import api_settings

    def get_paginated_tracks(self, obj):
        tracks = Track.objects.filter(album=obj)[:api_settings.PAGE_SIZE]
        serializer = TrackSerializer(tracks, many=True, context={'request': self.context['request']})
        return serializer.data

Это даже требует на один запрос меньше, чем указано выше.

person Chemical Programmer    schedule 23.12.2015
comment
это прекрасно работает для одного альбома, но если вы извлекаете список альбомов (который также требует разбиения на страницы), параметры разбиения на страницы, установленные в объекте запроса, вероятно, не должны использоваться для разбивки на страницы дорожек. - person eugene; 21.04.2016
comment
@eugene paginator.page_query_param = 'track_page' и paginator.page_size_query_param = 'track_page_size' решат это. также, если вы return paginator.get_paginated_response(serializer.data).data вывод согласуется с нумерацией страниц на верхнем уровне. - person gonkan; 19.03.2018
comment
Когда я пробую первое решение, я обнаруживаю, что page, возвращаемое значение paginate_queryset, по-прежнему представляет собой простой список объектов. Согласно настраиваемым стилям разбивки на страницы , я думаю, что правильный способ получить данные с разбивкой на страницы — это вызвать get_paginated_response после вызова paginate_queryset. - person H.C.Liu; 06.02.2019

Методы Малкольма Бокса и Дипака Пракаша могут помочь сериализовать объекты отношений, но, как сказал @eugene ранее, он работает только для одного квасца. Для альбомов мы можем сделать это:

serializers.py

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')
        depth=1

apis.py

class getAPIView(generics.ListAPIView):
    serializer_class=TrackSerializer
    filter_backends = (filters.OrderingFilter,)
    def get_queryset(self):
        queryset=Track.objects.all()
        return queryset
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        serializer = self.get_serializer(page, many=True)
        data=serializer.data
        albums=Album.objects.values_list('album_name').all()
        trackObjs=[]
        albumObjs=[]
        self.categoryKeyList(albums,albumObjs)
        if page is not None:
            for p in page:
                for n,i in enumerate(albums):
                     if re.search(str(p.alum),str(i)):
                        albumObjs[n]['track'].append(p)
        data={}
        data['count']=self.get_paginated_response(self).data['count']
        data['next']=self.get_paginated_response(self).data['next']
        data['previous']=self.get_paginated_response(self).data['previous']
        data['pageNumber'] = self.paginator.page.number
        data['countPage'] = self.paginator.page.paginator._count
        serializer=ClientsCategorySerializer(categoryObjs,many=True)
        data['result']=serializer.data
        return Response({'data':data,'success':'1','detail':u'获得客户列表成功'})
    def categoryKeyList(self,albums,albumObjs):
        for i in albums:
            albumObjs={}
            albumObjs['album_name']=i[0]
            track=[]
            albumObj['track']=track
            albumObjs.append(albumObj)

Тогда вы можете получить ответ:

{
    data[
     {
          'album_name': 'The Grey Album',
          'tracks': [
                   {'order': 1, 'title': 'Public Service Annoucement'},
                   {'order': 2, 'title': 'What More Can I Say'},
                   {'order': 3, 'title': 'Encore'},
                      ...

      },
      {'album_name': 'The John Album',
          'tracks': [
                   {'order': 1, 'title': 'Public Annoucement'},
                   {'order': 2, 'title': 'What sd Can I Say'},
                   {'order': 3, 'title': 'sd'},
                      ...
},
 ......
}
person jiaojiao wang    schedule 11.01.2017