如何在Django REST框架ViewSet子类中使用分页?

时间:2016-02-25 10:54:01

标签: python django django-rest-framework

我有一个viewsets.ViewSet的简单子类,如下所示:

from rest_framework import viewsets
from rest_framework.response import Response

from ..models import Entry, Sitting, Source, Venue
from .serializers import (
    SittingSerializer, SittingWithEntriesSerializer,
)

class SittingViewSet(viewsets.ViewSet):

    def list(self, request, version=None):
        queryset = Sitting.objects.order_by('id')
        serializer = SittingSerializer(
            queryset, many=True, context={'request': request}
        )
        return Response(serializer.data)

    def retrieve(self, request, pk=None, version=None):
        prefetch_qs = Entry.objects.select_related('speaker')
        queryset = Sitting.objects.order_by('id') \
            .prefetch_related(Prefetch('entry_set', queryset=prefetch_qs))
        sitting = get_object_or_404(queryset, pk=pk)
        serializer = SittingWithEntriesSerializer(
            sitting, context={'request': request}
        )
        return Response(serializer.data)

但是,列表视图不是分页的,因为它是使用ModelViewSet的子类。我正在使用的设置是:

# Django Rest Framework settings:
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('pombola.api.permissions.ReadOnly',),
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'PAGE_SIZE': 10,
}

documentation建议查看mixins.ListModelMixingenerics.GenericAPIView类的源代码,但我不能轻易看到如何重新应用他们的工作来将结果分页到这些ViewSet方法

有人可以建议最简单的方法是更改​​此示例以获取list视图的分页吗?

5 个答案:

答案 0 :(得分:1)

您覆盖了list方法,因此它不会对您的数据进行分页。
如果你检查ListModelMixins我认为这可能是你的答案:

class SittingViewSet(
    viewsets.GenericViewSet,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin):

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(
            Sitting.objects.order_by('id')
        )

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = SittingSerializer(
                page, 
                many=True, 
                context={'request': request}
                )
            return self.get_paginated_response(serializer.data)

        serializer = SittingSerializer(
                queryset, 
                many=True, 
                context={'request': request}
                )
        return Response(serializer.data)

答案 1 :(得分:1)

尽管这是一个很晚的答案,但我为Django Rest Framework写了一个Q&A style example,它使非通用视图集具有分页功能。

默认情况下,只有viewsets.GenericViewSet具有自动分页(如果您在当然的设置中启用分页),因为它继承自generics.GenericAPIView

这给你留下了两个选择:

  1. 简单方法:

    mixins.ListModelMixin提供分页,因此您只需按如下方式声明您的视图集:

    class SittingViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    

    现在你有一个list()分页方法。

  2. 更难的方式: *

    您可以按照above给出的示例,在视图集中创建分页方法。
    list()代码必须源自上面提供的mixins.ListModelMixin的源代码 可以从文档或[paginator()] [4]

  3. 的源代码中复制paginate_queryset()get_paginated_response()generics.GenericApiView方法

答案 2 :(得分:0)

使用视图集和列表

在DRF中进行分页

这里我处理了一个异常如果页面为空,它将显示空记录

在设置中定义页面大小,此页面大小是全局的,并且在视图中由paginator_queryset使用

REST_FRAMEWORK = {     'PAGE_SIZE':10, }

  

在视图中

    from rest_framework import mixins, viewsets

    class SittingViewSet(viewsets.GenericViewSet,
        mixins.ListModelMixin):

        serializer_class = SittingSerializer
        queryset = Sitting.objects.all()
        serializer = serializer_class(queryset, many=True)

        def list(self, request, *args, **kwargs):
            queryset =self.filter_queryset(Sitting.objects.all().order_by('id'))

            page = request.GET.get('page')

            try: 
                page = self.paginate_queryset(queryset)
            except Exception as e:
                page = []
                data = page
                return Response({
                    "status": status.HTTP_404_NOT_FOUND,
                    "message": 'No more record.',
                    "data" : data
                    })

            if page is not None:
                serializer = self.get_serializer(page, many=True)
                data = serializer.data
                return self.get_paginated_response(data)

            # serializer = self.get_serializer(queryset, many=True)
            return Response({
                "status": status.HTTP_200_OK,
                "message": 'Sitting records.',
                "data" : data
            })
  

**指注意:如果您不使用Order_by,它将显示异常,因为此列表

     
    

给出无序列表。**

  

答案 3 :(得分:0)

**使用API​​View在DRF中进行分页,如果没有序列化程序类**

这里我使用了django paginator,非常简单

  

在视图中

from rest_framework.views import APIView
class SittingView(APIView):

 """This is a API code so when at e.g. (url /sitting-record/?page=2) is entered it will show 10 records for page 2 and if page is empty it will show empty"""

  def get(self, request, format=None):

    """Here 10 is the page size, that means 10 record per page"""
    sitting = Sitting.objects.all().order_by('id')
    sitting_paginator = Paginator(sitting, 10)

    """this gets the page page from url and if not given it set default page is 1"""
    page = request.GET.get('page')
    page = 1 if not page else page 

    try:
        paginated_setting = sitting_paginator.page(page)
    except Exception as e:
        paginated_setting = []   

    """you can retrieve or iterate the records fields from paginator_setting and then send the data in response"""
    data = {
        "setting records" : paginated_setting,
    }

    return Response({
        "status" : status.HTTP_200_OK,
        "messgae" : "Sitting content",
        "data"  : data
        })

答案 4 :(得分:0)

简单的解决方案。让我们以auth模型为例。

from django.contrib.auth.models import User

from rest_framework.pagination import PageNumberPagination
from rest_framework import viewsets

from .serializer import UserSerializer


class UserViewSet(viewsets.ViewSet):
    def list(self, request):
        queryset = User.objects.all()
        pagination = PageNumberPagination()
        qs = pagination.paginate_queryset(queryset, request)
        serializer = UserSerializer(qs, many=True)
        return pagination.get_paginated_response(serializer.data)