Google App Engine で Blobstore を使ってみる

Google App Engine(以下 GAE) で画像とかファイルをアップロードするのどう実装しようか迷っていたら、「Blobstore 使えばいいよ〜」というアドバイスをもらいました。そういえば、Blobstore が提供されたことは知っていたけど、試したこと無かったな。


さっそく試してみました。初めて Blobstore を使うので、webapp フレームワークでシンプルに実装。

# -*- coding: utf-8 -*-

import os
import urllib
from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app


class MainHandler(webapp.RequestHandler):
    def get(self):
        # アップロード用の URL を作成
        # アップロードに成功したら /upload に移動させる
        upload_url = blobstore.create_upload_url('/upload')

        # Blobstore に保存されているファイルを取得
        files = blobstore.BlobInfo.all()

        # テンプレートを使って出力
        data = dict(
                upload_url=upload_url,
                files=files)
        path = os.path.join(os.path.dirname(__file__), 'main.html')
        self.response.out.write(template.render(path, data))
        

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        # Blobstore にアップロードされたファイルの情報を取得
        files = self.get_uploads('file')
        blob_info = files[0]

        # ファイル表示用の URL へリダイレクト
        self.redirect('/serve/%s' % blob_info.key())


class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, blob_key):
        blob_key = str(urllib.unquote(blob_key)) 

        # BlobKeyを指定してファイルを取得
        blob_info = blobstore.BlobInfo.get(blob_key)

        # 結果をクライアントに返す
        self.send_blob(blob_info)


def main():
    application = webapp.WSGIApplication([
        ('/', MainHandler),
        ('/upload', UploadHandler),
        ('/serve/([^/]+)?', ServeHandler),
        ], debug=True)
    run_wsgi_app(application)
        
if __name__ == '__main__':
    main()
<html>
    <head>
        <title>Blobstore Sample</title>
    </head>
    <body>
        <form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
            Upload File:
            <input type="file" name="file"><br>
            <input type="submit" name="submit" value="Submit">
        </form>

        <!--Blobstore内のファイルを列挙する-->
        <h2>Uploaded Files</h2>
        <ul>
            <!--file.key()だとテンプレートのパースに失敗するので注意-->
            {% for file in files %}
            <li><a href="/serve/{{ file.key }}">{{ file.filename }}</a></lI>
            {% endfor %}
        </ul>
    </body>
</html>

すごく簡単にファイルのアップロードやダウンロードが実装できました。ファイル分割して BlobProperty に保存しようなんて考えていた自分が馬鹿みたいです。


GAE でファイルを保存するなら Blobstore で決定として、残る問題は料金ですねぇ。。。