Пагинация¶
Django предоставляет несколько классов, которые помогут вам управлять постраничными данными - то есть данными, разделенными на несколько страниц, со ссылками «Предыдущая/Следующая».
‒ Django documentation
Фреймворк REST включает поддержку настраиваемых стилей пагинации. Это позволяет изменять, как большие наборы результатов разбиваются на отдельные страницы данных.
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
- Имя шаблона, который будет использоваться при отображении элементов управления пагинацией в просматриваемом 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
- Имя шаблона, который будет использоваться при отображении элементов управления пагинацией в просматриваемом API. Может быть переопределено для изменения стиля рендеринга или установлено вNone
для полного отключения элементов управления пагинацией HTML. По умолчанию установлено значение"rest_framework/pagination/numbers.html"
.
CursorPagination¶
Пагинация на основе курсора представляет непрозрачный индикатор «курсор», который клиент может использовать для просмотра набора результатов. Этот стиль пагинации представляет только элементы управления перемоткой вперед и назад и не позволяет клиенту переходить к произвольным позициям.
Пагинация на основе курсора требует наличия уникального, неизменного порядка следования элементов в наборе результатов. Обычно таким упорядочиванием может быть временная метка создания записей, так как она представляет собой последовательный порядок для постраничного просмотра.
Пагинация на основе курсора сложнее, чем другие схемы. Она также требует, чтобы набор результатов представлял фиксированный порядок, и не позволяет клиенту произвольно индексировать набор результатов. Однако она обеспечивает следующие преимущества:
Обеспечивает последовательное представление пагинации. При правильном использовании
CursorPagination
гарантирует, что клиент никогда не увидит один и тот же элемент дважды при листании записей, даже если новые элементы вставляются другими клиентами в процессе пагинации.Поддерживает использование с очень большими наборами данных. При работе с очень большими наборами данных пагинация с использованием стилей пагинации на основе смещения может стать неэффективной или непригодной для использования. Вместо этого схемы пагинации на основе курсора имеют свойства фиксированного времени и не замедляются при увеличении размера набора данных.
Детали и ограничения¶
Правильное использование пагинации на основе курсора требует некоторого внимания к деталям. Вам нужно подумать о том, в каком порядке вы хотите применить схему. По умолчанию используется упорядочивание по "-created"
. Это предполагает, что в экземплярах модели должно быть поле временной метки «создано «, и будет представлено постраничное представление в стиле «временной шкалы», в котором первыми идут самые последние добавленные элементы.
Вы можете изменить порядок, переопределив атрибут 'ordering'
в классе pagination, или используя класс фильтра OrderingFilter
вместе с CursorPagination
. При использовании с OrderingFilter
следует тщательно продумать ограничение полей, по которым пользователь может упорядочивать данные.
Правильное использование пагинации курсора должно иметь поле упорядочивания, которое удовлетворяет следующим требованиям:
Должно быть неизменным значением, таким как временная метка, slug или другое поле, которое устанавливается только один раз, при создании.
Должны быть уникальными или почти уникальными. Хорошим примером являются временные метки с точностью до миллисекунды. Эта реализация пагинации курсора использует интеллектуальный стиль «позиция плюс смещение», что позволяет ей правильно поддерживать не строго уникальные значения в качестве упорядочивания.
Должно быть ненулевым значением, которое можно принудительно преобразовать в строку.
Не должно быть поплавком. Ошибки точности легко приводят к неправильным результатам. Подсказка: вместо этого используйте десятичные дроби. (Если у вас уже есть поле float и вам нужно сделать постраничную обработку, используйте example ``CursorPagination:doc:` subclass that uses decimals to limit precision is available here <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'
.ordering
= Это должна быть строка или список строк, указывающих на поле, к которому будет применяться пагинация на основе курсора. Например: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
}
Обратите внимание, что если вам важно, как порядок ключей отображается в ответах в просматриваемом API, вы можете использовать OrderedDict
при построении тела постраничных ответов, но это необязательно.
Использование пользовательского класса пагинации¶
Чтобы ваш пользовательский класс пагинации использовался по умолчанию, используйте параметр DEFAULT_PAGINATION_CLASS
:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
'PAGE_SIZE': 100
}
Ответы API для конечных точек списка теперь будут включать заголовок Link
, вместо того чтобы, например, включать ссылки на пагинацию как часть тела ответа:
*Настраиваемый стиль пагинации, использующий заголовок «Ссылка».
Пагинация и схемы¶
Вы также можете сделать элементы управления пагинацией доступными для автогенерации схемы, которую обеспечивает фреймворк REST, реализовав метод get_schema_fields()
. Этот метод должен иметь следующую сигнатуру:
get_schema_fields(self, view)
Метод должен возвращать список экземпляров coreapi.Field
.
Элементы управления пагинацией HTML¶
По умолчанию использование классов пагинации приводит к отображению элементов управления пагинацией HTML в просматриваемом 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-расширения¶
DRF-extensions package включает PaginateByMaxMixin mixin class, что позволяет вашим клиентам API указывать ?page_size=max
для получения максимально допустимого размера страницы.
drf-proxy-pagination¶
В drf-proxy-pagination package входит класс ProxyPagination
, который позволяет выбрать класс пагинации с помощью параметра запроса.
link-header-pagination¶
django-rest-framework-link-header-pagination:doc: package <https://github.com/tbeadle/django-rest-framework-link-header-pagination>` включает класс LinkHeaderPagination
, который обеспечивает пагинацию через заголовок HTTP Link
, как описано в Github’s developer documentation.