如何在 Django Rest Framework 中动态设置分页?

我使用 Django Rest Framework 制作了一个 API 端点,它可以根据两个参数进行过滤。我正在尝试执行以下操作:当没有过滤器时,它应该检索 x 条记录,而当有一个或多个过滤器时,它需要检索更多记录。所以基本上如果有过滤器,我需要更改分页。

这是我尝试过的:

class My_View(viewsets.ModelViewSet):
    http_method_names = ['get']
    serializer_class = My_Serializer
    pagination_class = StandardResultsSetPagination

    def get_queryset(self):

        valid_filters = {
            'Name': 'Name',
            'Date': 'Unix__gte',
        }

        filters = {valid_filters[key]: value for key, value in self.request.query_params.items() if key in valid_filters.keys()}

        if len(filters) == 0:
            pagination_class = StandardResultsSetPagination
        else:
            pagination_class = LargeResultsSetPagination

        queryset = My_Model.objects.filter(**filters)

        return queryset

这段代码应该做的是在没有过滤器的情况下将标准分页设置为 100,如果有过滤器,则设置为 200。

此代码不起作用,分页将始终设置为 StandardResultsSetPagination ,并且不会更改。我想是因为 get_queryset 是在设置分页之后调用的,所以以后不能再设置了。有没有办法做到这一点?

stack overflow How can i set pagination dynamically in Django Rest Framework?
原文答案
author avatar

接受的答案

您将需要重写分页类的 get_page_size 方法:

from rest_framework.pagination import LimitOffsetPagination

valid_filters = {'Name', 'Date'}
def _has_valid_filters(iterable):
    return not valid_filters.isdisjoint(iterable)

class MyPagination(LimitOffsetPagination):
    def get_page_size(self, request):
        if _has_valid_filters(request.query_params.items()):
            return 200
        else:
            return 100

class MyView(viewsets.ModelViewSet):
    pagination_class = MyPagination
    ...

答案:

作者头像

我知道它已经解决了但这里有更动态的方式。创建一个返回带有动态 PageNumberPaginationpage_size 子类的函数(您也可以添加其他属性,使它们成为动态的)

from rest_framework.pagination import PageNumberPagination

def customPagination(page_size):
    return type("SubClass", (PageNumberPagination,), {"page_size": page_size})

class MyViewA(viewsets.ModelViewSet):
    pagination_class = customPagination(page_size=20)
    ...

class MyViewB(viewsets.ModelViewSet):
    pagination_class = customPagination(page_size=50)
    ...