【问题标题】:using pagination in serializer django在序列化程序 django 中使用分页
【发布时间】:2016-11-12 09:39:16
【问题描述】:

我正在开发一个 django 项目,在该项目中我试图一次从服务器的Product 表中获取所有具有大于product_sync_tsupdate_ts 字段的产品,但由于产品数量很大这需要大量时间来获取所有数据。我还返回当前时间戳以及数据。现在我想对结果进行分页。

我以前的代码:

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

我如何尝试修改它以进行分页:

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)

这工作正常,我得到了分页结果,但问题是我无法将下一页和上一页信息发送给客户端。客户端无法知道有效(非空)页数是多少。

有人可以建议我如何修改我的代码以便这样做。

【问题讨论】:

    标签: django pagination django-rest-framework serialization


    【解决方案1】:

    下面是一个如何使用APIView 类和PageNumberPagination 分页类对结果进行分页的示例:

    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)
    

    阅读DRF - PageNumberPagination来配置你的分页

    【讨论】:

    • 另外,我怎样才能添加 page_size 和 current_page_number 以及下一个和上一个??
    • 我想自定义 get_paginated_response 方法,但我不确定我是否做得对
    • 嘿伙计,创建另一个问题来清楚地解释您的问题。我去看看:)
    • 是的,我想出了如何解决它。无论如何,谢谢:)
    【解决方案2】:

    GenericAPIViewget_paginated_response 方法返回

    return self.paginator.get_paginated_response(data)
    

    所以你只需要将这个 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)
    

    【讨论】:

    • 上面写着AttributeError: 'PaginatedProductList' object has no attribute 'get_paginated_response'
    • 抱歉你需要继承GenericAPIView Fixed
    • 好的。只需在分页器上直接调用get_paginated_response
    • 仍然无法正常工作..你确定 get_paginated_response 方法仍然存在于 DRF 3.0 中,因为我认为他们已弃用它。
    猜你喜欢
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 2016-12-15
    • 2018-04-25
    • 2022-01-11
    相关资源
    最近更新 更多