Django で静的ファイル(CSS・JS)が 404 になり読み込めない(DEBUG=False・collectstatic)
runserver が静的ファイルを配信するのは DEBUG = True のときだけだ。
本番では STATIC_ROOT に collectstatic で集めて Web サーバから配信し、開発中の 404 は置き場所と STATICFILES_DIRS を確認する。
公開:
要約
django.contrib.staticfiles を入れたプロジェクトでは、runserver が /static/ 配下のファイルを自動で配信する。
ただしこれは DEBUG = True のときだけの動作で、公式ドキュメントは「非常に非効率で、おそらく安全でもない」ため本番には向かないと明記している。
そのため、DEBUG = False に切り替えた途端に、CSS や JavaScript などの静的ファイルだけが 404 になる。
本番では次の 2 段階で配信する。
python manage.py collectstatic
# 集まった STATIC_ROOT を Web サーバから配信するよくある原因
DEBUG = Falseにした:runserverの静的ファイル配信は止まる。
ページ本体は表示されるのに、スタイルが外れた状態になる。collectstaticを実行していない: 本番の Web サーバは各アプリのstatic/を見に行かない。collectstaticで 1 か所に集め、そのディレクトリを配信する必要がある。STATIC_ROOTが未設定: 既定値はNoneで、このままcollectstaticを実行するとImproperlyConfiguredで止まる(全文は解決策 2)。STATICFILES_DIRSが無い: Django が標準で探すのは各アプリのstatic/サブディレクトリだ。
プロジェクト直下のstatic/site.cssは、DEBUG = Trueでも登録しない限り 404 になる。
解決策
1. ローカルでは DEBUG を戻すか --insecure を使う
DEBUG = False の挙動を手元で確かめたいときは、--insecure を付けると静的ファイルも配信される。
python manage.py runserver --insecure公式ドキュメントは、このオプションはローカル開発専用で本番では決して使わないよう警告している。DEBUG = False にするなら、ALLOWED_HOSTS の設定も同時に必要になる。
2. collectstatic して Web サーバから配信する
STATIC_ROOT が未設定のまま collectstatic を実行すると、次のエラーになる。
django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app without having set the STATIC_ROOT setting to a filesystem path.STATIC_ROOT を決めて、デプロイのたびに collectstatic を実行する。
# settings.py
STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"python manage.py collectstatic --noinput成功すると … static files copied to '<STATIC_ROOT のパス>'. の形で、コピーした件数が表示される。
集めたディレクトリを、nginx などで STATIC_URL のパスに割り当てる。
location /static/ {
alias /app/staticfiles/;
}3. STATIC_ROOT は置き場所と分ける
STATIC_ROOT は collectstatic の出力先で、ファイルを手で置く場所ではない。STATICFILES_DIRS と同じディレクトリを指定すると、システムチェックで止まる。
?: (staticfiles.E002) The STATICFILES_DIRS setting should not contain the STATIC_ROOT setting.4. アプリに属さないファイルは STATICFILES_DIRS に登録する
STATICFILES_DIRS = [BASE_DIR / "static"]アプリのファイルは blog/static/blog/app.css のように、アプリ名のサブディレクトリを挟んで置く。
公式ドキュメントは、別のアプリに同じ名前のファイルがあると Django が区別できず、最初に見つかったものを使うため名前空間を切るよう説明している。
テンプレートでは {% load static %} の後に {% static "blog/app.css" %} で URL を組み立てる。