Open2
Djangoで従テーブルのクエリーセットによるページネーションの実装方法
Djangoでページネーションを実装するにあたり、教本やWeb記事等では、ListViewのクラス変数であるpaginate_by
をオーバーライドすることで、テンプレート側で{% if is_paginated%}
でページネーションがある場合の制御を行ったり、page_obj
等でページネーションの表示工夫をする事が出来ると目にします。
しかし従テーブルのクエリーセットによるページネーションを実装する方法について情報が無く、こちらで知見を得られたらなと思います。
具体的には、記事公開アプリケーション等でマイページ上に自分が投稿した記事をページネーション表示させるような場合を想定し、教本やWeb記事に記載されているような条件との相違点では、下記の条件を想定しています。
・主テーブルCustomUserに対して、従テーブルArticleが一対多の関係でリレーションシップを取る
・ビューではListViewを継承し、クラス変数model
にはCustomUserを指定し、クラス変数paginate_by
の指定も行う
・get_queryset()のオーバーライドでは、マイページのユーザに紐づくArticleモデルのクエリーセットをテンプレートへ渡すようにする
・テンプレートでは、主テーブルCustomUserのクエリを{% for s in customuser_list %}
で取り出し、従テーブルArticleのクエリを{% for article in s.name.all %}
で取り出す。
#models.py
class CustomUser(AbstractUser):
username = models.CharField(
_("username"),
max_length=30,
help_text='Required 30 characters or fewer.',
unique=True,
error_messages={
'unique': _("This Username already exists."),
},)
email = models.EmailField(
_('email'),
unique=True,
error_messages={
'unique': _("A user with that email address already exists."),
},)
class Meta:
verbose_name_plural = 'CustomUser'
class Article(models.Model):
post_user = models.ForeignKey(CustomUser, verbose_name='Post User', on_delete=models.CASCADE, related_name='name',)
title = models.TextField(verbose_name='title', max_length=50,)
content = MDTextField()
thumbnail = models.ImageField(verbose_name='thumbnail', null=False, blank=False,)
#views.py
class MyPageView(LoginRequiredMixin, generic.ListView):
template_name = 'mypage.html'
model = CustomUser
paginate_by = 6
def get_queryset(self):
articles = CustomUser.objects.filter(username=self.request.user).prefetch_related('name')
return articles
<!--mypage.html-->
{% for s in customuser_list %}
<section class="u-content-space">
<div class="container">
<header class="text-center w-md-50 mx-auto mb-8">
<h2 class="h1">Prototyping Works by {{ s.username }}</h2>
</header>
<div class="js-shuffle u-portfolio row no-gutters mb-6">
{% for article in s.name.all %}
<figure class="col-sm-6 col-md-4 u-portfolio__item" data-groups='["its-illustration"]'>
<img class="u-portfolio__image_original" src="{{ article.thumbnail.url }}" alt="Image Description">
<figcaption class="u-portfolio__info">
<h6 class="mb-0">{{ article.title }}</h6>
</figcaption>
</figure>
{% endfor %}
<!--ページネーション処理-->
{% if is_paginated %}
<div class="row justify-content-between align-items-center mb-4">
<div class="col-lg">
<nav aria-label="Bootstrap Pagination Example">
<ul class="pagination mb-0">
<!--前ページへのリンク-->
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">
<span class="mr-1 d-none d-sm-inline-block">←</span> Previous
</a>
</li>
{% endif %}
<!--ページ数表示-->
{% for page_num in page_obj.paginator.page_range %}
{% if page_obj.number == page_num %}
<li class="page-item active">
<a class="page-item" href="#">{{ page_num }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
</li>
{% endif %}
{% endfor %}
<!--次ページへのリンク-->
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">
Next<span class="ml-1 d-none d-sm-inline-block">→</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endif %}
</div>
</section>
{% endfor %}