Pylonsでメモアプリ(3)

一覧をページングできるようにしよう。
最初の20件だけ表示して、以降は「1 2 3 次の20件へ」なページャから閲覧、みたいな。

タグ選んで一覧とか、検索結果一覧とか使う場面多そうなのでなるべく汎用的に。
SQLAlchemyではモデルがタプル型で返ってきてるので、配列のスライス使えば簡単にできるかな?

lib/ 以下にライブラリを置けばよさそうなのでそこにファイルを作ります。

  • lib/pager.py
# coding=utf-8

from sqlalchemy import *
from testapp.model import *
from testapp.lib.base import *

class Pager(object):
  def __before__(self):
    self.session = model.sac.session_context.current

  def __init__(self, cols, offset, limit):
    c.total = len(cols)
    c.page_num = c.total / limit + 1
    c.current = offset / limit + 1
    c.last = c.page_num == c.current and True or None
    c.notes = cols[offset:offset+limit]

コントローラで取得した一覧データとoffset・limitをPagerクラスに渡して、データの数・総ページ数・現在のページ数・最後のページかどうか・offsetから20件分のデータをc変数に入れてみました。
該当データを取る場合スライスを使うとすごい簡単になった。SQL実行するのも一回で済むしこれでいいのか?

コントローラではindex()で一覧を表示する場合、

def index(self, format='html'):
    if request.params.has_key('s') is False:
      start = 0
    else:
      start = int(request.params['s'])
    notes = self.session.query(Note).get_by(user_id=1).all()
    Pager(notes, start, 20)
    return render('list')

sパラメータは一覧の開始地点offsetです。
「/notes?s=20」だったら21件目から40件目までを表示。

テンプレートのlist.makにはこんな感じでページャを表示。

% if c.page_num > 1:
<div class="page_navi">
  % for i in range(1, c.page_num+1):
    % if i == c.current:
		  ${i}
    % else:
      ${h.link_to(i, h.url_for('?s=' + str((i-1)*20)))}
 	  % endif
	% endfor
  % if c.last is None:
	  ${h.link_to(u'次の20件へ', h.url_for('?s=' + str(c.current*20)))}
	% else:
	  次の20件へ
	% endif
</div>
% endif

微妙に悩ましかったのが、総ページ数と現在ページ数を入れるところで、
math.ceil()で小数点を切り上げてくれるかと思ったら切り下げられてた。
なので+1するというなんとも直接的な書き方に・・


とりあえず表示はできたので後で見直すとして、タグクラウドを表示するようにしていきたいと思います。