Django + microCMSでつくるブログサイト ④ページネーションの実装

「Django + microCMSでつくるブログサイト」シリーズの4番目の記事です。
今回はページネーションの実装をしていきます。

microCMSのGETパラメーター

microCMSにはページネーションを動的に設定できる便利なGETパラメーター、limitoffsetが用意されています。

公式の解説より内容を引用します。

**limit**
取得件数を指定します。
デフォルト値は10です。
上限値はありませんが、レスポンスサイズ(レスポンスヘッダのcontent-lengthの値)が約5MBを超えるとエラーが発生します。
そのため、大量のコンテンツの全件取得をしたい場合は下記のoffsetパラメータと組み合わせてページング処理を行ってください。
**offset**
何件目から取得するかを指定します。
デフォルト値は0です。


GETリクエストの送り方


例えば記事の数が全部で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


URLパターンの追記

まずは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パラメーターから実装できるのですが、今回は明示的にページの情報を渡す形をとります。

viewの編集

次に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の作成


次に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ページ目。

TOPページ