В одной из предыдущих статей был показан вариант внедрения страницы с пагинацией статей, которая может быть главной странице сайта, например. При этом применялся django-bootstrap3.
Но если страница не представляет какого-то особенного функционала, кроме отображения списка статей, например, то необходимо использовать классы дженерики. Одним из которых является ListView . Это позволит сократить программный код проекта и соответственно упростить его.
Класс ListView позволяет указать шаблон, который будет рендериться для отображения таблицы, указать модель данных или queryset, который необходимо будет показать, а также количество объектов на страницу, которые будут выводиться при пагинации.
IndexView
Давайте вспомним, как выглядел предыдущий вариант View класса для отображения списка страниц.
class IndexView(View): def get(self, request): context = {} # Забираем все опубликованные статье отсортировав их по дате публикации all_articles = Article.objects.filter(article_status=True).order_by('-article_date') # Создаём Paginator, в который передаём статьи и указываем, # что их будет 10 штук на одну страницу current_page = Paginator(all_articles, 10) # Pagination в django_bootstrap3 посылает запрос вот в таком виде: # "GET /?page=2 HTTP/1.0" 200, # Поэтому нужно забрать page и попытаться передать его в Paginator, # для нахождения страницы page = request.GET.get('page') try: # Если существует, то выбираем эту страницу context['article_lists'] = current_page.page(page) except PageNotAnInteger: # Если None, то выбираем первую страницу context['article_lists'] = current_page.page(1) except EmptyPage: # Если вышли за последнюю страницу, то возвращаем последнюю context['article_lists'] = current_page.page(current_page.num_pages) return render_to_response('home/index.html', context)
Если удалить все комментарии, то всё равно наберется строчек 15. К тому же это отдельный класс. А если таких View классов много, то может получиться, что в каждом будет дублирующийся код. Вот поэтому нужно использовать дженерики, такие как ListView.
Этот же класс, наследованный от ListView, может выглядеть следующим образом:
class IndexView(ListView): template_name = 'home/index.html' queryset = Article.objects.filter(article_status=True).order_by('-article_date') paginate_by = 10
Весьма неплохо, всего лишь 4 строки, но можно пойти ещё дальше и записать всё сразу в файле urls.py. А из файла views.py можно будет удалить IndexView .
from django.conf.urls import url from django.views.generic import ListView from knowledge.models import Article app_name = 'home' urlpatterns = [ url(r'^$', ListView.as_view( template_name='home/index.html', queryset=Article.objects.filter( article_status=True, ).order_by( '-article_date' ), paginate_by=10 ), name='index'), ]
django-bootstrap3
А вот при создании ссылок пагинации с django-bootstrap3 есть один нюанс. Дело в том, что в шаблоне bootstrap_pagination принимает объект типа Page. И если в старом варианте мы передавали в контекст как раз данный объект, то ListView генерирует обычный QuerySet , который не подходит для bootstrap_pagination. Но ещё ListView передаёт в контекст объект page_obj , который как раз подходит для bootstrap_pagination.
Давайте посмотрим, как будет выглядеть шаблон home/index.html теперь.
{% extends 'home/base.html' %} {% block page %} <h1>Публикации</h1> {% if article_lists %} {% for article in object_list %} <article> <a href="{{ article.get_absolute_url }}"> <h2>{{ article.article_title }}</h2> </a> {{ article.desctription|safe }} <p><a class="btn btn-default btn-sm" href="{{ article.get_absolute_url }}">Читать далее</a></p> </article> {% endfor %} {% endif %} {% load bootstrap3 %} {% bootstrap_pagination page_obj %} {% endblock %}
Как видите здесь два существенных изменения по сравнению с предыдущим вариантом:
- page_obj вместо article_lists в boostrap_pagination
- object_list вместо article_lists
Впрочем у ListView есть переменная context_object_name , которая отвечает за наименование переменной в контексте, так что можно было оставить и article_lists.
Для Django рекомендую VDS-сервера хостера Timeweb .