Как я могу динамически настраивать разбивку на страницы в Django Rest Framework?

#django #django-rest-framework

#python #django #django-rest-framework #django-viewsets

Вопрос:

Я создал конечную точку API, используя Django Rest Framework, ее можно фильтровать по двум параметрам. Я пытаюсь сделать следующее: когда нет фильтра, он должен получить 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 , что вызывается после установки разбивки на страницы, поэтому его нельзя будет установить позже. Есть ли какой-нибудь способ сделать это?

Ответ №1:

Я знаю, что это решаемая проблема, но здесь более динамичный способ. создайте функцию, которая возвращает PageNumberPagination подкласс class с dynamic page_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)
    ...
  

Ответ №2:

Вам нужно будет переопределить 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
    ...
  

Комментарии:

1. Этот ответ работает, когда я передаю query_params без метода caalling item. в противном случае он будет возвращать False каждый раз. мне нравятся _has_valid_filters(запрос. query_params)