はじめに
AppEngine/Python で CGM 系の Webサービスを作っているんですが、運営しているうちにデータ数が多くなりそうです。いや、なりますね。
1ページに何百何千もデータを表示すると、見づらいし表示が遅いので、ページングを実装しなければいけません。
Kay にはページング機能があるじゃないか
Kay Framework は バージョン 1.1 から、ページングを簡単に実装できる kay.utils.paginator モジュールが追加されました。
使い方はこんな感じ
こんなモデルがあるとします。
# -*- coding: utf-8 -*- # core.models from google.appengine.ext import db class Entry(db.Model): title = db.StringProperty(required=True) content = db.TextProperty() created = db.DateTimeProperty(auto_now_add=True)
paginator モジュールを使ってページに表示するデータを作成
# -*- coding: utf-8 -*- """ core.views """ from kay.utils import render_to_response from kay.utils.paginator import Paginator from core.models import Entry def index(request, number=1): entries = Entry.all().order("-created") # 1 ページに出力するデータの数は 5 つ paginator = Paginator(entries, 5) # 指定されたページを取り出す page = paginator.page(number) # テンプレートを使って出力 data = dict(page=page) return render_to_response('core/index.html', data)
URL マッピングを忘れず追加
ページ番号の文字列を数値に変換する処理は Kay にやって欲しいので、エンドポイントを分けておきます。
# -*- coding: utf-8 -*- # core.urls # from kay.routing import ( ViewGroup, Rule ) view_groups = [ ViewGroup( Rule('/', endpoint='index', view='core.views.index'), Rule('/page/<int:number>/', endpoint='show_page', view='core.views.index'), ) ]
データ一覧とページネーションを出力するテンプレートを書きます
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Paginator Sample</title> </head> <body> <div id="entry_list"> <!--ページに表示するデータのリストは object_list から取得できる--> {% for entry in page.object_list %} <div class="entry"> <h2>{{ entry.title }}</h2> <div class="entry_body"> {{ entry.content }} </div> </div> {% endfor %} </div> <div id="pagination"> <!--前のページへのリンクを出力--> {% if page.has_previous %} <a href="{{ url_for('core/show_page', number=page.previous_page_number) }}">前</a> {% endif %} <!--現在のページ番号と総ページ数を出力--> <span>{{ page.number }} / {{ page.paginator.num_pages }}</span> <!--次のページへのリンクを出力--> {% if page.has_next %} <a href="{{ url_for('core/show_page', number=page.next_page_number) }}">次</a> {% endif %} </div> </body> </html>
簡単だけど…
db.Query と組み合わせた場合、最大 1000 件までしかあつかえません。これはデータストアの制約だから仕方ないか。あと、ページを表示するたびにデータを全部取得して、そのページに表示するデータを取り出しているので、データ数が多いと遅いです。
まとめ
速度を気にする人、1000件以上データを扱いたい人は、結局独自でページングを実装する必要がありますね。
キーや一意のプロパティを使ってページングを行う方法が App Engine の公式サイトで紹介されています。
これが定番かな。
あと、結構前に話題になった、SkipList みたいなデータ構造にする手もあります。
こちらは実装が大変だ。