Пагинация


источник:

  • pagination.py


Пагинация

Django предоставляет несколько классов, которые помогают вам управлять постраничными данными - то есть данными, разделенными на несколько страниц, со ссылками "Предыдущая/Следующая".

Django documentation

DRF включает поддержку настраиваемых стилей пагинации. Это позволяет изменять, как большие наборы результатов разбиваются на отдельные страницы данных.

API пагинации может поддерживать любую из этих функций:

  • Ссылки пагинации, которые предоставляются как часть содержимого ответа.

  • Ссылки пагинации, включенные в заголовки ответа, такие как Content-Range или Link.

В настоящее время все встроенные стили используют ссылки, включенные как часть содержимого ответа. Этот стиль более доступен при использовании API с возможностью просмотра.

Пагинация выполняется автоматически, только если вы используете общие представления или наборы представлений. Если вы используете обычное APIView, вам нужно будет самостоятельно обратиться к API пагинации, чтобы убедиться, что вы возвращаете ответ с пагинацией. Пример смотрите в исходном коде классов mixins.ListModelMixin и generics.GenericAPIView.

Пагинацию можно отключить, установив для класса пагинации значение None.

Установка стиля пагинации

Стиль пагинации можно задать глобально, используя ключи настройки DEFAULT_PAGINATION_CLASS и PAGE_SIZE. Например, чтобы использовать встроенную пагинацию с ограничением/смещением, вы должны сделать следующее:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 100
}

Обратите внимание, что необходимо задать как класс пагинации, так и размер страницы, которая будет использоваться. По умолчанию и DEFAULT_PAGINATION_CLASS, и PAGE_SIZE имеют значение None.

Вы также можете установить класс пагинации для отдельного представления с помощью атрибута pagination_class. Обычно вы хотите использовать один и тот же стиль пагинации во всем API, хотя вы можете захотеть варьировать отдельные аспекты пагинации, такие как размер страницы по умолчанию или максимальный размер страницы, на основе каждого представления.

Изменение стиля пагинации

Если вы хотите изменить определенные аспекты стиля пагинации, вам нужно переопределить один из классов пагинации и установить атрибуты, которые вы хотите изменить.

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000
    page_size_query_param = 'page_size'
    max_page_size = 10000

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 100
    page_size_query_param = 'page_size'
    max_page_size = 1000

Затем вы можете применить ваш новый стиль к представлению с помощью атрибута pagination_class:

class BillingRecordsView(generics.ListAPIView):
    queryset = Billing.objects.all()
    serializer_class = BillingRecordsSerializer
    pagination_class = LargeResultsSetPagination

Или примените стиль глобально, используя ключ настройки DEFAULT_PAGINATION_CLASS. Например:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}

Описание API

PageNumberPagination

Этот стиль пагинации принимает номер страницы с одним номером в параметрах запроса.

Запрос:

GET https://api.example.org/accounts/?page=4

Ответ:

HTTP 200 OK
{
    "count": 1023,
    "next": "https://api.example.org/accounts/?page=5",
    "previous": "https://api.example.org/accounts/?page=3",
    "results": [

    ]
}

Настройка

Чтобы включить стиль PageNumberPagination глобально, используйте следующую конфигурацию и установите PAGE_SIZE по желанию:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100
}

В подклассах GenericAPIView вы также можете установить атрибут pagination_class для выбора PageNumberPagination на основе каждого вида.

Конфигурация

Класс PageNumberPagination включает ряд атрибутов, которые могут быть переопределены для изменения стиля пагинации.

