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