引き続き、「作ればわかる! Google App Engine for Java プログラミング」本にてPythonを修行中。
今回は、最後の章の「みんなでお絵かき」。
ChannelAPIとJavaScriptがメインであったので、JavaScript部分は書籍を見ながら写経する(その分、でき上がりがあまり良くない...)。
なお、過去の復習部分も多くあり、クラスをJSON化するところとかを振り返ることができた。
あとは、ChannelAPIを使って複数ブラウザが同時に更新されるのを見て、単純に感動したり。
■準備
書籍に記載されていた、別ライブラリを以下よりダウンロード。
- FlashCanvas: Google Code - flashcanvas (MITライセンス) (FlashCanvas-20110201.zip)
- json2.js: GitHub - douglascrockford / JSON-js (JSONライセンス? パブリックドメイン?) (douglascrockford-JSON-js-43d7836.zip)
JSONライセンスについては知らなかったので、以下が参考になった。
オープンソース・ライセンスの談話室 - 邪悪なことに使うなという、JSONライセンスに関する個人的な解釈
json2.jsのライセンスについてはJSONライセンスとパブリックドメインのどちらかは正直分からず。以下にはパブリックドメインとの記載あり。
OLEX - JSON in Javascript
■実装時に困ったことと対応
ChannelAPIまわり
以下を参考にした。
- Google Developers - Google App Engine - Channel API Overview (Python)
- しゃけログ - Google App EngineのChannel APIを試してみた
app.yamlへの追加も忘れずに。
inbound_services: - channel_presence
データストアに、db.Text型をリストで持つプロパティを用意するには
item_typeに指定してあげればよい。
別内容だが、今回は絵の描き始めに空のリストを入れてあげる必要があったため、default=Noneを設定して空のリストを入れられるようにもした。
strokes = db.ListProperty(item_type=db.Text, default=None)
ちなみに、2つの線が途切れている図をデータストアに格納すると、プロパティの中身は以下のようになった。2つの要素(「u」始まり)のリストであることが見て取れる。
[u"[{\\"x\\":124,\\"y\\":145},{\\"x\\":127,\\"y\\":145},{\\"x\\":128,\\"y\\":145},{\\"x\\":130,\\"y\\":145},{\\"x\\":133,\\"y\\":145},{\\"x\\":134,\\"y\\":145},{\\"x\\":138,\\"y\\":145},{\\"x\\":147,\\"y\\":145},{\\"x\\":153,\\"y\\":147},{\\"x\\":155,\\"y\\":148}]", u"[{\\"x\\":216,\\"y\\":165},{\\"x\\":216,\\"y\\":167},{\\"x\\":216,\\"y\\":168},{\\"x\\":218,\\"y\\":170},{\\"x\\":221,\\"y\\":171},{\\"x\\":224,\\"y\\":171},{\\"x\\":233,\\"y\\":174},{\\"x\\":241,\\"y\\":175},{\\"x\\":250,\\"y\\":175},{\\"x\\":253,\\"y\\":175}]"]
db.Text型のリストへ、[]で囲まれた文字列を要素として追加するには
リストなので[]で囲まれており、普通に渡してしまうと文字列でなく配列として認識されてしまう。
そこで明確に文字列であることを分かるように設定した。(strでも良かったかも)
picture.strokes.append(db.Text(unicode(stroke)))
picture.put()
データストアのlistプロパティをforで回したいとき
変数に移動することなく、以下の形で回すことができた。
for stroke in pictures.strokes: strokes.append(stroke)
データストアのlistに要素を追加したいとき
エンティティを取得した後に、listへappendする。
picture.strokes.append(db.Text(unicode(stroke)))
取得する全数が不定な時の、iterableな結果の取得方法
RPCオブジェクトを使って、run()で取得する。
rpc = db.create_rpc(deadline=10, read_policy=db.EVENTUAL_CONSISTENCY) return Picture.all().run(rpc=rpc)
参考:Google Developers - Google App Engine - Query クラス
iterableかどうかを知りたい時
今回は使用していないが、RPCオブジェクトとiterableまわりで知りたくなったため調べてみたところ、以下が参考になった。
Stringでなければ、hasattr(オブジェクト, '__iter__')でOKということで。
A-LIAISON BLOG - Pythonで変数の型をチェックする方法(Javaでいうinstanceofが使いたい)
データストアのIDを取得するには
取得するとき
Picture.get_by_id(int(id))
使うとき
picture.key().id()
datetime型を「yyyy年mm月DD日 HH時MM分ごろの絵」という文字列へと変換する
datetime.strftime('%Y年%m月%d日 %H時%M分ごろの絵')とやりたかったが、Unicodeが渡せなさそうなので、断念。
datetiem.yearなどを地道に拾って連結する形にした(改行して見やすくするため、両端をカッコで囲った)。
self.__createDate = ( unicode(jst.year) + u'年' + unicode(jst.month) + u'月' + unicode(jst.day) + u'日 ' + unicode(jst.hour) + u'時' + unicode(jst.minute) + u'分ごろの絵' )
参考:pythonで心理実験 - 例題12-3:ビジランスの実験(試作)
■ソースコード
GitHubのchap11として追加。
今回ですべてのアプリを実装し終わりました。
ゆっくりとした進み具合でしたが、PythonとGoogle App Engineの入門となりました。
知ったことの量が多かったので、忘れないようにどこかでまとめようかとは思います。