2011年1月22日土曜日

GAE上のFlaskで画像アップ&表示

みなさん。Flask使ってますか。

Flask最高ですね。
最近はWebアプリ作るときは何やるにしてもFlaskでやってます。
Javaのモジュールが必要なときはJythonつかってFlask動かすくらいです。
(これはまた別の話)

GAEも最高ですね。
ということで、Flask,GAEについて今日は書きたいと思います。
まあGAE上でFlask使う方法は色々なところで書かれているので割愛。

今日はGAE上のFlaskで画像のアップロードと表示について
結構時間かかったので備忘録として書きます。

pythonコードは以下のような感じ。

from flask import Flask
from flask import request
from flask import Response
from google.appengine.ext import db

app = Flask(__name__)

@app.route('/image/upload',methods=['POST'])
def upload_image():
    """画像アップロード"""
    uploaded_image = request.files['image']
    image = Image()
    image.content_type = uploaded_image.content_type
    image.image = uploaded_image.stream.read()
    image.put()
    return 'ok'

@app.route('/image')
def disp():
    """keyで表示"""
    image = Image.get(request.args.get('key',''))
    return Response(response=image.image,content_type=image.content_type)

class Image(db.Model):
    """画像保存用エンティティ"""
    content_type= db.StringProperty()
    image = db.BlobProperty()

まず登録時にはBigtable側に画像のバイナリとコンテントタイプを保存しておく。
で表示側にはResponseに画像バイナリとコンテントタイプを返してやる。


画像アップロードのformはこんな感じ

<form action="/admin/image/upload" enctype="multipart/form-data" method="post">
<input type="file" name="image">
<input type="submit" value="upload">


表示側はこんな感じ

<img src="/image?key={{画像のキー}}" >

2011年1月8日土曜日

The Zen of Python

Pythonのインタラクティブシェルでthisをimportすると
The Zen of Pythonを読むことができる。


>>> import this


英語のリハビリとして辞書片手に翻訳してみる。

-翻訳-
醜いよりも美しいほうがいい
わかりにくいよりも分りやすいほうがいい
複雑よりもシンプルなほうがいい
入り組んでいるよりも複合のほうがいい
ネストしているよりもフラットなほうがいい
密度は低いほうがいい
読みやすさが重要
特別な場合でも規則を破るほど特別ではない
けれども実用性は純粋性をしのぐ
明確に沈黙させているので無い限り、決してエラーを黙って通してはいけない
曖昧さに直面したとき、推測するという誘惑に負けてはいけない
明らかな方法がひとつ、なるべくひとつだけあるべき
たとえオランダ人以外には明らかでなかったとしても
何もしないよりは今やる方がいい
けれども今すぐにやらないほうがいいこともたびたびある
説明が大変な実装であるならば、それは良くないアイディア
説明が簡単な実装であるならば、それがきっと良いアイディア
名前空間こそが良いアイディア、これらをどんどんやっていこう


-原文-
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

FlaskでJSONP

PythonのマイクロフレームワークFlaskでは
JSONを返却するためのメソッドjsonifyが定義されている。


from flask import Flask
from flask import jsonify

app=Flask(__name__)

@app.route('/test.json')
def test_json():
return jsonify(res='test')

if __name__ == '__main__':
app.run()



/test.jsonでリクエストすると
{
res:'test'
}
という結果が帰ってくる

JSONPにしたい場合はjsonifyは使えない。



@app.route('/test.jsonp')
def test_jsonp():
import json
request.args.get('callback') + '(' + json.dumps(dict(res='test')) + ')'



というように自分でリクエストパラメータからcallbackを受け取って
付与して返す必要がある。

ただしこのままでは、mimetypeの指定がないので
厳密にはmimetypeの指定を行わなくてはならない。
script/javascript

現状FlaskのJSONP用のmethod(padded_jsonify)が要望として上がっているが、
jsonifyのように*args,**kwdとすべての引数がjsonオブジェクトになるような機能のため
callbackが入る余地が無いみたいで、提案が今は棄却されている模様。