Help us understand the problem. What is going on with this article?

Google App Engine + Python アプリから Cloud Storage を利用する

More than 1 year has passed since last update.

※2016年7月4日に書いたブログ記事からの転記です。

Cloud Storage を利用可能にしておく

まず最初に、Google Cloud Console から Cloud Storage を使用できるように初期設定しておく必要があります。

初期設定は「利用開始」を選択して「バケットを作成」しておくだけです。

デフォルトのバケットを作成してそれを使用してもよいですし、新たにバケットを作成してもOKです。

Cloud Storafe クライアント・ライブラリをダウンロードする

App Engine Python アプリから Cloud Storage を利用するには、まず最初に Google Cloud Storage クライアント・ライブラリをダウンロードする必要があります。その方法は3つあります。

(1)Github から ZIP をダウンロードする:Google Cloud Storage client library on GitHub

(2)GitHub から clone する:

git clone https://github.com/GoogleCloudPlatform/appengine-gcs-client.git

(3)PIP からインストールする:

pip install GoogleAppEngineCloudStorageClient -t <your_app_directory/lib>

自分の場合は(1)の方法でダウンロードしました。

ダウンロードしたファイルを解凍して、python → src → cloudstorage というフォルダを app_id/lib に配置します。

app_id/
  lib/
  cloudstorage/

さて、これで準備は整いました。

リクエストハンドラーを記述する

プログラムの大まかな流れは次のとおりです。

(1)ブラウザからファイルを受け取る。

(2)受け取ったファイルを Cloud Storage へ保存する。

(3)Cloud Storage での保存先を Datastore に保存する。

(4)Cloud Storage に保存したファイルを表示する。

まずはフォームの HTML です。

<html>
  <body>
    <form method="post" action="" enctype="multipart/form-data">
      <label for="inputTitle">タイトル</label>
      <input type="text" name="title" id="inputTitle">
      <label for="inputFile">ファイル</label>
      <input type="file" name="file" id="inputFile">
    </form>
  </body>
</html>

次に、このフォームから送信されるデータを受け取る POST のリクエストハンドラーです。

from google.appengine.ext import ndb

from google.appengine.ext import blobstore
from lib import cloudstorage as gcs

# Cloud Storage に保存したファイルのパスを保持するための Datastore モデル
class File(ndb.Model):
    path = ndb.StringProperty()
    type = ddb.StringProperty()

class AdminCreateFileHandler(BaseHandler):
    def get(self):
        context = {}
        self.render_template('file.html', **context)  # 上記のフォームのHTMLを表示

    def post(self):
        title = self.request.get('title')
        file_data = self.request.get('file')
        file_name = self.request.POST['file'].filename
        file_type = self.request.POST['file'].type

        # フォームから受け取ったファイルをCloud Storageに保存
        if file_data:
            bucket_name = os.environ.get(
                "GCS_BUCKET_NAME",  # app.yaml に環境変数としてバケット名があればそれを使用
                app_identity.get_default_gcs_bucket_name())  # なければデフォルトのバケット名を使用

            file_path = '/' + bucket_name + '/files/' + file_name
            with gcs.open(file_path, 'w') as gcs_file:
                gcs_file.write(file_data)

        # Cloud Storage での保存先をDatastoreに保存
        file_key = File(
            path=file_path,
            type=file_type,
            title=title,
        ).put()

        self.redirect('/files/%s' % file_key.urlsafe())  # 適当なURLへリダイレクト

最後に、Cloud Storage に保存したファイルを表示するハンドラーです。

from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers

class RequestHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, gcs_path):
      gs_key = blobstore.create_gs_key('/gs' + gcs_path)
      self.send_blob(gs_key)

このハンドラーを routes 内で

Route(
    r'/gcs<gcs_path:/.+>',
    handler='handlers.gcs.RequestHandler',
)

といった感じのURLにマッピングしてあげます。

ファイルを表示

ファイルを表示したい場合は、テンプレートに以下のように記述します。

<img src="/gcs{{ file.path }}">
<!--file は File モデルのエンティティ-->

以上です。

syousei
WEB: Pyton, JavaScript, Ruby on Rails FPGA: Verilog HDL
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away