Ни один сайт не состоит только лишь из одной страницы. Будь то блог, новостной портал или даже домашняя страничка Васи Пупочкина. Материала много, страницы нужно как-то выводить. Вывод всех публикаций на одной странице является по сути своей идеей порочной: бесконечно прокручивать список статей неудобно для пользователя, а про нагрузку на сервер лучше даже не вспоминать.
Для решения этой задачи в Django есть несколько способов и сегодня предлагается рассмотреть один из них: стандартный пагинатор. Рассмотрим пример, где нужно получить список всех публикаций и затем вывести их постранично.
В примере используются всё те же модели, что и в предыдущем посте.
В класс Paginator
следует передать список объектов и количество элементов, которые
нужно отображать на одной странице. Далее используются методы класса для доступа к
этим элементам.
Модель публикации
# models.py
class Post(models.Model):
title = models.CharField(max_length=150)
body = models.TextField()
timestamp = models.DateTimeField()
author = models.ForeignKey(User)
meta_keywords = models.CharField(blank=True, max_length=200)
meta_description = models.TextField(blank=True, max_length=250)
Отображение (View)
post_lists
— получаем список всех публикаций, отсортированных по времени создания.
paginator
— передаём классу Paginator
наш список, указываем количество
элементов на одну страницу
paginator.page(1)
— возвращает объект Page
по переданному индексу
(начинается с единицы). Вызывает исключение InvalidPage
, если указанная
страница не существует.
paginator.page(paginator.num_pages)
— отобразить общее количество страниц
# views.py
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render_to_response
from django.template import RequestContext
from .models import Post
def news(request):
'''Show all news'''
posts_list = Post.objects.all().order_by('-timestamp')
paginator = Paginator(posts_list, 8)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
vars = dict(
posts=posts,
)
return render_to_response('news.html', vars, context_instance=RequestContext(request))
Шаблон
for post in posts
— итерация по элементам
post.has_previous
— возвращает True
в случае, если предыдущая страница существует
post.has_next
— возвращает True
в случае, если следующая страница существует
post.number
— выведет номер страницы
post.previous_page_number
— вернуть предыдущую страницу
post.next_page_number
— вернуть следующую страницу
{# news.html #}
{% extends 'base.html' %}
{% block title %}News{% endblock %}
{% block content %}
<div id="post">
{% for post in posts %}
<ul>
<li><a href="{% url 'news:one_new' post.id %}">{{ post.title}}</a></li>
</ul>
{{ post.timestamp }}
{{ post.author }}<br />
{{ post.body|truncatewords:80|safe }}<br />
<a href="{% url 'news:one_new' post.id %}">Читать полностью</a>
{% endfor %}
<div id="pages" align="center">
{% if posts.has_previous %}
<a href="?page={{ posts.previous_page_number }}">Previous</a>
{% endif %}
<span class="current">
Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
</span>
{% if posts.has_next %}
<a href="?page={{ posts.next_page_number }}">Next</a>
{% endif %}
</div>
</div>
{% endblock %}
Страница документации: Pagination