Hirologue

年齢を理由にエンジニアになることを諦めないミドルの成長記録

EP 26: Herokuものがたり 〜 静的ファイル設定編

前回までのあらすじ

Djangoで作成したアプリをHerokuにデプロイするための基本的な設定を行い、実行環境によって読み込むファイルを切り替える設定を行いました。



目次



動作確認

ローカル環境

本番にデプロイできる準備が完了したので、本番環境へデプロイと行きたいところですが、その前にローカル環境できちんと動作するか確認しましょう。

Dockerを使っているので入力するコマンドは、お決まりのコマンドです。

$ docker compose up

settings.pyを分割する前と変わらずアプリが表示されたら、ローカル環境の設定はクリアです。
エラーが出る場合は、どこかに打ち間違いがないか十分確認しましょう。

本番環境

では、いよいよHerokuにデプロイです。
Herokuにデプロイするためのコマンドは、ブランチを切っているかどうかで書き方が違うので、注意が必要です。

  • mainブランチをデプロイする場合
$ git push heroku main


  • ブランチを切った状態でデプロイする場合
$ git push heroku <ブランチ名>:main


例えばブランチ名が、 feature の場合は次のように入力します。

$ git push heroku feature:main


git pushコマンドを使うので、実行前にgit commitコマンドを忘れずに実行しましょう。

デプロイするとログがたくさん流れますが、プロジェクト内に静的ファイルがある場合は、ビルド中にエラーが出ると思います。
出力結果を遡ると、次のように書いてあるはずです。

remote: -----> $ python manage.py collectstatic --noinput
remote:        Traceback (most recent call last):
remote:          File "/app/.heroku/python/lib/python3.12/site-packages/environ/environ.py", line 388, in get_value
...

どうやら、Herokuにデプロイする際に
$ python manage.py collectstatic --noinput​が自動的に実行されることが原因のようです(参考: Django と静的アセット | Heroku Dev Center)。

これを回避するため、デプロイ時に自動で実行しないように設定を変更する必要があります。
ターミナルから次のコマンドを入力しましょう。

$ heroku config:set DISABLE_COLLECTSTATIC=1

このコマンドで一時的にcollecstaticを無効にしますが、後ほど元に戻します。

これでもう一度デプロイするとビルドが成功して、ログを少しだけ遡るとこのようなログが確認できると思います。

...
remote:        https://<アプリの名前>.herokuapp.com/ deployed to Heroku
...

このhttps://<アプリの名前>.herokuapp.com/が、デプロイ先のURLです。
しかし、まだアプリは正常に表示されません。

なかなか一筋縄ではいきませんが、一つずつ確実にクリアしていきますのでご安心ください。



whitenoise

ここでローカル環境では上手く表示できたのに、なぜ本番環境では正常に表示されないのか疑問に思った方もいるかと思います。
公式ドキュメントには次のように理由が記述されています。

Django では、本番環境での静的ファイルの処理がサポートされていません。

つまり、追加で何かしらの設定をしないと静的ファイルは処理されないということです。

ということで、この問題を解決するのがwhitenoiseです。

whitenoiseの設定(その1)

whitenoiseの設定はローカル環境と本番環境で共通にします。
したがって、base.pyに必要な設定を記述します。

まずは、MIDDLEWAREの中にwhitenoiseを追記します。

(略)
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # この位置に追記
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
(略)

このwhitenoiseの記述位置については罠がありまして・・・
whitenoiseドキュメントにひっそりと次のように書いてあります。

settings.py ファイルを編集し、 MIDDLEWARE リストに WhiteNoise を追加してください。
WhiteNoise ミドルウェアDjango SecurityMiddleware (もし使っているなら) の直後で、他の全てのミドルウェアの前に置く必要があります。


「俺でなきゃ見逃してるね」

whitenoiseの設定(その2)

続いて、STATIC_URLSTATICFILES_DIRSSTATIC_ROOTSTORAGEの設定を行います。

base.pyに次のように記述します。

STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = BASE_DIR / 'staticfiles'

STORAGES = {
    'staticfiles': {
        'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage',
    },
}


サイトによってはSTORAGESの部分の書き方が次のようになっているものもあります。

STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

Django4.2からはこの書き方ではなくなったようですので、ご注意ください。

ローカル環境でもwhitenoiseを使う設定

ローカルでは静的ファイルをサポートしているので、ローカル環境でwhitenoiseを使う必要はないとも思えますが、whitenoiseドキュメントには、このように書いてあります。

開発環境では、Django の runserver が自動的に静的ファイルの処理を引き継ぎます。 たいていの場合、これは問題ありませんが、WhiteNoise が静的ファイルハンドリングに施した改良のいくつかが開発環境では利用できなくなり、開発環境と本番環境で動作が異なる可能性が出てきます。
Runserver コマンドに --nostatic オプションを渡すだけで、 Django の静的ファイルハンドリングを無効にして WhiteNoise に引き継がせることができますが、runserver を呼び出すたびにこのオプションを追加するのを忘れないようにする必要があります。
もっと簡単な方法は、 settings.py ファイルを編集して、 whitenoise.runserver_nostatic を INSTALLED_APPS リストの先頭に追加することです

要するにこうです。
ローカルと本番の環境を統一した方がいいので、local.pyINSTALLED_APPSのリストの先頭にwhitenoise.runserver _nostaticを追加しましょう。


では、local.pyに設定を追加しましょう。

# config/settings/local.pyの末尾に以下のコードを追記
(略)
INSTALLED_APPS.insert(0, 'whitenoise.runserver_nostatic')



静的ファイルに関する動作確認

静的ファイル関係の設定が上手くいったのか確認する前に、htmlファイルの内容を見直しましょう。
もし、ファイル内にデータベースからデータを持ってくるような記述があるようなら、その部分はコメントアウトします。

確認が済んだら、デプロイする前に本番環境の環境変数DISABLE_COLLECTSTATICを元に戻しましょう。
ターミナルから次のコマンドを入力します(Herokuダッシュボードを使用して削除しても可)。

$ heroku config:unset DISABLE_COLLECTSTATIC


では、DISABLE_COLLECTSTATICの設定を削除したところで、ローカルで動作確認→本番環境にデプロイの順で進めましょう。



動作確認は無事にできたでしょうか?

もし、エラーが出た場合は、タイプミスを疑いましょう。
わたしもカンマ( , )が抜けてただけといったタイプミスに気づくことができずにかなりの時間を溶かしました!

今の時代、自分で解決できないことって生成AIがサクッと解決してくれたりしますので、数分悩んだら時間を無駄にしないためにも積極的に利用しましょう。

次回は、PostgreSQLの設定について解説する予定です

では、また次の記事で!✋️