Чтобы установить эти атрибуты, необходимо переопределить класс PageNumberPagination, а затем включить свой собственный класс пагинации, как указано выше.

  • django_paginator_class - Класс Django Paginator, который будет использоваться. По умолчанию это django.core.paginator.Paginator, что должно быть хорошо для большинства случаев использования.

  • page_size - Числовое значение, указывающее размер страницы. Если установлено, оно отменяет настройку PAGE_SIZE. По умолчанию имеет то же значение, что и ключ настройки PAGE_SIZE.

  • page_query_param - Строковое значение, указывающее имя параметра запроса, который будет использоваться для управления пагинацией.

  • page_size_query_param - Если установлено, это строковое значение, указывающее имя параметра запроса, который позволяет клиенту устанавливать размер страницы на основе каждого запроса. По умолчанию None, что означает, что клиент не может контролировать размер запрашиваемой страницы.

  • max_page_size - Если установлено, это числовое значение, указывающее на максимально допустимый размер запрашиваемой страницы. Этот атрибут действителен, только если page_size_query_param также установлен.

  • last_page_strings - Список или кортеж строковых значений, указывающих на значения, которые могут быть использованы с page_query_param для запроса последней страницы в наборе. По умолчанию ('last',)

  • template - Имя шаблона для использования при отображении элементов управления пагинацией в Web-интерфейсе API. Может быть переопределено для изменения стиля рендеринга или установлено в None для полного отключения HTML элементов управления пагинацией. По умолчанию используется "rest_framework/pagination/numbers.html".


LimitOffsetPagination

Этот стиль пагинации повторяет синтаксис, используемый при поиске нескольких записей в базе данных. Клиент включает в себя как 'limit', так и параметр запроса 'offset'. Лимит указывает на максимальное количество возвращаемых элементов и эквивалентен page_size в других стилях. Смещение указывает начальную позицию запроса по отношению к полному набору непагинированных элементов.

Запрос:

GET https://api.example.org/accounts/?limit=100&offset=400

Ответ:

HTTP 200 OK
{
    "count": 1023,
    "next": "https://api.example.org/accounts/?limit=100&offset=500",
    "previous": "https://api.example.org/accounts/?limit=100&offset=300",
    "results": [

    ]
}

Подключение

Чтобы включить стиль LimitOffsetPagination глобально, используйте следующую конфигурацию:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}

По желанию вы также можете задать ключ PAGE_SIZE. Если параметр PAGE_SIZE также используется, то параметр запроса limit будет необязательным и может быть опущен клиентом.

В подклассах GenericAPIView вы также можете установить атрибут pagination_class для выбора LimitOffsetPagination для каждого представления.

Настройка

Класс LimitOffsetPagination включает ряд атрибутов, которые могут быть переопределены для изменения стиля пагинации.

Чтобы установить эти атрибуты, вы должны переопределить класс LimitOffsetPagination, а затем включить свой собственный класс пагинации, как указано выше.

  • default_limit - Числовое значение, указывающее предел, который следует использовать, если он не указан клиентом в параметре запроса. По умолчанию имеет то же значение, что и ключ настройки PAGE_SIZE.

  • limit_query_param - Строковое значение, указывающее имя параметра запроса "limit". По умолчанию имеет значение 'limit'.

  • offset_query_param - Строковое значение, указывающее имя параметра запроса "offset". По умолчанию имеет значение 'offset'.

  • max_limit - Если установлено, то это числовое значение, указывающее на максимально допустимый лимит, который может быть запрошен клиентом. По умолчанию None.

  • template - Имя шаблона, который будет использоваться при отображении элементов управления пагинацией в Web-интерфейсе API. Может быть переопределено для изменения стиля рендеринга или установлено в None для полного отключения HTML элементов управления пагинацией. По умолчанию используется "rest_framework/pagination/numbers.html".


CursorPagination

Пагинация на основе курсора представляет непрозрачный индикатор cursor, который клиент может использовать для просмотра набора результатов. Этот стиль пагинации представляет только элементы управления перемоткой вперед и назад и не позволяет клиенту переходить к произвольным позициям.

Пагинация на основе курсора требует наличия уникального, неизменного порядка следования элементов в наборе результатов. Обычно таким упорядочиванием может быть временная метка создания записей, так как она представляет собой последовательный порядок для постраничного просмотра.

