🔰

【Django】での静的ファイルのキャッシュ対策【超初心者向け】

2025/01/28に公開

前回、こちらでキャッシュバスティングについて解説しましたが、
実際の所、Djangoの場合、ハッシュ値(例:style.css?v=a1b2c3)を
どのように更新するのか、ということをまとめました。

ハッシュ値を更新するためには?

  1. まずpython manage.py collectstaticコマンドを実行したとき:

    • 静的ファイル(CSS, JavaScript, 画像など)のハッシュ値が計算される
    • マニフェストファイルが更新される
  2. その後、{% static %}の部分は:

    • 単にマニフェストファイルを参照して
    • 対応するハッシュ値付きのURLを表示する

つまり:

  • 静的ファイルを更新しただけでは、自動的にはハッシュ値は更新されません
  • collectstaticコマンドを実行することで、初めてハッシュ値が更新されます

例えば:

  1. CSSファイルを更新
  2. collectstaticを実行しないと
  3. 古いハッシュ値のままになります

なので、本番環境では一般的に
- デプロイ時にcollectstaticを実行する
- それによって新しいハッシュ値が生成される
という運用フローになります。

更新忘れが起きない?

上記の流れを見て、
collectstaticの実行、忘れそうじゃない?」
と勘の鋭い人は思うと思います。

「俺でなきゃ見逃しちゃうね」案件だと思います。

ちょっと意味が分からないかもしれませんが、
デプロイ時のcollectstatic実行忘れは実際によくある問題だということです。

これを防ぐための一般的なアプローチをいくつかご紹介します。

  1. デプロイスクリプトの利用
# deploy.sh
#!/bin/bash
git pull
python manage.py collectstatic --noinput  # 自動実行
python manage.py migrate
sudo systemctl restart myapp
  1. CIパイプラインでの自動化
# .github/workflows/deploy.yml の例
jobs:
  deploy:
    steps:
      - uses: actions/checkout@v2
      - name: Deploy
        run: |
          python manage.py collectstatic --noinput
          # その他のデプロイ手順
  1. デプロイツールの利用
# fabfile.py (Fabric使用例)
def deploy():
    with cd('/path/to/project'):
        run('git pull')
        run('python manage.py collectstatic --noinput')
        # その他の手順
  1. Herokuなどのプラットフォームを使う場合
# Procfile
release: python manage.py collectstatic --noinput
  1. デプロイ前チェックリストの実装
# checks.py
from django.core.checks import register, Error

@register()
def check_static_files(app_configs, **kwargs):
    errors = []
    if not os.path.exists('staticfiles/staticfiles.json'):
        errors.append(
            Error(
                'Static files have not been collected',
                hint='Run python manage.py collectstatic',
                id='myapp.E001',
            )
        )
    return errors

これらの方法により:

  • 人的ミスを防ぐ
  • デプロイプロセスを標準化
  • 再現性のあるデプロイを実現

することができます。

また、開発環境では:

# settings.py
if DEBUG:
    STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
else:
    STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

このように設定することで、開発中はcollectstaticを実行しなくても静的ファイルが更新されるようにすることもできます。

Discussion