【Django×GoogleCloudStorage】メディアファイルを本番環境で扱う

Googleが提供するGAE(Google App Engine)を用いてDjangoアプリケーションをホスティングした場合、ImageFieldを使用した画像を表示させようとするとうまくいきません。

「GAE(GCP)で画像も扱いたい!」

そんな方向けに、解決策として Google Cloud Storage を用いて画像を使用する方法をご紹介します。

今回の内容

・なぜそのままだと画像を扱えないか
・サービスアカウントの作成、連携
・バケットの作成、連携

目次

なぜ画像を扱えないのか

簡潔に言うと、「CloudSQL(MySQL)がメディアファイルのアップロードに対応していないから」です。

なので、メディアファイルを別の場所にアップロード・管理し、アプリケーションと紐づけて管理する必要があります。

この「別の場所」として Google Cloud Storage(以下 Cloud Storage) を使用します。

さらにこの Cloud Storage とDjangoアプリケーションを紐づけることで、メディアファイルを扱うことができるようになります。

ちなみにモデルにて ImageField として定義している項目については、データベース上でファイル名が保存されます。

例えば、モデルでこのように項目を定義しているとします。

from accounts.models import CustomUser
from django.db import models

class CafeMenu(models.Model):
    photo = models.ImageField(verbose_name='写真', blank=True, null=True)
    name = models.CharField(verbose_name='商品名', max_length=255, default='商品名')
    price = models.PositiveIntegerField(verbose_name='値段')
    description = models.CharField(verbose_name='説明', max_length=255)

    # ... 略 ...

「photo」が ImageField です。さらに実際のフォームでこのように入力してレコードを作成したとしましょう。

新規レコード作成フォーム

するとデータベースにはこのような形で保存されます。

データベースのレコードのサンプル

ご覧の通り、入力フォームではメディアファイルをアップロードしていますが、データベースではそのファイルパスが保存されています。このファイルパスを利用して Cloud Storage から画像を引っ張り出して、アプリケーション上で表示させます。

それでは実際に実装していきましょう!

実装する

Cloud Storage を使用してメディアファイルを使用できるようになるまでの流れはこの通りです。

  1. Google Cloud のサービスアカウントを作成
  2. Cloud Storage(バケット) を作成する
  3. サービスアカウントとバケットを紐づける
  4. Djangoの設定ファイル settings.py を編集

GCPに馴染みがない方はこの時点ではイメージがつかないかと思いますが、コンソール上で簡単にできるので安心してください!

Google Cloud のサービスアカウントを作成

まずはサービスアカウントと呼ばれるものを作成します。

STEP
プロジェクトの選択

上記のリンクにアクセスします。

GCPのプロジェクト選択画面に移動します。Djangoアプリケーションをデプロイしているプロジェクトを選択しましょう。

STEP
サービスアカウントを作成

選択したプロジェクトのサービスアカウント一覧ページに移動します。画面上部の「+ サービスアカウントを作成」をクリックします。

STEP
サービスアカウント名の入力

作成するサービスアカウントの詳細入力ページに移動します。任意のサービスアカウント名を入力し、「作成して続行」をクリックします。

STEP
アクセス権の設定

作成したサービスアカウントが「何にアクセスできて、どんな事までできるのか」を設定します。「ロールを選択」をクリックします。

ロールに「storage」と入力→必要に応じた「Storage オブジェクト」を選択。GCSオブジェクトの作成・読み取り・削除も行う前提で「管理者」としています。

STEP
作成

最後に「完了」をクリックしてサービスアカウントを作成します。

STEP
秘密鍵(JSONキー)を取得

サービスアカウント一覧ページに移動します。

先ほど作成したサービスアカウントの右にある「・」が縦に3つ並んだやつ(語彙力)→「鍵を管理」の順でクリックしましょう。

「鍵を追加」→「新しい鍵を作成」の順でクリックします。

「キーのタイプ」はJSONを選択し、「作成」ボタンを押しましょう。

するとJSONデータがローカルマシンにダウンロードされます。そのJSONデータを、Djangoアプリケーションのルートディレクトリ(manage.pyがあるとこ)に移動しておきましょう!

Cloud Storage(バケット) を作成する

続いてメディアファイルを含めた静的ファイル(CSS、jsなど)を格納しておく Cloud Storageバケットを作成します。

バケットは Cloud Storage内のコンテナ単位のことを指します。

STEP
バケットを作成

上記のリンクにアクセスします。

プロジェクトのバケット一覧ページに遷移します。上部の「作成」ボタンをクリックしましょう。

STEP
バケットの設定
バケット名設定

バケット設定画面に移動します。バケット名は自分勝手に命名することはできず、いくつかルールがあるので注意です。

リージョン設定

リージョンは「asia-northeast1(東京)」としました(お好きなところで大丈夫です)。

ストレージクラス設定

ストレージクラスも、用途に合わせて選択してください。

アクセス制御

