Webサイトでは一般に、画像、CSS、JavaScriptなど、ブラウザで完全なWebページを表示するために必要なファイルが追加で必要になります。
小さなプロジェクトでは、リソースを絶対パスで指定したり、HTMLファイル内にCSSやJavaScriptの関数をインラインで記述することで、回避することができます。
しかし、これはコーディングのベストプラクティスに反するだけでなく、大規模なプロジェクト、特に複数のアプリケーションを扱う場合には、厄介なことになります。
Django では、インタラクティブなユーザ体験、ドキュメントのプレゼンテーション、機能的な Web ページに必要なファイルを静的ファイルと呼びます。
この記事では、各アプリケーションが提供する複数の静的ファイルのセットをどのように扱えば、Webサイトのルック&フィールをカスタマイズできるかを見ていきます。
静的ファイルの設定
Django は静的ファイルをどのように提供するかについて、非常に大きな柔軟性を提供し ています。
ここでは、ローカル開発での静的ファイルの使用と、少し複雑な実運用での静的ファイルの使用を取り上げます。
まず最初に、基本的な設定を行いましょう。
Django は django.contrib.staticfiles
を提供しており、各アプリケーションから (そしてあなたが指定した他の場所からも) 静的ファイルを集め、実運用で簡単に提供できるようにします。
settings.pyファイルで、
INSTALLED_APPS` は以下のようになっているはずです。
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.contenttypes',
'django.contrib.admin',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles', # To serve static files
]
STATIC_ROOTは、静的ファイルを収集する場所を定義するためのパスです。
settings.py で、 STATIC_ROOT
への絶対パスを指定します。
これを行うには、 os
モジュールの dirname()
関数を使用して、これらのファイルを格納するディレクトリの名前を取得し、パスを定義します。
import os
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
次に、静的ファイルを参照するときに使用する URL である STATIC_URL
を指定する必要があります。
None以外の値を指定する場合は、末尾に
/をつけなければなりません。
以下のパスは、静的ファイルをhttp://localhost:8000/static/または
http://127.0.0.1:8000/static/` という場所に格納することを意味する。
STATIC_URL = '/static/'
Django には STATICFILES_FINDERS
として、静的ファイルを探すのに使うファインダーのリストがあります。
デフォルトのファインダは AppDirectoriesFinder
で、 INSTALLED_APPS
の中にある static
という名前のフォルダを探します。
例えば、プロジェクトに users
というアプリケーションが含まれている場合、 project_name/users/static/index.css
というディレクトリを作って、そのアプリケーションに関連する CSS ファイルを追加することができます。
この場合でも、 project_name/users/static/users/index.css
のように、アプリケーション名で別のサブディレクトリを作成する方がよいでしょう。
これは、似たような名前の静的ファイルが2つ以上ある場合に重要です。
各アプリに index.css
があり、それぞれ異なる CSS スタイルを含んでいると考えましょう。
Django は app/static/
ディレクトリの中から、最初に見つかった index.css
を探します。
これでは、各アプリケーションの static
ディレクトリにある様々な index.css
を区別することができません。
そのため、アプリケーション名 app/static/app/
を持つサブディレクトリを作成しました。
なお、多くのプロジェクトでは、複数のアプリケーションで共通の静的ファイルを持つことができるので、通常は、アプリケーションごとに static
フォルダを作成するのではなく、プロジェクトのルートディレクトリに static
フォルダを作成した方がよいでしょう。
プロジェクトのディレクトリにある全ての静的ファイルを共通の場所に置くには、 AppDirectoriesFinder
が app
ディレクトリにある static
しか探さないので、 STATICFILES_DIRS
を設定して、新しいディレクトリを Django に通知する必要があります。
静的ファイルを置く場所を複数定義することもできます。
複数のプロジェクトがある場合、個々のプロジェクトの静的フォルダーを定義するのはここです。
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, 'static'),
# Extra lookup directories for collectstatic to find static files
)
STATICFILES_DIRSは、
STATICFILES_FINDERSから
FileSystemFinder` を削除しない場合のみ動作することに注意してください。
簡単にまとめると、私たちの settings.py
は以下を含みます。
import os
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'
# Extra lookup directories for collectstatic to find static files
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, 'static'),
)
これで、静的ファイルをプロジェクトで使用する準備が整いました。
あとは {% load static %}
で static
テンプレートタグをロードして、与えられた相対パスに対して URL をビルドするだけです。
それでは、テンプレートファイル base.html
でどのように静的ファイルを利用するか見てみましょう。
<!DOCTYPE html
{% load static %}
<html lang="en"
{% include 'head.html' %}
<style
body{
background: url('{% static "bg.png" %}') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
</style
<body
<div class="row justify-content-center"
<div class="col-8"
<h1 class="mainbtn"MY CUSTOM CSS CLASS</h1
{% block content %}
<hr class="mt-0 mb-4"/
{% endblock %}
</div
</div
</body
</html
大きなプロジェクトでは、通常 head
タグに長いコードを記述するため、 base.html
には head.html
テンプレートが含まれ、適切に分離されます。
h1の
mainbtnクラスは
static/index.cssファイルで定義されています。
背景画像bg.pngも
static` ディレクトリにあります。
head.html
は以下のような構成になっている。
<head
{% block css_block %}{% endblock %}
{% load static %}
<meta charset="utf-8"/
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"/
<link href="{% static 'css/index.css' %}" rel="stylesheet"/
<script src="{% static 'js/functions.js' %}"</script
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"</script
<title{% block title %} Title to be changed in included files {% endblock %}</title
</head
静的ファイルの提供
上記の設定に加え、実際に静的ファイルを提供する必要があります。
これは、 Debug = True
の場合、Django の runserver
コマンドで自動的に行われます。
この方法は簡単なので開発段階では使うべきですが、非効率で安全でないため、実運用では推奨されません。
Django には組み込みのコマンド collecstatic
があります。
これは全ての静的ファイルを、既に設定した一つのディレクトリ STATIC_ROOT
にコンパイルします。
最後に、 collectstatic
コマンドで静的ファイルを収集する際に使用するストレージエンジンです。
ストレージエンジンは STATICFILES_STORAGE
で設定することができます。
Django は独自のストレージエンジンを持っているので、 STATICFILES_STORAGE
のデフォルト値は django.contrib.staticfiles.storage.StaticFilesStorage
に設定されています。
本番環境での静的ファイル
静的ファイルを本番環境に置くには、主に2つの手順があります。
- 静的ファイルが変更されるたびに
collectstatic
コマンドを実行する。 - 静的ファイルサーバに
STATIC_ROOT
を移動して提供するように手配する。
Storageクラスの
post_process()メソッドが 2 番目のステップを担当しますが、実際にはストレージエンジン (例:
STATICFILES_STORAGE`) に依存します。
注意: 環境の違いにより、すべてのプロダクションで静的ファイルを提供することは異なりますが、基本的な考え方と手順は同じです。
運用環境で静的ファイルを扱うには、3つの主要な方法があります。
- 静的ファイルとサイトを同じサーバーから配信する。静的ファイルとサイトを同じサーバーから配信する: 静的ファイルを、すでにウェブアプリケーションを実行しているサーバーから配信したい場合は、この方法を使用します。パフォーマンス上の問題はありますが、ホスティングサーバーが一台で済むため、コスト面では有利です。これを行うには、コードをデプロイサーバーにプッシュしてから
collectstatic
を実行し、すべてのファイルをSTATIC_ROOT
にコピーしてください。最後に、静的ファイルをSTATIC_URL
配下で提供するようにウェブサーバを設定します。 - 専用サーバから静的ファイルを提供する。静的ファイル専用サーバーの最も一般的な選択肢は、nginxとApacheのストリップダウン版です。静的ファイルの専用サーバとして最も一般的なのは、nginxとApacheのストリップダウン版です。静的ファイルが変更されるたびにローカルで
collectstatic
を実行し、STATIC_ROOT
を専用サーバーのディレクトリにプッシュして、サービスを提供します。詳細な手順については、各サーバーのドキュメントを参照してください。 - クラウドサービスから静的ファイルを提供する。クラウドサービスからの静的ファイルの提供:もう一つの一般的な戦術は、Amazon、Microsoft Azure、Alibaba Cloudなどのクラウドストレージプロバイダーから静的ファイルを提供することです。
ここでは、この目的のためにAmazon S3をどのように使用するかを見てみましょう。
まず、以下のコマンドを使用して、2つのPythonライブラリをインストールします。
$ python -m pip install boto3
$ pip install django-storages
boto3ライブラリは、Amazon S3やその他のAmazon Web Services (AWS)にアクセスするためのパブリックAPIクライアントである。
django-storages は Amazon S3、OneDrive などのストレージバックエンドを管理する。
これは組み込みの Django ストレージバックエンド API をプラグインしています。
また、 INSTALLED_APPS
に storages
を追加する必要があります。
今、私たちの INSTALLED_APPS
はこのようになっています。
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.contenttypes',
'django.contrib.admin',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
'storages', # New
]
その後、settings.py
に以下の設定を追加します。
AWS_ACCESS_KEY_ID = your_access_key_id
AWS_SECRET_ACCESS_KEY = your_secret_access_key
AWS_STORAGE_BUCKET_NAME = 'sibtc-static'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
最後に、python manage.py collectstatic
を実行すれば、静的ファイル用の Amazon S3 の設定は完了です。
WhiteNoiseを使った静的ファイルの配信
Amazon S3 のようなサードパーティのクラウドサービスは、有料のサブスクリプションを含むいくつかの理由で使わない人がよくいます。
WhiteNoise を使うと、Django プロジェクトが自分自身の静的ファイルを提供できるようになり、サービスプロバイダに依存せずにどこにでもデプロイできる自己完結したユニットになるのです。
WSGI 互換の任意の Web アプリケーションで動作しますが、Django プロジェクトで最も簡単に設定できます。
WhiteNoiseの設定
でWhiteNoiseをインストールしましょう。
$ pip install whitenoise
settings.pyで、WhiteNoise を
MIDDLEWARE` のリストに以下の順序で追加してください。
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# WhiteNoise Middleware above all but below Security
'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',
]
圧縮サポートと永久にキャッシュ可能なファイルを使用するには、settings.py
に以下を追加してください。
STATICFILES_STORAGE = ‘whitenoise.storage.CompressedManifestStaticFilesStorage’` を追加します。
python manage.py collectstatic`を実行します。
これで完了です。
これで、Heroku などのホスティングプラットフォームに Web アプリケーションをデプロイできるようになりました。
結論
すべての Web サイト開発者は、美しく機能的な Web サイトを作るために静的ファイルを必要とします。
Django は静的ファイルの簡単な設定を提供するだけでなく、そのデプロイメントで遊べるとてつもない柔軟性も備えています。
この記事では、ローカル開発および実運用において、Django の Web アプリケーションに静的ファイルを統合するいくつかの方法について取り上げました。