JavaRush /Курси /Модуль 3: Django /Налаштування базової пагінації

Налаштування базової пагінації

Модуль 3: Django
Рівень 19 , Лекція 1
Відкрита

Ми вже дійшли до моменту, коли наші API починають ставати розумними... ну, майже розумними. Сьогодні ми будемо вчитися керувати обсягом даних, які повертаються клієнту, використовуючи пагінацію. Адже ніхто не хоче, щоб їхній API повертав тисячу записів за один запит: клієнти зненавидять вас за зайвий трафік, а сервер — за навантаження. Отже, сьогодні ми налаштуємо базову пагінацію в Django REST Framework (абревіатура: DRF).

Чому пагінація така важлива?

Програмісти люблять каву, але не люблять стояти в черзі зі 100 людей. Припустимо, програміст вирішив піти відпочити (ну, або попрацювати з ноутбуком) у найближчу кав’ярню. Уявіть програму, яка відфільтровує дані про кав’ярні для вас. Ви хочете бачити список найближчих 5-10 кавових закладів, а не всі на Землі. Аналогічно, в API пагінація дозволяє повернути лише частину даних — наприклад, перші 10 записів. Клієнт може потім запитати наступну партію даних (наприклад, другу сторінку), і так далі.

Ось основні переваги пагінації в API:

  1. Покращення продуктивності. Сервер не перевантажується, а клієнт отримує відповідь швидше.
  2. Економія трафіку. Передається менше даних за один запит.
  3. Зручність для користувача. Інформація розбита на сторінки, що робить її більш доступною.

Отже, пагінація не тільки знімає навантаження з сервера, але й робить взаємодію з вашим API більш зручною.

Підтримка пагінації в DRF

Django REST Framework надає кілька готових класів для роботи з пагінацією:

  • PageNumberPagination — пагінація на основі сторінок (наприклад, "покажи мені сторінку 3, де кожна сторінка містить 10 елементів").
  • LimitOffsetPagination — пагінація з вказанням зсуву (offset) і ліміту записів (limit).
  • CursorPagination — пагінація на основі курсора (зазвичай використовується для великих обсягів даних).

Сьогодні наш фокус на найпопулярніших варіантах: PageNumberPagination і LimitOffsetPagination. Ми спробуємо налаштувати їх на глобальному та локальному рівнях.

Конфігурація пагінації в проєкті

Почнемо з налаштування базової пагінації в проєкті. Для цього нам, як завжди, достатньо трохи поколдувати у файлі settings.py. DRF дозволяє налаштувати пагінацію глобально, щоб вона автоматично застосовувалась до всіх представлень, де не передбачена кастомна логіка.

Давайте додамо базову пагінацію в settings.py

Для цього відкриваємо файл settings.py нашого проєкту і додаємо такі параметри:

# Налаштування REST Framework
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,  # Кількість елементів на одній сторінці
}

Що тут відбувається:

  • DEFAULT_PAGINATION_CLASS вказує DRF, який клас пагінації використовувати за замовчуванням.
  • PAGE_SIZE — це кількість елементів, які повинні повертатися на одній сторінці.

Тут ми налаштували так, щоб клієнт отримував по 10 записів за один запит.

Тепер, якщо ви зробите запит до вашого API, він автоматично поверне дані з поділом на сторінки.

Як це працює на практиці

Для тесту нам знадобиться view з виводом даних із моделі. Припустимо, у нас є модель Post, що представляє записи блогу. Ось як виглядає наш views.py:

from rest_framework.generics import ListAPIView
from .models import Post
from .serializers import PostSerializer

class PostListView(ListAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

Відкриваючи в браузері URL-адресу цього view або роблячи GET-запит через Postman, ви помітите, що дані тепер повертаються з розділенням на сторінки.

Приклад відповіді з першою сторінкою:

{
    "count": 50,
    "next": "http://127.0.0.1:8000/api/posts/?page=2",
    "previous": null,
    "results": [
        {
            "id": 1,
            "title": "Перша запис",
            "content": "Контент першої запису"
        },
        {
            "id": 2,
            "title": "Друга запис",
            "content": "Контент другої запису"
        },
        ...
    ]
}

Тут:

  • count — загальна кількість об'єктів.
  • next — посилання на наступну сторінку (якщо вона є).
  • previous — посилання на попередню сторінку (якщо вона є).
  • results — масив об'єктів, які відносяться до поточної сторінки.

Якщо ви додасте параметр ?page=2 до вашого запиту, ви отримаєте наступний набір записів.

Налаштування глобальної пагінації

А що, якщо для різних API-представлень потрібно встановити різні параметри пагінації? DRF дозволяє налаштувати пагінацію не тільки глобально, але й локально — на рівні представлення.

Спробуємо переключитися на LimitOffsetPagination в одному конкретному представленні. Ось як це зробити:

from rest_framework.pagination import LimitOffsetPagination
from rest_framework.generics import ListAPIView
from .models import Post
from .serializers import PostSerializer

class CustomLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 5  # Кількість об'єктів за замовчуванням
    max_limit = 100    # Максимально допустима кількість об'єктів

class PostListView(ListAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    pagination_class = CustomLimitOffsetPagination

Тепер наш API буде використовувати LimitOffsetPagination. Користувач може передати параметри limit (кількість об'єктів) і offset (зміщення). Приклад запиту:

GET /api/posts/?limit=5&offset=10

Відповідь API виглядатиме приблизно так:

{
    "count": 50,
    "next": "http://127.0.0.1:8000/api/posts/?limit=5&offset=15",
    "previous": "http://127.0.0.1:8000/api/posts/?limit=5&offset=5",
    "results": [
        {
            "id": 11,
            "title": "Одинадцятий запис",
            "content": "Контент одинадцятого запису"
        },
        ...
    ]
}

Тут параметри next і previous вказують посилання на сусідні "сторінки". Це особливо зручно, якщо у вас є лінивий скролінг у користувацькому інтерфейсі.

Корисні поради щодо налаштування пагінації

  1. Якщо ви використовуєте глобальну пагінацію, переконайтеся, що вона підходить для всіх ваших ендпоінтів. Наприклад, розмір сторінки PAGE_SIZE=10 може бути занадто малим або великим для різних API.
  2. Налаштовуючи пагінацію на рівні представлення (як у випадку з LimitOffsetPagination), спробуйте написати свій кастомний клас, щоб гнучко управляти налаштуваннями.
  3. Для великих даних або специфічних UI-компонентів (наприклад, каруселі з горизонтальним прокручуванням) краще використовувати CursorPagination. Але це тема для іншої лекції.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