「Django + microCMSでつくるブログサイト」シリーズの4番目の記事です。
今回はページネーションの実装をしていきます。
microCMSにはページネーションを動的に設定できる便利なGETパラメーター、limit
、offset
が用意されています。
公式の解説より内容を引用します。
limit
取得件数を指定します。
デフォルト値は10です。
上限値はありませんが、レスポンスサイズ(レスポンスヘッダのcontent-lengthの値)が約5MBを超えるとエラーが発生します。
そのため、大量のコンテンツの全件取得をしたい場合は下記のoffsetパラメータと組み合わせてページング処理を行ってください。
offset
何件目から取得するかを指定します。
デフォルト値は0です。
例えば記事の数が全部で10ある場合で考えます。
1ページに3つの記事を表示すると決めたのであれば、limit
に3を指定してGETリクエストを送ります。
https://your-service-id.microcms.io/api/v1/post?limit=3
このようなURLになります。
ユーザーが2ページ目にアクセスしてきた際は4つ目の記事から6つ目の記事までを表示したいです。
その場合はoffset
を用いて以下のようなURLを指定します。
https://your-service-id.microcms.io/api/v1/post?limit=3&offset=3
まずはurls.py
を編集します。
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='index'),
path('page/<str:page>/', views.post_list, name='index_with_page'), # 追加
path('post/<slug:slug>/', views.post_detail, name='post_detail')
]
こちらは追加しなくても、requestパラメーターから実装できるのですが、今回は明示的にページの情報を渡す形をとります。
次にviews.py
を下記のようにします。
# blog/views.py
from django.shortcuts import render
import requests
from django.conf import settings
from django.http import Http404
import math # 追加
def post_list(request, **kwargs):
"""記事一覧"""
# 1ページあたりの表示件数を設定
limit = 2
# urlパラメーターから現在何ページ目にアクセスしているかを取得
current_page = kwargs.get('page', 1)
# 現在のページから、何番目の記事から取得するかを設定
offset = (int(current_page) - 1) * limit
end_point = f'/post?limit={limit}&offset={offset}'
url = getattr(settings, "BASE_URL", None)
api_key = getattr(settings, "API_KEY", None)
headers = {'X-API-KEY': api_key}
res =requests.request(method='GET',
url=url + end_point,
headers=headers)
# 記事のトータル数を取得
total_count = res.json()['totalCount']
# 何ページ目まであるか?の計算
num_page = math.ceil(total_count / limit)
context = {
'post_list': res.json()['contents'],
# 1ページ目から何ページ目まであるか
'num_page': range(1, num_page + 1),
# 現在のページは何ページ目か
'current_page': int(current_page),
# 最後のページは何ページ目か
'last_page': num_page
}
return render(request, 'blog/index.html', context)
...省略
まず変数limitに1ページあたりの表示記事数を設定しておきます。
テストブログで記事数が5個しかないので、2としています。
次にユーザーがhttps://hogehoge.com/page/2/
というurlにアクセスしてきた際に何ページ目か?ということを変数current_pageに保存してます。
何もページが指定されていないhttps://hogehoge.com/
にアクセスしてきた際は1ページ目としたいので、kwargs.get('page', 1)
となります。
この二つの変数から、変数offsetを計算して、end_pointに渡して、表示する記事を取得しているという流れです。
最後にcontextに含める形で、1ページ目から何ページ目まであるか、現在のページは何ページ目か、最後のページは何ページ目か、という情報をテンプレートに渡してあげます。
これらの情報がpager部分を実装するパーツになります。
次にpagerの部分を作ります。
components
ディレクトリにpagination.html
を作成します。
<!-- blog/templates/blog/components/pagination.html -->
<div class="pagination">
<ul>
<!-- 前のページに送る部分 1ページ目ならリンクなし -->
{% if current_page == 1 %}
<span class="pagination-link prev-off"><li><</li></span>
{% else %}
<a href="{% url 'blog:index_with_page' current_page|add:'-1' %}" class="pagination-link"><li><</li></a>
{% endif %}
<!-- 数字の部分 -->
{% for num in num_page %}
<!-- 現在のページならリンクなし -->
{% if num == current_page %}
<span class="pagination-link is-active"><li>{{ num }}</li></span>
{% else %}
<a href="{% url 'blog:index_with_page' num %}" class="pagination-link"><li>{{ num }}</li></a>
{% endif %}
{% endfor %}
<!-- 次のページに送る部分 最後のページならリンクなし -->
{% if current_page == last_page %}
<span class="pagination-link next-off"><li>></li></span>
{% else %}
<a href="{% url 'blog:index_with_page' current_page|add:'+1' %}" class="pagination-link"><li>></li></a>
{% endif %}
</ul>
</div>
作成したらindex/html
に読み込みます。
<!-- blog/templates/blog/index.html -->
{% extends "blog/base.html" %}
{% load blog %}
{% load static %}
{% block content %}
<div class="container" style="padding-top:112px;">
{% for post in post_list %}
<article class="article">
...省略
</article>
{% endfor %}
<!-- 読み込み -->
{% include "blog/components/pagination.html" %}
</div>
{% endblock %}
スタイルを設定して終了です。
/* blog/static/css/style.css */
@charset "UTF-8";
...省略
/* --------------------------------
* ページネーション
* -------------------------------- */
.pagination {
padding: 30px 0;
text-align: center;
}
.pagination ul {
padding: 0;
list-style-type: none;
}
.prev-off,
.next-off {
opacity: .2;
}
.pagination .pagination-link {
display: inline-block;
font-size: 2rem;
padding: 10px 18px;
color: #888;
width: 40px;
height: 40px;
line-height: 40px;
font-weight: bold;
padding: 0;
text-align: center;
}
.pagination .is-active {
background-color: #888;
border-radius: 100%;
color: #fff;
}
...省略
スタイルについてはほぼこちらのページのコードを使いました。
コピペで簡単!ページ送りのデザインCSS 35選まとめ【ページャー・ページネーション】
いろいろ試すとおもしろいと思います。
1ページ目。
2ページ目。
3ページ目。