アクセス制御の項目では「公開アクセス禁止」のチェックを外しましょう。

アプリケーションからアクセスできなくなってしまいます。

データ保護の方法

データ保護の設定はデフォルト通り「なし」にしています。

ここまで設定が完了したら、画面下部の「作成」ボタンをクリックしてバケットを作成しましょう!

サービスアカウントとバケットを紐づける

残念ながら、バケットを作成しただけではアプリケーションからアクセスすることはできません。

そういえば、記事の最初の方でサービスアカウントを作成しましたね。Storageへのアクセス権限も付与していたので大丈夫そうですが、サービスアカウントを作成しただけではまだアクセスすることはできません。

バケット側でも「このアカウントならアクセスしてええで」という設定をしてあげる必要があります。

すなわち「バケットへのアクセス権を持った特定のサービスアカウントを許可する設定」を行う必要があります。

それでは実際にこの作業を行なっていきます。

STEP
サービスアカウントのメールアドレスをコピー

最初に、先ほど作成したサービスアカウントのメールアドレスを控えておきます。

こちらにアクセスしましょう。

サービスアカウント一覧ページに移動します。

この中から、先ほど作成したStorageへのアクセス権限を付与したサービスアカウントのメールアドレスをコピーしておきましょう。

STEP
バケットのトップページにアクセス

このリンク先にアクセスします。

バケット一覧ページに遷移します。この中から、先ほど作成したバケット名をクリックします。

STEP
アクセス権の追加

バケットのトップページに遷移するかと思います。「権限」タブ→「アクセス権を付与」の順でクリックしましょう。

STEP
プリンシパル・ロールの設定

このようにプリンシパルとロールの設定画面が表示されます。それぞれ上図のように入力し、最後に「保存」をクリックして保存しましょう。

以上でバケット側の許可設定はおしまいです!

Djangoの設定ファイル settings.py を編集

やっとDjango側での設定です。

Django側に先ほど作成したサービスアカウントを携えることで、バケットにアクセスすることが出来ます。

まず必要なライブラリ群をインストールしましょう。

(venv)$ pip install django-storages
(venv)$ pip install google-cloud-storage

忘れずに requirements.txt を更新しましょう。

(venv)$ pip freeze > requirements.txt

続いて settings.py に下記のように記述をします。

import os
from google.oauth2 import service_account

GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
    os.path.join(BASE_DIR, '<サービスアカウントの認証鍵のファイル名>.json')
)

DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'

STATICFILES_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'

GS_BUCKET_NAME = '<バケット名>'

STATIC_URL = '/static/'

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

MEDIA_URL = 'https://storage.googleapis.com/<バケット名>/'

<サービスアカウントの認証鍵のファイル名>は、先ほど作成したJSONファイルの名前をコピペしましょう。

<バケット名>も先ほど作成したバケット名をそのままぶち込んでください。

これで settings.py の設定は終了です!

動作確認

きちんと動作するか確認します。

本番環境では開発環境と異なり、静的ファイルを1つの場所にまとめておく必要があります

特段難しいことを行う必要はなく、下記のコマンドを行えば一発でできます。

(venv)$ python manage.py collectstatic

これを行うと、作成したバケットに静的ファイルがアップロードされるはずです。

バケットの中

中身はもちろんプロジェクトによって異なります。

あとはいつも通りデプロイすればOKです!お疲れ様でした!

まとめ

本記事では、GAEにデプロイしたDjangoアプリケーションでメディアファイルを正常に扱う方法をご紹介しました。

しかし、現段階ですと正常に画像は表示されるのですが、アプリケーション側でレコード(データベース)を削除してもバケットにはメディアファイルが残ったままです。

こちらの記事で解決方法をご紹介しておりますのでぜひご覧ください。

ご覧いただきありがとうございました!

詳しく気になる部分や間違い等ございましたら是非お声がけください。

案件、ありますか?

「メインの仕事があるけれど、週1、2日だけできる仕事ないかな、、、」

「ある程度スキルが身に付いてはきたけど、そのスキルを活用できる場が欲しい」

なんて悩みが以前はありました。

自分で仕事を探しに行くのも大事ですが、蛇の道は蛇。その道の人に頼むことで、自分だけでは見つからないような案件に携わることができます。

IT PRO パートナーズでは、簡単に無料でアカウントを登録でき、さらにはエージェントさんに希望の働き方・案件の種類を提示することでお仕事を紹介してくれます!

登録自体も非常に簡単で、「エージェントさんとの面談を希望する」という欄にチェックをするだけで、エージェントさんから直接連絡をいただくことができます。

驚くほど簡単で正直拍子抜けしてしまいました笑

もしお仕事探しに困っておりましたら、一度登録し案件を眺めてみることをおすすめします!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

勤めていた設計会社を退社し、フリーランスとして活動しています
また、趣味で主にpyhonを用いて機械学習を行なっています!
現在競艇の予測モデルの開発中です。

コメント

コメント一覧 (1件)

コメントする

目次