2010-10-14

GAE アプリでユーザごとの設定を可能にする #4

今回は、「設定」画面を追加する前の最後の下準備として、メニューを追加する。また、ログイン(とログアウト)にも対応する。

メニューの追加

ここで言うメニューとは、BG の主要機能のリクエスト URL へのリンクのことだ。具体的な項目については「GAE アプリでユーザごとの設定を可能にする #3」を参照のこと。

ウェブアプリにおけるメニューは、特定のリクエスト URL へのリンクだ。具体的に言えば、「List」は "/" への、「Settings」は "/settings/" へのリンクとなる。

メニューの項目とその並びの情報を保持するため専用のオブジェクトを定義する。

(メニュー用オブジェクト)
class Menu:
    class Item:
        name = ""
        request_url = ""
        def __init__(self, name, request_url):
            self.name = name
            self.request_url = request_url

    def __init__(self):
        self.menu_items = []
        self.menu_items.append(self.Item('List', '/'))

    def menu(self):
        return self.menu_items

メニュー項目が増えたら、Menu オブジェクトの初期化(__init__)で、menu_items に追加する。

これを画面に表示するためにテンプレートには以下のような記述を追加する。このとき、リクエストハンドラからテンプレートにわたす AppInfo オブジェクトに Menu.menu() の戻り値をセットしておく。

(テンプレート内のメニュー表示)
<div id="top-menu">
  {% for item in app.menu %}
  <span class="menu-item"><a href="{{ item.request_url }}">{{ item.name }}</a></span>
  {% endfor %}
</div>

ログインによるメニュー項目の切り替え

Menu オブジェクトの変更点

ログインしているかどうかに応じてメニュー項目を切り替えるために、上述の Menu オブジェクトの定義を以下のように変更する。

(Menuオブジェクト; ログイン対応版)
class Menu:
    [...snip...]
    def __init__(self, request_url):
        self.menu_logged_in = []
        self.menu_logged_out = []
        # menu items those are enabled when a user logged in.
        [...snip...]
        self.menu_logged_in.append(self.Item('Logout',
                                             users.create_logout_url(request_url)))
        # menu items those are enabled when a user does not logged in.
        [...snip...]
        self.menu_logged_out.append(self.Item('Login',
                                              users.create_login_url(request_url)))

    def menu(self):
        user = users.get_current_user()
        if user:
            return self.menu_logged_in
        else:
            return self.menu_logged_out

初期化時に request_url をわたしているのは、ログインとログアウト用の URL を生成するため(ログインまたはログアウト画面からの戻り先になる)。この値として、メニューの生成時にはリクエストハンドラから self.request.uri をわたす必要がある。このため、fill_appinfo に引数を増やした。

(util.py; fill_appinfo)
def fill_appinfo(appinfo, request_url):
    [...snip...]
    appinfo.menu = Menu(request_url).menu()
リクエストハンドラの変更点

リクエストハンドラ側の(fill_appinfo の)呼び出しは以下のように変更した。

(リクエストハンドラの変更点)
class MainHandler(webapp.RequestHandler):
    [...snip...]
    def get(self):
        fill_appinfo(self.appinfo, self.request.uri)
        [...snip...]
テンプレートの変更点

メニューを表示するため、各画面のテンプレートに以下の記述を追加する。

(テンプレート内のメニュー表示部分)
<div id="top-menu">
  {% for item in app.menu %}
  <span class="menu-item"><a href="{{ item.request_url }}">{{ item.name }}</a></span>
  {% endfor %}
</div>

実装の方針

一覧表示も内容表示もログインの状況には無関係だ。ログインしていようがいまいが機能の動作に変化はない。だから、リクエストハンドラとテンプレートにもログインを判別するコードは入れないようにした。つまり、ハンドラ内で判別してメニューを切り替えるのではなく、メニュー自体がログインの状況を判別するようにした、ということ。またこれは、すべてのリクエストハンドラに(ログイン判定という)同じコードが入ることを防ぐためでもある。

関連記事

0 件のコメント:

コメントを投稿