В одній з попередніх статей було показано варіант впровадження сторінки з пагінацією статей, яка може бути головною сторінкою сайту, наприклад. При цьому застосовувався 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 .