2013-03-25 130 views
11

我们为我们的API使用Django REST框架,我们需要分页返回多个项目的关系字段。Django REST框架中的分页关系?

为了证明使用类似于在documentation例子:

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

这成为问题,那里有说数百在相册轨道。在这种情况下,有没有办法对'曲目'进行分页?

理想情况下,我知道在这种情况下,'曲目'应该指向一个只返回某个特定专辑的曲目的API网址,而该网址可以轻松分页。这种方法的缺点是需要额外的请求(因此延迟等)才能获得前几个曲目。在我们的例子中,重要的是我们能够通过对Album API的单一请求获得至少一部分曲目,然后在需要时动态加载其余曲目。

DRF是否为此提供任何特定功能或模式?还是有任何解决办法?

+3

注意事项以供将来参考。随后在Django REST框架邮件列表的[此线程](https://groups.google.com/d/msg/django-rest-framework/UtVRH8mHwmU/C6C5OhkEQ80J)中进行了跟踪。 – 2013-03-27 15:37:38

回答

8

回答汤姆的链接在未来位腐烂的情况下复制上述:

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 
+0

但是如何获得paginated_tracks里面的页面大小参数和页面参数? – scott 2014-05-14 14:01:57

+1

好的,我明白了。 'request = self.context ['request']' – scott 2014-05-14 14:20:52

+0

FYI - 'Paginator'来自'from django.core.paginator import paginator'。 – 2015-12-23 17:42:44

8

由于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 

也可以为

0替代
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 

它甚至需要比上面少一个查询。

+0

这适用于单个相册,但如果您正在检索相册列表(也需要分页),则请求对象中设置的分页参数可能不应用于跟踪分页。 – eugene 2016-04-21 02:17:30

0

我在查看文件中创建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 
1

马尔科姆盒和迪帕克·普拉卡什的方法都可以帮助串行器relathionship对象,但正如@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 

的API。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'}, 
         ... 
}, 
...... 
}