概要
Djangoをローカル環境で起動したら、なぜかJSなどの静的ファイルが読み込まれない404エラーに...。
おかしいなぁ本番環境では正常に動いているプログラムなのに...と思ったら、思わぬところに原因がありました。
原因はDEBUG
設定
原因は、DjangoのDEBUG
設定にありました。
settings.py
で明示的にDEBUG=True
と追記したら無事に読み込まれるようになりました。
調べてみると多くの場所で既にこの現象の対応策が書かれていました。
stackoverflowでもそんなコメントが盛りだくさん。
On localhost, make sure to define DEBUG = True on settings.py
引用元:Django Static files 404
また、以下の記事にはこのように記載がありました。
DEBUG=True と設定すると、本来Webサーバーを経由してstaticやmediaのファイルを読み込むところをdjangoアプリ内のstaticとmediaを見に行くように設定することができます。
引用元:【Django】debug=False設定時staticとmediaのファイルが読み込めない事象の解決
なぜDEBUG設定でSTATICが読めるようになるのか?
DEBUG = False
の状態では、Djangoは静的ファイルを提供するための役割を持っていません。
じゃあ、本番環境ではFalse
にしているけどどうしているの?といえば、静的ファイルを提供するのは通常、Webサーバー(NginxやApacheなど)の役割です。
Django自体が「静的ファイルの提供」という責任を持たない設計思想なのです。Webサーバに任せた方が効率的で高速だから、でしょう。
では、開発環境では一体誰が静的ファイルを提供してくれているのか?
というと、Django内蔵の開発用Webサーバー(runserver)です。
「え、python manage.py runserver 0.0.0.0:8000
みたいなコマンド使ってないんだけど!?」っというケースもあるかもですが、DEBUG=True
に設定すると、このrunserverが使用されるようになります。
そして、このサーバによって静的ファイルが提供されるようになるのです。
逆を言えば、Webサーバを使わない開発環境下では、runserverを使わないと静的ファイルが読み込まれません。
(nginxのdockerを利用してconfで設定するという方法もありますので、これは別途また記事にしたいと思います。あとは静的ファイル提供用のPythonライブラリもあるみたいです)
ただし、言わずもがな、デバッグ内容が本番でも見れると、詳細なシステム情報を取得されてしまう可能性があるので本番では使いません。Django公式ドキュメントにもrunserverが自動的に動いてくれていることが書いてありますし、もちろん、開発環境でのみの利用が推奨されています。
During development, if you use django.contrib.staticfiles, this will be done automatically by runserver when DEBUG is set to True (see django.contrib.staticfiles.views.serve()).
This method is grossly inefficient and probably insecure, so it is unsuitable for production.
runserverはどんな流れで処理しているのか?
処理の流れとしては以下になっていると考えられます。
①runserverがSTATIC_URL
(settings.py
で行う/static/
とかのこと)のリクエストをクライアントから受け取る
②Djangoはそれを確認し、静的ファイルとみなす
③runserverは設定ファイル(settings.py
)で定義されたSTATIC_ROOT
のパスを確認し、静的ファイルのルートディレクトリとして使用
④リクエストされた静的ファイルがSTATIC_ROOT
内に見つかった場合、runserverはそのファイルをクライアント(ブラウザなど)に返す
static
ファイルをnginxから見せるような手間がいらなくなるので、ローカル環境で行う場合はrunserverを使った方が良いケースが多いかと思います。