はじめに
Djangoでページネーションの実装を行う必要があった。
その際、ページあたりのコンテンツの表示数を変更できるような実装を行いたかった。
今回は記事の一覧表示を行うアプリケーションを参考に実装方法を示す。
環境
- Python 3.7.3
- Django 2.1.6
- bootstrap4
Model
app/models.py
from django.db import models
class Article(models.Model):
title = models.CharField('title', max_length=255)
content = models.CharField('content', max_length=255)
Form
コンテンツの表示数を10〜50で変更できるようにしている。
また、今回はセレクトボックスで値を選択した時点で、submit
も行いたいため、
widget=forms.Select(attrs={'onchange': 'submit(this.form);
})
のようにしている。
app/forms.py
from django import forms
PAGINATE_BY_CHOICES = (
('', '-'*10),
(10, '10'),
(20, '20'),
(30, '30'),
(40, '40'),
(50, '50')
)
class Paginate(forms.Form):
paginate_by = forms.ChoiceField(
label='記事表示数',
widget=forms.Select(attrs={'onchange': 'submit(this.form);'}),
choices=PAGENATE_BY_CHOICES
)
View
Viewはdjango.view.View
を利用している。現在Djangoを勉強中のため、むやみに汎用ビューを使いたくないという理由からです。
デフォルトではページあたり10個の記事を表示します。
また、セッションに選択したページあたりのコンテンツ数を保存することで、ページ遷移しても大丈夫なようにしています。
app/views.py
from django.views import View
from .models import Article
from . import forms
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
class ArticleList(View):
paginate_by = 10
def get(self, request, **kwargs):
form = forms.Paginate(request.GET or None)
if 'paginate_by' in request.GET:
request.session['paginate_by'] = request.GET['paginate_by']
if 'paginate_by' in request.session:
self.paginate_by = request.session['paginate_by']
queryset = Article.objects.all()
paginator = Paginator(queryset, self.paginate_by)
try:
contents = paginator.page(kwargs['page'])
except PageNotAnInteger:
contents = paginator.page(1)
except EmptyPage:
contents = paginator.page(paginator.num_pages)
context = {}
context['contents'] = contents
context['form'] = form
return render(request, 'app/article_list.html', context)
URLs
app/urls.py
from django.urls import path
from . import views
app_name = 'app'
urlpatterns = [
path('article_list/<int:page>', views.ArticleList.as_view(), name='article_list'),
]
Template
app/aritcle_list.html
<form name="paginate_form" action="{% url 'main:user_list' 1 %}" method="get">
{{ form.paginate_by.label }} {{ form.paginate_by }}
</form>
<table class="table twitter-user-list">
<thead>
<tr>
<th scope="col">タイトル</th>
<th scope="col">内容</th>
</tr>
</thead>
<tbody>
{% for article in contents %}
<tr>
<td class="align-middle">{{ article.title }}</td>
<td class="align-middle">{{ article.content }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
{% if contents.has_previous %}
<li class="page-item">
<a href="{% url 'app:article_list' 1 %}" class="page-link">1</a>
</li>
<li class="page-item">
<a href="{% url 'app:article_list' contents.previous_page_number %}" class="page-link"><</a>
</li>
{% else %}
<li class="page-item disabled">
<a href="#" class="page-link">1</a>
</li>
<li class="page-item disabled">
<a href="#" class="page-link"><</a>
</li>
{% endif %}
<li class="page-item active">
<a class="page-link" href="#">{{ contents.number }}</a>
</li>
{% if contents.has_next %}
<li class="page-item">
<a href="{% url 'app:article_list' contents.next_page_number %}" class="page-link">></a>
</li>
<li class="page-item">
<a href="{% url 'app:article_list' contents.paginator.num_pages %}" class="page-link">{{ contents.paginator.num_pages }}</a>
</li>
{% else %}
<li class="page-item disabled">
<a href="#" class="page-link">></a>
</li>
<li class="page-item disabled">
<a href="#" class="page-link">{{ contents.paginator.num_pages }}</a>
</li>
{% endif %}
</ul>
</nav>