using pagination in serializer django

会有一股神秘感。 提交于 2019-12-12 03:44:30

问题


I am working on a django project in which I am trying to fetch all the products having update_ts field greater than product_sync_ts from Product table from the server at a time, but since the number of products is large this requires a large amount of time to fetch all data.I am also returning the current time stamp along with the data.Now I want to paginate the results.

My Previous code :

Views.py

@api_view(['GET'])
def productlist(request, format=None):
    product_sync_ts = request.GET.get(
            'product_sync_ts', None)
    if product_sync_ts:
        product =Product.objects.filter(
            update_ts__gt=product_sync_ts)
        )
        serializer = SyncedProductSerializer(
            instance={'products': product})
        return response(serializer.data)
    else:
        content = {'details': "Bad Request"}
        raise APIException400(request, content)

serializer.py

class SyncedProductSerializer(serializers.Serializer):
    product_sync_ts = serializers.SerializerMethodField(
        method_name='get_current_ts'
    )
    products = ProductSerializer(many=True, read_only=True)

    class Meta:
        fields = ('products', 'product_sync_ts')

    def get_current_ts(self, obj):
        product_sync_ts = datetime.utcnow().isoformat(' ')
        return product_sync_ts




class ProductSerializer(serializers.ModelSerializer):
    image_url = serializers.SerializerMethodField(
        method_name='change_image_url'
    )

    class Meta:
        model = Product
        fields = (
            'id',
            'name',
            'unit',
            'price',
            'image_url'
        )

    def change_image_url(self, obj):
        return ''.join([
            CDN_URL, str(obj.image_url)
        ]) if str(obj.image_url) else None

How I tried modifying it for pagination :

Views.py

class PaginatedProductList(APIView):

    def get(self, request, format=None):
        product_sync_ts = request.GET.get(
            'product_sync_ts', None)
        if product_sync_ts:
            product = GrProduct.objects.filter(
                update_ts__gt=product_sync_ts
            )
            paginator = Paginator(product, 1000)
            page = request.GET.get('page')
            try:
                 product = paginator.page(page)
            except PageNotAnInteger:
                 product = paginator.page(1)
            except EmptyPage:
                 product = paginator.page(paginator.num_pages)

             serializer = SyncedProductSerializer(
                 instance={'products': product})
            return Response(serializer.data)
        else:
            content = {'details': "Bad Request"}
            raise APIException400(request, content)

This is working fine, I am getting paginated results,but the problem is that I'm not able to send the next and previous page information to the client. The client has no way to know what are the valid(non-empty) number of pages.

Can someone suggest me how can I modify my code in order to do so.


回答1:


Here is an example how to paginate results with an APIView class and PageNumberPagination pagination class :

from rest_framework.views import APIView
from rest_framework.pagination import PageNumberPagination

class ProductList(APIView, PageNumberPagination):
    # number of items per page by default
    page_size = 1000
    # max number of items per page
    max_page_size = 1000

    def get_queryset(self):
        product_sync_ts = self.request.GET.get('product_sync_ts', None)
        if product_sync_ts:
            products = GrProduct.objects.filter(update_ts__gt=product_sync_ts)
            return self.paginate_queryset(products, self.request)

        raise APIException400(request, {'details': "Bad Request"})

    def get(self, request):
        products = self.get_queryset()
        serializer = SyncedProductSerializer(instance={'products': products})
        return self.get_paginated_response(serializer.data)

Read DRF - PageNumberPagination to configure your pagination




回答2:


There is GenericAPIView which has get_paginated_response method which returns

return self.paginator.get_paginated_response(data)

So you just need to subclass this Mixin

from rest_framework.generics import GenericAPIView

class PaginatedProductList(GenericAPIView): # Fixed

    def get(self, request, format=None):
        product_sync_ts = request.GET.get(
            'product_sync_ts', None)
        if product_sync_ts:
            product = GrProduct.objects.filter(
                update_ts__gt=product_sync_ts
            )
            paginator = Paginator(product, 1000)
            page = request.GET.get('page')
            try:
                 product = paginator.page(page)
            except PageNotAnInteger:
                 product = paginator.page(1)
            except EmptyPage:
                 product = paginator.page(paginator.num_pages)

            serializer = SyncedProductSerializer(
                 instance={'products': product})
            return paginator.get_paginated_response(serializer.data) # <- here it is
        else:
            content = {'details': "Bad Request"}
            raise APIException400(request, content)


来源:https://stackoverflow.com/questions/38290029/using-pagination-in-serializer-django

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!