Пагинация на основе курсора является более сложной, чем другие схемы. Она также требует, чтобы набор результатов представлял фиксированный порядок, и не позволяет клиенту произвольно индексировать набор результатов. Однако она обеспечивает следующие преимущества:

  • Обеспечивает последовательное представление пагинации. При правильном использовании CursorPagination гарантирует, что клиент никогда не увидит один и тот же элемент дважды при листании записей, даже если новые элементы вставляются другими клиентами во время процесса пагинации.

  • Поддержка использования с очень большими наборами данных. При работе с очень большими наборами данных пагинация с использованием стилей пагинации на основе смещения может стать неэффективной или непригодной для использования. Вместо этого схемы пагинации на основе курсора имеют свойства фиксированного времени и не замедляются при увеличении размера набора данных.

Подробности и ограничения

Правильное использование пагинации на основе курсора требует некоторого внимания к деталям. Вам нужно подумать о том, в каком порядке вы хотите применять схему. По умолчанию используется порядок по "-created". Это предполагает, что в экземплярах модели должно быть поле временной метки "created", и будет представлено постраничное представление в стиле "временной шкалы", где первыми будут самые последние добавленные элементы.

Вы можете изменить порядок, переопределив атрибут 'ordering' класса пагинации, или используя класс фильтра OrderingFilter вместе с CursorPagination. При использовании OrderingFilter следует тщательно продумать ограничение полей, по которым пользователь может делать заказ.

Правильное использование пагинации курсора должно иметь поле упорядочивания, которое удовлетворяет следующим требованиям:

  • Должно быть неизменным значением, таким как временная метка, slug или другое поле, которое устанавливается только один раз, при создании.

  • Должно быть уникальным или почти уникальным. Хорошим примером являются временные метки с точностью до миллисекунды. Эта реализация пагинации курсора использует интеллектуальный стиль "позиция плюс смещение", что позволяет ей правильно поддерживать не строго уникальные значения в качестве упорядочивания.

  • Должно быть не нулевым значением, которое можно принудительно преобразовать в строку.

  • Не должно быть плавающей точкой. Ошибки точности легко приводят к неправильным результатам. Совет: используйте вместо этого десятичные числа. (Если у вас уже есть поле с плавающей запятой и вам нужно сделать постраничную запись по нему, можно воспользоваться командой [пример подкласса CursorPagination, который использует десятичные числа для ограничения точности, доступен здесь] (https://gist.github.com/keturn/8bc88525a183fd41c73ffb729b8865be#file-fpcursorpagination-py).)

  • Поле должно иметь индекс базы данных.

Использование поля упорядочивания, которое не удовлетворяет этим ограничениям, как правило, будет работать, но вы потеряете некоторые преимущества пагинации курсора.

Для получения более подробной технической информации о реализации, которую мы используем для пагинации курсоров, в статье "Building cursors for the Disqus API" блога дается хороший обзор основного подхода.

Подключение

Чтобы включить стиль CursorPagination глобально, используйте следующую конфигурацию, изменяя PAGE_SIZE по желанию:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
    'PAGE_SIZE': 100
}

В подклассах GenericAPIView вы также можете установить атрибут pagination_class для выбора CursorPagination на основе каждого вида.

Настройка

Класс CursorPagination включает ряд атрибутов, которые могут быть переопределены для изменения стиля пагинации.

Чтобы установить эти атрибуты, необходимо переопределить класс CursorPagination, а затем включить свой собственный класс пагинации, как указано выше.

  • page_size - числовое значение, указывающее размер страницы. Если установлено, оно отменяет настройку PAGE_SIZE. По умолчанию имеет то же значение, что и ключ настройки PAGE_SIZE.

  • cursor_query_param - Строковое значение, указывающее имя параметра запроса "cursor". По умолчанию 'cursor'.

  • orderering - Это должна быть строка или список строк, указывающих на поле, к которому будет применяться пагинация на основе курсора. Например: ordering = 'slug'. По умолчанию используется -created. Это значение также может быть переопределено с помощью OrderingFilter в представлении.

  • template - Имя шаблона, который будет использоваться при отображении элементов управления пагинацией в API просмотра. Может быть переопределено для изменения стиля рендеринга или установлено в None для полного отключения HTML элементов управления пагинацией. По умолчанию используется "rest_framework/pagination/previous_and_next.html".


Пользовательские стили пагинации

Чтобы создать собственный класс сериализатора пагинации, необходимо унаследовать подкласс pagination.BasePagination, переопределить методы paginate_queryset(self, queryset, request, view=None) и get_paginated_response(self, data):

  • Метод paginate_queryset передается начальному кверисету и должен возвращать итерируемый объект. Этот объект содержит только данные запрашиваемой страницы.

  • Метод get_paginated_response передается сериализованным данным страницы и должен возвращать экземпляр Response.

Обратите внимание, что метод paginate_queryset может установить состояние экземпляра пагинации, которое впоследствии может быть использовано методом get_paginated_response.

Пример

Предположим, мы хотим заменить стандартный стиль вывода пагинации на модифицированный формат, который включает следующую и предыдущую ссылки во вложенном ключе 'links'. Мы можем указать пользовательский класс пагинации следующим образом:

class CustomPagination(pagination.PageNumberPagination):
    def get_paginated_response(self, data):
        return Response({
            'links': {
                'next': self.get_next_link(),
                'previous': self.get_previous_link()
            },
            'count': self.page.paginator.count,
            'results': data
        })

Затем нам нужно будет установить пользовательский класс в нашей конфигурации:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
    'PAGE_SIZE': 100
}

