Добавляем пагинацию (pagination)

Курс по Django: https://stepik.org/a/183363

На этом занятии мы рассмотрим возможность разбивки списка данных на отдельные страницы. Например, у нас имеется API-запрос на список известных женщин:

http://127.0.0.1:8000/api/v1/women/

Понятно, что в БД может быть огромное количество записей по женщинам и выдавать их все по данному запросу было бы крайне неразумно из-за слишком большого объема данных. Для этого и вводится пагинация, то есть, разбивка на отдельные страницы по несколько записей на каждой. И как это сделать в рамках Django REST Framework мы сейчас увидим.

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

https://www.django-rest-framework.org/api-guide/pagination/

Я прямо буду ей следовать. Фактически, все что нам нужно, это прописать в словаре REST_FRAMEWORK, следующие строчки:

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

Ключ 'DEFAULT_PAGINATION_CLASS' позволяет задать класс пагинации, который будет применяться по умолчанию к выдаваемым спискам данных. В Django REST Framework имеется встроенный класс LimitOffsetPagination и мы его здесь указываем. Второй ключ 'PAGE_SIZE' задает число записей (в нашем случае женщин) на странице. Я указал два, чтобы мы могли видеть пагинацию в действии.

Запустим, теперь, тестовый веб-сервер:

python manage.py runserver

и откроем в браузере страницу:

http://127.0.0.1:8000/api/v1/women/

Как видите, у нас здесь с вами отобразился только первый фрагмент списка из двух записей. Кроме того, в JSON-ответе мы видим параметры:

  • "count" – общее число записей;
  • "next" – ссылка на следующую страницу;
  • "previous" – ссылка на предыдущую страницу;
  • "results" – набор данных.

Также средства DRF позволяют нам в интерактивном режиме в браузере переключаться по страницам и просматривать их содержимое.

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

http://127.0.0.1:8000/api/v1/auth/users/

и здесь мы тоже видим включенный режим пагинации.

Но, если открыть страницу с одной записью:

http://127.0.0.1:8000/api/v1/women/9/

то никакой пагинации не будет, т.к. здесь нет списка записей в ответе.

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

Конечно, нам может потребоваться для определенных API-запросов настраивать свои параметры пагинации. Это делается достаточно просто с помощью определения собственных классов пагинации и подключения их к нужным видам. Давайте сделаем это для класса WomenAPIList.

Вначале определим свой класс пагинации WomenAPIListPagination, который унаследуем от базового класса в DRF – PageNumberPagination:

class WomenAPIListPagination(PageNumberPagination):
    page_size = 3
    page_size_query_param = 'page_size'
    max_page_size = 10000

Здесь:

  • page_size – число записей на страницу;
  • page_size_query_param – параметр запроса, в котором можно настраивать количество выдаваемых записей на страницу;
  • max_page_size – максимальное количество записей на странице для запроса page_size_query_param.

Сейчас мы увидим, как все это работает. Подключим класс пагинации в классе WomenAPIList:

class WomenAPIList(generics.ListCreateAPIView):
    queryset = Women.objects.all()
    serializer_class = WomenSerializer
    permission_classes = (IsAuthenticatedOrReadOnly, )
    pagination_class = WomenAPIListPagination

и в браузере откроем страницу:

http://127.0.0.1:8000/api/v1/women/

Видим, что выдается по три записи на странице, как это и настроено в нашем пользовательском классе. Но мы также можем выполнить и такой запрос:

http://127.0.0.1:8000/api/v1/women/?page_size=4

Здесь дополнительно прописан параметр page_size со значением 4. Теперь у нас на странице будет по четыре записи. Этот параметр можно использовать, если клиент пожелает изменить число выдаваемых записей на странице. Но их будет не более max_page_size. Например, если этот параметр установить в два:

    max_page_size = 2

то получим максимум две записи, несмотря на то, что page_size=4. В результате, мы на стороне сервера ограничиваем максимальный выдаваемый объем данных – своеобразная «защита от дурака», если клиент запросит слишком большой объем.

Вот так, достаточно просто, можно реализовать пагинацию в Django REST Framework и теперь, уверен, каждый из вас сможет это сделать в своем проекте.

Курс по Django: https://stepik.org/a/183363