2014/09/10

Google App Engineでファイルを保存する方法3つ


Google App Engineでは、通常のWebアプリケーションのように、サーバー上のファイルシステムへアクセスすることができない。別の方法でファイルの読み書きをする事になるけど、方法はいくつかあるので、それぞれの方法と長所短所をまとめてみた。サンプルと全てのソースコードはこちら。(サンプル/ソースコード)

方法1:BlobPropertyを使う

ndb(db)のBlobProperty(https://developers.google.com/appengine/docs/python/ndb/properties)ではバイナリデータをそのまま格納できる。

まずは保存するModelの定義を実装する。
from google.appengine.ext import ndb
class UserFileModel(ndb.Model):
    """
    ファイル格納モデル
    """
    file_data = ndb.BlobProperty()                  # ファイルデータ

続いて、アップロードフォーム。
<form>
<div class="form-group">
<input id="exampleInputFile" name="file_data" type="file" />
    </div>
<button class="btn btn-default" type="submit">保存</button>
</form>

アップロードハンドラを実装。リクエストされたデータをそのまま突っ込むだけ。
def post(self):
        file_data = self.request.get('file_data')
        user_file = UserFileModel()
        user_file.file_data = file_data
        user_file.put()

一番お手軽な方法だけど、1エンティティの上限が1MBまでという制限があるので注意が必要。それより大きいファイルを保存しようとするとこんなエラーが出る。

RequestTooLargeError: The request to API call datastore_v3.Put() was too large.

BlobPropertyではzip圧縮オプション(compressed=True)が使えるので多少容量を抑えることができる。ただ、圧縮しない時よりデータ読み書き時にCPUを消費するのでそこはトレードオフだ。

方法2:Blobstoreを使う

Blobstoreとは、Googleが提供するキー・バリュー型のデータストアサービス。上のBlobPropertyと名前が似てるけど、厳密にはGoogle App Engineとは別領域のサービスだ。

まずはアップロード先URLの生成する。Blobstoreでは、最初にアップロード先のURLを生成しておく必要がある。生成にはgoogle.appengine.ext.blobstoreライブラリの create_upload_url を使う。

upload_url = blobstore.create_upload_url('/file_save/upload2')

引数の /file_save/upload2 は、アップロード後にリダイレクトされるパスを指定する。

続いて、アップロードフォームを実装する。上で生成したアップロードURLがPOST先となるようにする。
<form action="{{ upload_url }}" enctype="multipart/form-data" method="post" role="form">
<div class="form-group">
<input id="exampleInputFile" name="file_data" type="file" />
    </div>
<button class="btn btn-default" type="submit">保存</button>
  </form>

生成したアップロードURLはこんな感じになる。
http://gcp-memo.appspot.com/_ah/upload/AMmfu6aKr-VcNuFlEljprrh7rkbKnBA7WndhyciPTGolHiRkxVq670JENWihVEWViTxRue0K5Y10fOFpmnFzF4hn7qBMIZSn8vhmDT55aO5jNMPqEeQL46R6iWQvEps64_i8WQJsXAHl/ALBNUaYAAAAAVA_q4rzSwstBg1S6i5l3FpfHv4N0EdAR/

/_ah/upload はGoogle App Engineで決まっているシステム用のパスだ。ここでアップロードが行われた後、create_upload_urlで指定したパスに302リダイレクトされる。

アップロード後にリダイレクトされる処理を実装する。ここでBlobstoreに保存したファイルの情報が取れるので、キーを格納したりできる。このハンドラは、google.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandlerクラス を継承しておく必要がある。
class Upload2(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload_files = self.get_uploads('file_data')
        blob_info = upload_files[0]
        self.redirect('/file_save/upload2_done?key=%s' % blob_info.key())

先にアップロードするURLを生成する必要があったり、アップロード後にリダイレクトされたりとちょっと扱いにくい印象。保存したファイルを参照する方法はまたの機会に。

方法3:Google Cloud Storageを使う

Google Cloud Storageは、Google Cloud Platformで提供されているストレージサービスだ。Google App Engineからも簡単にアクセスすることができる。

アップロードフォーム。
<form action="upload3" enctype="multipart/form-data" method="post" role="form">
<div class="form-group">
<input id="exampleInputFile" name="file_data" type="file" />
  </div>
<button class="btn btn-default" type="submit">保存</button>
  </form>

アプロードハンドラを実装。通常のPythonアプリケーションの様に、ストレージ上のファイルの読み書きができる。ファイル操作には、Googleから提供されている Google Cloud Storage Client Libraryを使用する。(ダウンロードしてGAEアプリケーションに組み込んでおく必要がある)。

また、blobstore.create_gs_key 関数を使用すると、blobstoreライブラリで利用できるキーを生成することができる。blobstoreライブラリを使うと大きめのファイルのダウンロード処理が簡単にできるようになるので覚えておきたい。

関連ライブラリがごちゃごちゃしている感があるけど、通常のファイル操作と同じように扱えるため利用しやすい。
import lib.cloudstorage as gcs
# (中略)
class Upload3(Controller):
    def post(self):
        # ファイル名とファイルデータを得る
        file_name = self.request.POST['file_data'].filename
        file_data = self.request.get('file_data')
        # このアプリケーションのデフォルトGCSバケット名を得る
        bucket_name = app_identity.get_default_gcs_bucket_name()
        # 保存パスを作成
        filepath = '/' + bucket_name + '/file_save/' + file_name
        # ファイル作成
        gcs_file = gcs.open(filepath, 'w')
        gcs_file.write(file_data)
        gcs_file.close()
        gcs_key = blobstore.create_gs_key('/gs' + filepath)
        self.set_template_value('message', gcs_key)
        self.draw_template('front/file_save/done.html')

まとめ

総合的に見るとGoogle Cloud Storageが一番良い。1MB未満のデータで無料枠で収まるようなアプリならBlobPropertyがお手軽でいいかも。Blobstoreを使うメリットは無さそうかな。
方法 扱いやすさ 容量制限 ストレージ価格(GB/月)
BlobProperty 1MB $0.18
Blobstore × 2GB $0.026
Google Cloud Storage ほぼ無制限 $0.026

1 件のコメント:

  1. 大変参考になりました。
    これからもいろんな情報アップしてくださいね♪

    返信削除