[Django]ページネーションを使わずにページングする

Django
この記事は約6分で読めます。

果たして需要があるのかわかりませんが、django.core.paginatorを使わずにページング機能を実装したのでまとめておきます。

今回追加したページネーションについて

ページネーションと言っても、次と前のページへの移動ボタンと、最初のページに戻るボタンを追加しただけです。GoogleBooksAPIで取得した書籍の検索結果表示ページで、ページングによって検索結果を切り替えられるようにしようと思って。

まずはページ切り替えを実現するところができたらいいかなと。今後ページ番号リンクによるページネーションにも随時対応していこうと思っています。

今回作ったページ移動ボタンのイメージを載せておきます。

これだけ見ても大体の操作イメージは掴んでもらえると思います。

なぜ django.core.paginator を使わないのか?

ページングの対象がAPIの返り値だったので、Djangoのページネーションを使うのは見送りました。いくつか参考サイトを見て回ったのですが、どうもWEBアプリで抱えているDBに対してのページネーションっぽかったので今回の場合には使いにくいと判断しました。

GoogleBooksAPIsで動的にページを生成するので、ページング機能よりもURLにパラメータを付けてリクエストを送ってviewで処理したほうが早いかなと。

その際にtemplates内で演算する方法でちょっとハマりましたので別途まとめておこうと思います。

ページネーション?の実装

view関数の中身

def book_search(request):
    """書籍の検索画面"""
    searchform = SerchForm(request.GET)
    
    # 検索実行
    if  searchform.is_valid():
        keyword = searchform.cleaned_data['keyword']

        # 検索を行った場合、ページネーションをする
        # デフォルト値は 0 とするが、+1 することで実際のページ数とする
        page = int(request.GET.get("page", 1))

        #keywordとurlを連結する
        req_url = url + keyword + '&maxResults=10' + '&startIndex=' + str((int(page) - 1) * 10) 
        #リクエストを投げる
        response = requests.get(req_url)
        #レスポンスをストリング?に変えて、jsonとしてロードする。
        #そしてitems要素(本のcollectionになるのかな?)としてhtmlにわたす。
        items = json.loads(response.text)['items']

        context = {
            'searchform' : searchform,
            'keyword' : keyword,
            'items' : items,
            'page' : page,
        }
    # 一覧表示
    else:
        context = {
            'searchform' : searchform,
        }
        searchform = SerchForm()
    return render(request,'cms/book_search.html',context)

book_search()は検索実行画面のviewを管理する関数です。

search_formの中身があるかないかで、検索実行済か否かを判断しています。検索実行済の場合はGetメソッドからpage変数の値を取得しています。値が取得できなかった場合、ページなのでデフォルト値は1です。

req_urlはGoogleAPIへのリクエストですね。終端に”&startIndex=**”を付加して、検索結果の開始位置を調整しています。この調整によってページ切り替えのようなことをやっています。

templates側の実装

        {% if page %}
            {% if page > 1 %}
            <a href="{% url 'cms:book_search'%}?keyword={{ keyword }}&page=1" class="btn btn-primary btn-sm">最初のページ</a>
            <a href="{% url 'cms:book_search'%}?keyword={{ keyword }}&page={{ page|add:-1 }}" class="btn btn-primary btn-sm">前のページ</a>
            {% endif %}

            <a href="{% url 'cms:book_search'%}?keyword={{ keyword }}&page={{ page|add:+1 }}" class="btn btn-primary btn-sm">次のページ</a>
            <br>
            <br>
        {% endif %}

冒頭に貼り付けた3つのボタンリンクの実装がこれです。

こっちで結構ハマったのですが、page数を演算してリクエストにくっつけています。この演算ですが、templates側では{% a = a + 1 %}のような演算は許されていないのです。

実際の演算は{{ page|add:-1 }}のようにやります。これはpageに-1を足す、すなわちpageを-1する演算ですね。

リクエストを送る時に、次に表示したいページ数を演算して送るようにしたらうまくいきました。リクエストで取得したページ数に対応する検索結果を表示するのはview側の実装でうまく行っているので、ページ番号を決め打ちで書いちゃえばページ番号によるページングも実装できそうですね。

ちなみにその場合、ほんの検索結果がいくつあるかをtemplates側で意識する必要がありそうなので、そのあたりも考えないといけないですね。

参考文献

python – django:テンプレートのhtmlページ内で計算を行う方法

GoogleBoooksAPIs-Using the API

コメント

タイトルとURLをコピーしました