Припустимо, ми на тій стадії, коли в базі даних нашого Django-додатку накопичилося стільки записів, що їх неможливо "з'їсти" за один раз. Давайте вивчимо пагінацію — інструмент, який допомагає розрізати дані на зручні порції. Готові? Починаємо!
Навіщо потрібна пагінація?
Уявіть собі гіпотетичний інтернет-магазин з мільйонами товарів. Якщо ви раптом вирішите вивести всі ці товари на одну веб-сторінку, то ваш сервер може попрощатися з адекватною продуктивністю, а ваш користувач — зі стабільним інтернет-з'єднанням. Це не опис кінця світу, але вже близько.
Пагінація дозволяє розбити величезні масиви даних (наприклад, записи QuerySet) на сторінки фіксованого розміру і надавати їх користувачеві порціями. Це корисно для відображення даних у таблицях, списках, стрічках соцмереж або будь-яких інших інтерфейсах, де обсяг інформації потенційно великий.
Ось ще пара причин освоїти пагінацію:
- Користувацький досвід: ніхто не хоче прокручувати нескінченну сторінку.
- Зменшення навантаження на сервер: менше переданих даних.
- Прискорення відображення даних: користувачі швидше отримують інформацію (маленькими шматочками).
Давайте одразу перейдемо до практики. Погнали!
Реалізація пагінації в Django
Django надає вбудовані інструменти для пагінації, які легко інтегруються з вашими представленнями та QuerySet. Основний герой тут — клас Paginator, про який ми поговоримо нижче.
1. Клас Paginator
Клас Paginator із модуля django.core.paginator бере QuerySet або список даних і "ріже" його на сторінки. Кожна сторінка представляє собою набір записів, з якими можна працювати.
Приклад використання Paginator
Почнемо з простого прикладу та створимо пагінатор. Припустимо, ми хочемо розбити список продуктів на порції по 10 штук:
from django.core.paginator import Paginator
# Список даних (наприклад, товари в інтернет-магазині)
products = ['Товар 1', 'Товар 2', 'Товар 3', 'Товар 4', 'Товар 5',
'Товар 6', 'Товар 7', 'Товар 8', 'Товар 9', 'Товар 10',
'Товар 11', 'Товар 12']
# Створюємо пагінатор з розміром сторінки = 5
paginator = Paginator(products, 5)
# Доступ до сторінок
page_1 = paginator.page(1) # Перша сторінка
page_2 = paginator.page(2) # Друга сторінка
# Виводимо дані на сторінці 1
print(page_1.object_list) # ['Товар 1', 'Товар 2', 'Товар 3', 'Товар 4', 'Товар 5']
# Перевіряємо, чи є наступна сторінка
print(page_1.has_next()) # True
print(page_2.has_next()) # False
# Загальна інформація про пагінацію
print(paginator.count) # Загальна кількість об'єктів (12)
print(paginator.num_pages) # Загальна кількість сторінок (3)
print(page_1.number) # Номер поточної сторінки (1)
Важливі методи об'єкта Paginator:
count: загальна кількість об'єктів.num_pages: кількість сторінок.page(number): отримання об'єкта сторінки за номером.has_next()іhas_previous(): перевірка наявності наступної або попередньої сторінки.
2. Пагінація у представленнях
Тепер ми готові інтегрувати пагінацію в додаток Django. Додамо пагінацію для списку об'єктів у нашому представленні.
Приклад інтеграції пагінації у представленні
Нехай у нас є модель Product:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
Додамо представлення для відображення продуктів із пагінацією:
# views.py
from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Product
def product_list_view(request):
products = Product.objects.all()
paginator = Paginator(products, 10) # Показувати по 10 записів на сторінці
page_number = request.GET.get('page') # Отримуємо номер сторінки із запиту
page_obj = paginator.get_page(page_number) # Отримуємо поточну сторінку
return render(request, 'product_list.html', {'page_obj': page_obj})
На що тут звернути увагу:
request.GET.get('page')— номер поточної сторінки передається через GET-параметр.paginator.get_page()— повертає об'єкт сторінки, навіть якщо номер сторінки відсутній або некоректний.
Шаблон для відображення
Тепер давайте додамо HTML-шаблон, який буде відображати дані з пагінацією:
<!-- templates/product_list.html -->
<!DOCTYPE html>
<html>
<head>
<title>Список продуктів</title>
</head>
<body>
<h1>Список продуктів</h1>
<ul>
{% for product in page_obj %}
<li>{{ product.name }} - {{ product.price }} грн.</li>
{% endfor %}
</ul>
<!-- Пагінація -->
<div>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">Попередня</a>
{% endif %}
<span>Сторінка {{ page_obj.number }} із {{ page_obj.paginator.num_pages }}</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Наступна</a>
{% endif %}
</div>
</body>
</html>
Цей шаблон виводить список продуктів, а нижче — елементи керування для переходу між сторінками.
3. Покращення користувацького досвіду
Пагінація працює, але давайте трохи наблизимо її до реальності. У реальних додатках користувачі очікують бачити номери сторінок, щоб одразу перейти до потрібної.
<div>
{% for num in page_obj.paginator.page_range %}
{% if num == page_obj.number %}
<strong>{{ num }}</strong> <!-- Поточна сторінка -->
{% else %}
<a href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
</div>
Тепер користувачі зможуть побачити номери всіх сторінок і легко перемикатися між ними.
Практичне завдання
- Створіть новий Django-додаток для управління студентами. Назвіть модель
Student. - Додайте атрибути
first_name,last_nameтаgrade(середній бал). - Заповніть базу даних тестовими даними (наприклад, 50 студентів).
- Налаштуйте представлення та шаблон для відображення студентів по 10 записів на сторінці.
- Реалізуйте пагінацію з відображенням номерів сторінок.
Ваш додаток має показувати список студентів із кнопками "Попередня", "Наступна" та номерами сторінок (наприклад, 1, 2, 3).
пагінація часто трапляється у реальному житті! Якщо ви впораєтесь із цим завданням, вас уже не злякає список із мільйона котиків (або студентів), який потрібно розбити на сторінки. І не забудьте протестувати пагінацію з порожнім QuerySet — там теж можуть бути сюрпризи!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