旧それなりブログの跡地、画像やスタイルやJSなどが壊れてることがあります。

[Django] Paginatorに渡すobject_listを自作クラスでラップ

2008年12月25日

Django-1.0から出来たPaginatorですが、
インスタンス生成時にページングしたい全要素のリストを渡さないといけない点が、若干不便。

というのも、object_listにQuerySetインスタンスを渡すならば、
遅延評価して抽出された各要素のみを生成するからいいんですが、
渡すリストにそのような遅延評価の機能が無い場合は、
「全要素を生成して渡し、その中で表示するページ分だけの要素を使う。」
という、非効率なことになってしまう。

リストが無視できるデータ量ならいいんだけど、
自分の場合に無視できない問題になってしまったので、
以下のようにして対応しました。

(1) こういうクラスを作って・・・

class SomeObjectList(object):
def __getitem__(self, key):
start = None
stop = None
if isinstance(key, int):
start = key
stop = key + 1
elif isinstance(key, slice):
start = key.start
stop = key.stop
else:
raise IndexError
if 0 > start: raise IndexError
items = []
# ある行数が多いデータから、上記の start / end を使用して
# 一部だけ抽出してitemsへ格納して返す。
return items
def count(self)
count = 0
# ある行数の多いデータから、全体の個数を素早く取得できる手段で取得して返す。
# 例えば、SQLのCOUNT文的に。
return count

(2) ・・・こんな風にPaginatorを生成させる

Paginator(SomeObjectList(), 10)

とりあえず、object_listだよって、「枠」だけ渡して、
中身は paginator.page とかで、実際に評価された時に生成させるという感じです。

このPaginatorの仕様なんですけど、
(a) Paginatorインスタンス生成時には、全体の個数だけ渡して。
(b) paginator.page に対して、対応するobject_listを設定する。
(c) QuerySetとの連携は、ObjectPaginatorサブクラスで対応する。
・・・という方が、より疎結合でDjangoのイメージに合っている気がするんだけどなー。

まぁ、上記のような抜け道を用意してくれているので、これでやってね、ってことか。

と、何かおかしかったらご指摘願います!!