簡単そうだと思ったのでやってみた。実際、簡単だった。要した時間のほとんどは Python の文法を調べることだった。
今回の切り分けでは、以下のようにリクエスト URL に応じて共通スタイルと機器用スタイルに分け、さらに機器用スタイルではユーザエージェントを使って実際の機器に合わせたスタイルに切り替えている。
リクエスト URL | 返されるデータを収めたファイル |
---|---|
http://stylerepo.../logrepo/common |
logrepo_common.css |
http://stylerepo.../logrepo/device |
ユーザエージェントに応じて logrepo_ipad.css や logrepo_imac.css に切り替える |
つまり、以下のように 2 つのリンクを書くだけでデバイスに応じたスタイルに切り替えられるわけだ。
(スタイルへのリンク方法)
<link type='text/css' rel='stylesheet' href='http://stylerepo.../logrepo/common' />
<link type='text/css' rel='stylesheet' href='http://stylerepo.../logrepo/device' />
切り替えの仕組み
今回の変更で、stylerepo
の構成は以下のようになっている。
(stylerepo アプリ構成の一部)
/stylerepo/
+-- app.yaml
+-- index.yaml
+-- logrepo/
| +-- __init__.py
| +-- base.py
| +-- common_handler.py
| +-- default_handler.py
| +-- device_handler.py
| +-- logrepo_common.css
| +-- logrepo_ipad.css
| +-- logrepo_iphone.css
| +-- logrepo_mac.css
+-- main.py
+-- stylesheets
+-- mac.css
前回の状態から logrepo
ディレクトリが増えた。また、app.yaml
にも手が入っている。
app.yaml
共通スタイルと機器用スタイルの切り替えはリクエストする URL を替えることで行う。この仕組みは GAE に用意されていて、設定を app.yaml
に記述すれば良い。
app.yaml
では、リクエストの URL パターンごとに処理を行うハンドラを記述する。この URL パターンの記述には正規表現が使えるためコンパクトかつ高機能な記述が行える。たとえば、以下のような記述。
(app.yaml より)
- url: /logrepo/(common|device)
script: logrepo/\1_handler.py
この指定は リクエスト URL が /logrepo/common
または /logrepo/device
で終わっていた場合に、続くハンドラに処理させることを意味する。ここで common
と device
の選択は正規表現になっていて、実際のリクエストにふくまれている文字列(common
か device
) がスクリプト名の指定中では \1
として参照されている。すなわち、/logrepo/common
でアクセスされたときには logrepo/common_hander.py
に、/logrepo/device
としてアクセスされたときには logrepo/device_handler.py
に、それぞれ処理が任せられる。
以下に今回の app.yaml
の全体を示す。
ユーザエージェントの判別
機器の判別には HTTP のリクエストヘッダにふくまれているユーザエージェント文字列を使う。JavaScript で判別する方法でもお馴染のものだ。
以下がその部分のコードになる。
(device_handler.py より)
1: class DeviceHandler(base.BaseHandler):
2: def request_device(self):
3: agent_string = self.request.headers['User-Agent']
4: device = 'mac'
5:
6: if agent_string.find('iPad') > -1:
7: device = 'ipad'
8: elif agent_string.find('iPhone') > -1:
9: device = 'iphone'
10: else:
11: device = 'mac'
12: return device
13:
14: def style_file(self):
15: return 'logrepo_' + self.request_device() + '.css'
また、DeviceHandler
が継承している BaseHandler
はこうなっている。
(base.py より)
1: class BaseHandler(webapp.RequestHandler):
2: def style_file(self):
3: return ''
4:
5: def get(self):
6: path = os.path.join(os.path.dirname(__file__), self.style_file())
7:
8: self.response.headers['Content-Type'] = 'text/css'
9: for line in open(path, 'r'):
10: self.response.out.write(line)
get
メソッドを見ればわかるように、スタイル定義自体はファイルとして用意したものをそのまま使っている。発展形として、CSS ファイルをテンプレートとして使い、内容の一部をコードで置き換える、というようなことも考えられる。たとえば、色の組み合わせを何通りか用意しておき、日付などに応じて入れ替える、とか。
こちら側と向こう側
ページを開こうとする機器に応じて見た目を調整したい場合、2 通りの方法が考えられる。1 つはこちら側(クライアント側)で JavaScript を使って切り替えるもの、もう 1 つが今回のように向こう側(サーバ側)でやるものだ。
クライアント側でやればサーバ(とアプリ)を用意する必要はない。JavaScript の動くブラウザだけあれば良いから手軽にできる。一方、サーバ側でやるメリットとしては、クライアントの環境によらない、かな。これは、クライアントが JavaScript の動かないブラウザやプログラムであっても対応できる、という意味だ。
ま、サーバでできること(リクエスト時に解決できること)はサーバでやってしまうべきかな。クライアント側(JavaScript)はもっと他のことで忙しいはずだろう?
関連リンク
- GAE: Python アプリケーション設定 (Google App Engine 公式ドキュメントより)
- GAE: webapp フレームワーク (同上)
0 件のコメント:
コメントを投稿