Обратите внимание, что если вам важно, как порядок ключей отображается в ответах в Web-интерфейсе API, вы можете использовать OrderedDict при построении тела постраничных ответов, но это необязательно.

Использование вашего пользовательского класса пагинации

Чтобы ваш пользовательский класс пагинации использовался по умолчанию, используйте параметр DEFAULT_PAGINATION_CLASS:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
    'PAGE_SIZE': 100
}

Ответы API для конечных точек списка теперь будут включать заголовок Link, вместо того чтобы, например, включать ссылки пагинации как часть тела ответа:

Настраиваемый стиль пагинации с использованием заголовка Link.


Элементы управления пагинацией HTML

По умолчанию использование классов пагинации приводит к отображению элементов управления пагинацией HTML в Web-интерфейсе API. Существует два встроенных стиля отображения. Классы PageNumberPagination и LimitOffsetPagination отображают список номеров страниц с предыдущим и следующим элементами управления. Класс CursorPagination отображает более простой стиль, в котором отображаются только предыдущий и следующий элементы управления.

Настройка элементов управления

Вы можете переопределить шаблоны, которые отображают элементы управления пагинацией HTML. Есть два встроенных стиля:

  • 'rest_framework/pagination/numbers.html'

  • 'rest_framework/pagination/previous_and_next.html'

Предоставление шаблона с любым из этих путей в глобальном каталоге шаблонов переопределит рендеринг по умолчанию для соответствующих классов пагинации.

В качестве альтернативы вы можете полностью отключить элементы управления HTML-пагинацией, создав подкласс одного из существующих классов и установив template = None в качестве атрибута класса. Затем вам нужно будет настроить ключ параметров DEFAULT_PAGINATION_CLASS, чтобы использовать ваш пользовательский класс в качестве стиля пагинации по умолчанию.

Низкоуровневый API

Низкоуровневый API для определения того, должен ли класс пагинации отображать элементы управления или нет, раскрывается как атрибут display_page_controls на экземпляре пагинации. Пользовательские классы пагинации должны быть установлены в True в методе paginate_queryset, если они требуют отображения элементов управления пагинацией HTML.

Методы .to_html() и .get_html_context() также могут быть переопределены в пользовательском классе пагинации для дальнейшей настройки отображения элементов управления.


Пакеты сторонних производителей

Также доступны следующие пакеты сторонних производителей.

DRF-extensions

Пакет DRF-extensions включает класс-миксин PaginateByMaxMixin, который позволяет вашим клиентам API указывать ?page_size=max для получения максимально допустимого размера страницы.

drf-proxy-pagination

Пакет drf-proxy-pagination включает класс ProxyPagination, который позволяет выбирать класс пагинации с помощью параметра запроса.

Пакет django-rest-framework-link-header-pagination включает класс LinkHeaderPagination, который обеспечивает пагинацию через HTTP-заголовок Link, как описано в документации GitHub REST API.

Last updated