Paginate отношения в 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 какую-либо конкретную функцию или шаблон для этого? Или есть какая-нибудь работа вокруг?

Ответ 1

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

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

Ответ 2

Так как 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

Для этого даже требуется меньше запросов, чем указано выше.

Ответ 3

Методы Malcolm Box и Deepak Prakash действительно могут помочь сериализовать объекты relathionship, но так же, как сказал @eugene, он работает только для одного Alum. Для альбомов мы можем сделать это:

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)

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

{
    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'},
                      ...
},
 ......
}

Ответ 4

Я создаю файлы api в представлении и получаю предупреждение об ошибке " Exception Type: KeyError Exception Value:'request'". Где вы установили request? Мой код api:

class getAlbumsList(APIView):
    def get(self,request,token,format=None):
        page = request.query_params.get('page')
        tracks = Albums.objects.filter(designer=2)[:3]
        serializer = AlbumSerializer(categorys, many=True)
        return serializer.data