「作ればわかる! Google App Engine for Java プログラミング」本をPythonで書いてみる (9)

引き続き、「作ればわかる! Google App Engine for Java プログラミング」本にてPythonを修行中。


今回はiPhoneアプリの作成・・・のはずが、以下の理由で完全な実装は諦めることにした。

  実機での検証ができない他、PCのJavaScriptではのイベントを捕まえられそうに無いかと思ったが、
  ChromeではTouch系のイベントをエミュレートできたので、そちらを利用する。
  (Chrome起動後、F12⇒右下の設定ボタン⇒「Overrides」⇒「Emulate touch events」をチェックする
  stackoverflow - Simulating touch events on a PC browser

  • 書籍の実装で使われている「UiUIKit」が、2008年以降更新されていない

  完成したのかサポートされていないのか分からず。
  仕事で活かすには、ライセンスが「GNU AGPL 3」であるのも微妙にツライ。
  Google Code - iphone-universal

  • mixiのアカウントがない

  mixiによるOpenIDでのテストができない。



そのため、書籍の実装とは以下の点で異なる(この章ではOpenIDを扱っているため、OpenIDの扱いを増やした)。

  Hatena Developer Center - はてなでOpenID

  • OpenIDの確認画面(要OpenIDでのログイン)
  • main.cssの一部変更

  UiUIKitがないせいか、発進画面の背景画像が消えたため、100%指定をpx指定へと変更

/* height: 100%だとUiUIKit無しでは床画面が表示されなかったため、px指定へと変更; 
#screen1 { height: 100%; background-image: url('/juststop/img/bgtop.jpg'); }
*/
#screen1 { height: 300px; background-image: url('/juststop/img/bgtop.jpg'); }

■実装時に困ったことと対応

アプリでOpenID認証をするための設定

アプリを作成する際、「Authentication Options」を設定することができるが、以下のどちらかを選択する。

  • Open to all Google Accounts users (default)
  • (Experimental) Open to all users with an OpenID Provider


「Restricted to the following Google Apps domain」としてしまうと、GoogleAppsでの認証しかできない上、あとで直すこともできなくなる。
なお、「Open to all Google Accounts users (default)」を選んだ場合は、あとで「(Experimental) Open to all users with an OpenID Provider」へと変更する必要がある。



OpenIDでログイン後の表示

nicknameなどの情報は、Googleアカウントのみ有効。
Yahooやはてなの場合は、nicknameに認証した時のURLが表示されるだけなので注意。
Google Developers - Google App Engine - User クラス



OpenIDの認証サーバー情報を取得する方法
url = users.create_login_url(
                             dest_url=continuePage,                   # リダイレクトURL
                             federated_identity=openidIdentifier,     # 入力されたOpenID
                            )
OpenIDを使う時の注意点

今回は簡易的なOpenIDであり、セッションなどによる保護は実装していない。
実用的なアプリとする場合には、セッションなどで保護した保護する必要あり。
セッション自体は、以前webapp2で実装した方法を使えばよさそう。

webapp2で、リクエスト元のURLなどを知る

self.request.host_url で取得できる。
webapp2 - Request data - Common Request attributes



app.yamlでディレクトリ内のpyファイルを、script指定する
  • ディレクトリ内に、「__init__.py」ファイルを置く
  • app.yamlで「<ディレクトリ名>.<ファイル名>.app」のように指定する

stackoverflow - google app engine app.yaml url handlers



認証を強制するための実装
  • 認証が必須となるurlの記述:app.yamlの「handlers:」内
- url: /require
  script: option.require.app
  login: required
  • 認証画面の指定:app.yamlの「handlers:」内

  認証が必須の場合、「/_ah/login_required」へと飛ばされるため、処理先を記載。

- url: /_ah/login_required
  script: loginout.app
  • 認証画面の処理:処理先にて記載

  今回は、自分でログイン画面へと移動する方法と強制的に移動する方法を共通化したため、「loginout.py」に記載した。

app = webapp2.WSGIApplication([
                               ('/login', Login),
                               ('/_ah/login_required', Login),
                               ('/logout', Logout)
                               ], debug=debug)

参考:Google Developers - Google App Engine - Python アプリケーションの設定



Scoreのモデリング
  • 登録日時のregisterDateは日本時間で登録したいため、今回はutcとなるauto_nowは使用できない。
  • 年月によるoffsetが何回も出てきたので、staticmethodとして持たせた。
  • rankValueは書籍ではdoubleを使っていたが、Pythonのlong型はメモリが許す限り桁数を増やせるそうなので、IntegerProperty() を使った。

参考:Python 2.7ja1 documentation - 5.4. 数値型 int, float, long, complex



Scoreに登録する際の、leftLengthの算出方法

JavaScriptから渡ってくる小数点付のデータに対し、仕様の6除算後に切り捨てて整数にする方法を考えた。

decimalLength = decimal.Decimal(self.request.get('leftLength'))
leftLength = int((decimalLength / 6).to_integral_exact(rounding=decimal.ROUND_DOWN))

参考:Python 2.7ja1 documentation - 9.4. decimal ― 10進固定及び浮動小数点数の算術演算



ランキングページの「xx.x cm」のように小数点を表現する方法

テンプレート側ではなく、Scoreのget_left_lengthメソッド側で小数⇒Unicode化のようにして、表現した。
あまり良くないコードに思えたが、あまり思いつかなかったため、今回はこれで。

unicode(float(self.rankValue - offset) / 10)

■ソース

GitHubのchap10へと追加。
上記にもある通り、今回は書籍の実装とは異なることに注意。