はじめに
Djangoで開発をしていたところ、ローカル環境ではMEDIA_ROOTを使って画像を表示できていても、Herokuなどの本番環境にデプロイした途端に
- 画像が表示されない
- 画像がデプロイのたびに消えてしまう
といった問題にぶつかりました。
なぜならローカルディスクに画像を保存しているだけでは、本番環境では安定して使えないからです。
そこでこの記事では、Cloudinaryを使って画像をクラウドに保存し、Heroku上のDjangoアプリから表示できるようにする手順を整理しました。
そもそもなぜCloudinaryを使うのか
これまでは開発環境でMEDIA_ROOTを使って画像を表示していました。
しかし、この方法には次のような問題がありました。
- 画像ファイルがローカルマシンにしか存在しない
- 本番環境(HerokuのDyno)はファイルシステムが揮発的で、デプロイや再起動のたびに消える
- 外部ユーザーに安定して画像を提供できない
そのため、本番環境では 画像をクラウド上に保存して配信する仕組み が必要であることがわかりました。
Cloudinaryは、これらの問題を解決してくれるサービスです。
- 画像や動画をクラウドに保存
- URLベースでの取得・変換・リサイズが簡単
- Herokuアドオンとしても提供されている
という理由から、今回はCloudinaryを採用しました。
CloudinaryをHerokuに追加する
まずは、HerokuアプリにCloudinaryアドオンを追加します。
# Cloudinaryアドオンの追加
$ heroku addons:create cloudinary:starter
# アドオン一覧の確認
$ heroku addons
cloudinary:starter プランが追加されていればOKです。
環境変数の確認と設定
Cloudinaryアドオンを追加すると、自動的に CLOUDINARY_URL という環境変数が設定されます。
$ heroku config
出力の中に、次のような値が含まれているはずです。
CLOUDINARY_URL: cloudinary://<api_key>:<api_secret>@<cloud_name>
このURLを分解して、以下の3つを環境変数として .env に追記し扱えるようにしておきます。
CLOUD_NAME="<cloud_name>"
CLOUDINARY_API_KEY="<api_key>"
CLOUDINARY_API_SECRET="<api_secret>"
Heroku上の環境変数として登録する場合は、次のように実行します。
$ heroku config:set CLOUD_NAME=<cloud_name>
$ heroku config:set CLOUDINARY_API_KEY=<api_key>
$ heroku config:set CLOUDINARY_API_SECRET=<api_secret>
settings/base.py の設定
ここからはDjango側の設定です。
この記事では、共通設定を base.py にまとめている前提で書いています。
分割する方法はこちら↓
1. アプリの登録
まずは INSTALLED_APPS にCloudinary関連アプリを追加します。
INSTALLED_APPS = [
'django.contrib.admin',
# (略)
'django.contrib.staticfiles',
# ここから追加
'cloudinary_storage',
'cloudinary',
]
2. ストレージの設定
次に、Djangoのどのストレージバックエンドを使うかを STORAGES で指定します。
STORAGES = {
# 静的ファイル(CSS / JS)は WhiteNoise で配信
'staticfiles': {
'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage',
},
# メディアファイル(画像アップロード)は Cloudinary を使用
'default': {
'BACKEND': 'cloudinary_storage.storage.MediaCloudinaryStorage',
},
}
ここで
-
staticfiles…collectstaticで集めた静的ファイル用 -
default…ImageField/FileFieldなどのアップロード先
という役割になっています。
3. Cloudinaryの設定
最後に、Cloudinaryに接続するための設定を追加します。
CLOUDINARY_STORAGE = {
'CLOUD_NAME': env('CLOUD_NAME'),
'API_KEY': env('CLOUDINARY_API_KEY'),
'API_SECRET': env('CLOUDINARY_API_SECRET'),
}
ここでは、env() で環境変数を読み込んでいる前提です(django-environ など)。
Cloudinaryの画像を使ってみる
ここまで設定できれば、DjangoのモデルのImageFieldなどを通じて、Cloudinary上に画像がアップロードされるようになります。
Cloudinary側でリサイズした画像を使う方法などは、以下の記事書いています。
最後に
ローカルのMEDIA_ROOTだけに頼っていると、
- 本番環境で画像が消える
- ユーザーに安定して提供できない
といった問題が起こります。
Cloudinaryを使うことで
- 画像をクラウドに保存できる
- URLベースでリサイズなどの処理も簡単
- Herokuとの相性も良い
と、かなり運用が楽になりました。