2010-11-08

「Labels」ボタンの実装 (BloggerGlass)

「Labels」ボタンは、Blogger Glass の iPhone 専用画面のうち、記事表示画面の下部に付いているボタンだ。その名の通り、記事に付けられたラベルの一覧を表示させるためのボタンとして置いてある。これまでは、対応する機能を実装しておらず、ただの飾りでしかなかった。今回はそれを実装した。

ラベルの取得

ブログ記事のデータは GData Python ライブラリを使って読み込んでいる。ラベルのデータも同ライブラリが処理してくれている。

記事画面の場合

記事画面(を表示するリクエストハンドラ)で扱うデータは gdata.blogger.data.BlogPost だ。記事に付けたラベルは、このオブジェクトの category 属性として保持されている(atom.data.Category オブジェクトのリスト)。atom.data.Category オブジェクトの term 属性がラベルの文字列になる。

記事画面(のハンドラ)ではこれまでもラベルを上記の方法で取り出している。これまでは画面表示用に使うだけだったが、今回から「ラベル一覧画面」用に別途保存することになる。util.save_lables() については後述。

該当する部分のコードは以下のようになる。

(src/postview.py より)
        entry = client.get_one_post(settings.get('blog_id'), post_id)
        if entry:
            [...snip...]
            labels = []
            for label in entry.category:
                labels.append(label.term)
            labels.sort()
            self.view.labels = labels
            util.save_labels(labels, self.request, self.response)

ちなみに、Python のリストのソートメソッドは自分自身を返さないので注意が必要。たとえば上記のコードで、ソートした labels を代入するつもりで self.view.labels = labels.sort() とすると、None が代入されることになる。今回もふくめて何度も痛い目に会ってきたので、忘れないようにここに書き留めておく(それでもまた忘れるんだろうな)。

一覧画面の場合

一覧画面および検索結果画面(を表示するリクエストハンドラ)で扱うデータは gdata.blogger.BlogPostFeed になっている。このオブジェクトは entry 属性として記事データ(gdata.blogger.data.BlogPost)のリストを保持している。したがって、ここから個々の記事に付けられたラベルをすべて集めるには以下のようなコードが必要だ。

(src/util.py より)
def collect_labels(entries):
    """
    'entries' must be a list of gdata.blogger.BlogPost.
    """
    labels = []
    for entry in entries:
        for label in entry.category:
            if label.term not in labels:
                labels.append(label.term)
    labels.sort()
    return labels

これを呼び出すコードはこうなる。

(src/main.py より)
        q = gdata.blogger.client.Query(start_index=start_index,
                                       max_results=info.Pager.PAGESIZE)
        feed = util.get_posts(q)
        if feed:
            [...snip...]
            # collect labels for each post, then save them.
            labels = util.collect_labels(feed.entry)
            util.save_labels(labels, self.request, self.response)

ラベルの保存と読み込み

ラベルの保存には GAE が提供する memcache サービスを使う。データストアとは異なり揮発性のストレージだが、その分高速に動作するとのこと。前回の記事(「Back」ボタンの実装)にも書いたように、ラベル情報の保存先とその形態にはいくつか方法が考えられるが、とりあえずはセッション固有データとして memcache に保存する方式にしてみた。

ラベルの保存と読み取りは以下の 2 つの関数で行う。

(src/util.py より)
def save_labels(labels, request, response):
    sess = session.Session(request, response)
    if memcache.get('labels', namespace=sess.id) is None:
        memcache.add('labels', labels, namespace=sess.id)
    else:
        memcache.set('labels', labels, namespace=sess.id)

def load_labels(request, response):
    sess = session.Session(request, response)
    return memcache.get('labels', namespace=sess.id)

memcache へのデータの書き込みには、keynamespace という 2 つの情報を指定できる。ここでは key として 'labels' という文字列を、namespace としてセッション ID を指定している。セッション ID を使うことで、セッション固有の情報として保存と読み取りが可能になる。

「Labels」ボタン用のリクエスト

以下が今回追加したリクエスト形式になる。iPhone 用の「記事画面」のボタンだけでなく、「アプリメニュー」にも「Labels」項目を追加しておいた。当初は「記事画面」の時だけラベル情報を保存するつもりだったが、「一覧」と「検索結果」でも表示した分の記事に付いたものを集めて保存することにしてみた。これにより「一覧」系の画面から呼び出しても(それなりに)意味のある機能になったため、アプリメニューにも付け加えた次第。

すべての記事に付けられたすべてのラベルを集めて表示することも考えたが、そのためには全記事データの取得が必要でまとまった時間が必要になる。むしろ別機能として実現すべきだと考え、今回は表示した分の記事に付いたものだけを集める、という機能にした。

リクエスト形式 機能
/lables/ 直前の画面で表示された記事に付いていたラベルの一覧を表示する。

このリクエストを処理するハンドラを新たに追加してある。

その他の変更点

以下のコミットを参照。

関連リンク

関連記事

0 件のコメント:

コメントを投稿