私は静的ファイルとその中の更新に関する問題のいくつかの普遍的な解決策に取り組んでいます。
例:/static/styles.css
ファイルのあるサイトがあり、そのサイトが長期間使用されていたため、多くの訪問者がこのファイルをブラウザにキャッシュしたとします。
現在、このcssファイルに変更を加えてサーバーで更新していますが、一部のユーザーはまだ古いバージョンを持っています(サーバーから返された変更日にもかかわらず)
明白な解決策は、ファイル/static/styles.css?v=1.1
にバージョンを追加することですが、この場合、開発者はこのファイルの変更を追跡し、手動でバージョンを上げる必要があります
2番目の解決策は、ファイルのmd5ハッシュをカウントし、それを/static/styels.css/?v={mdp5hashvalue}
というURLに追加することです。
彼らが私がそれを見る可能性のある方法-このようないくつかのテンプレートタグを作成します
{% static_file "style.css" %}
レンダリングされます
<link src="/static/style.css?v=md5hash">
しかし、私はこのタグがすべてのページの読み込みでmd5を計算することを望んでおらず、Django-cacheにハッシュを格納したくないので、ファイルを更新した後でクリアする必要があります...
何かご意見は ?
Django 1.4に CachedStaticFilesStorage
が含まれるようになりました。これは、必要なことを正確に実行します(まあ...mostly)。
Django 2.2 ManifestStaticFilesStorage
なので、CachedStaticFilesStorage
の代わりに使用する必要があります。
manage.py collectstatic
タスクで使用します。すべての静的ファイルは通常どおりアプリケーションから収集されますが、このストレージマネージャーは、名前にMD5ハッシュが付加された各ファイルのコピーも作成します。たとえば、css/styles.css
ファイルがあるとすると、css/styles.55e7cbb9ba48.css
のようなファイルも作成されます。
もちろん、あなたが言及したように、問題は、ビューとテンプレートが常に生成する適切なURLを見つけるためにMD5ハッシュを計算したくないことです。解決策はキャッシュです。さて、あなたはキャッシュなしの解決策を求めました、すみません、それが私がほとんどと言った理由です。しかし、実際にはキャッシングを拒否する理由はありません。 CachedStaticFilesStorage
は、staticfiles
という名前の特定のキャッシュを使用します。デフォルトでは、既存のキャッシュシステムを使用します。しかし、通常のキャッシュを使用したくない場合は、おそらくそれが分散memcacheであり、静的ファイル名を取得するためだけにネットワーククエリのオーバーヘッドを回避したい場合は、特定のRAM staticfiles
専用のキャッシュです。思ったより簡単です:チェックアウト この優れたブログ投稿 。次のようになります。
CACHES = {
'default': {
'BACKEND': 'Django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
},
'staticfiles': {
'BACKEND': 'Django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'staticfiles-filehashes'
}
}
Django-compressor のようなものを使用することをお勧めします。この種のものを自動的に処理するだけでなく、ファイルを自動的に結合して縮小し、ページの読み込みを高速化します。
完全に使用しない場合でも、同様のコードを設定するためのガイダンスとしてコードを調べることができます。これは、単純なStackOverflowの回答から得られるものよりも精査されています。
車輪を再発明して独自の実装を作成するのは悪いことですか?さらに、私は、pythonアプリケーションの代わりに、バックエンドを使用しても、静的ファイルを本番環境で提供するために、低レベルのコード(たとえばnginx)を使用したいと思っています。再計算するため、ブラウザは新しいファイルのみを取得するので、 ここ 自分の視点:
template.html:
{% load md5url %}
<script src="{% md5url "example.js" %}"/>
out html:
static/example.js?v=5e52bfd3
settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')
appname/templatetags/md5url.py:
import hashlib
import threading
from os import path
from Django import template
from Django.conf import settings
register = template.Library()
class UrlCache(object):
_md5_sum = {}
_lock = threading.Lock()
@classmethod
def get_md5(cls, file):
try:
return cls._md5_sum[file]
except KeyError:
with cls._lock:
try:
md5 = cls.calc_md5(path.join(settings.STATIC_ROOT, file))[:8]
value = '%s%s?v=%s' % (settings.STATIC_URL, file, md5)
except IsADirectoryError:
value = settings.STATIC_URL + file
cls._md5_sum[file] = value
return value
@classmethod
def calc_md5(cls, file_path):
with open(file_path, 'rb') as fh:
m = hashlib.md5()
while True:
data = fh.read(8192)
if not data:
break
m.update(data)
return m.hexdigest()
@register.simple_tag
def md5url(model_object):
return UrlCache.get_md5(model_object)
変更を適用するには、uwsgiアプリケーション(具体的にはプロセス)を再起動する必要があります。
私は自分のテンプレートタグを使用して、ファイル変更日をURLに追加します: https://bitbucket.org/ad3w/Django-sstatic
Django 1.7 追加 ManifestStaticFilesStorage
CachedStaticFilesStorage
のより良い代替手段であり、キャッシュシステムを使用せず、実行時に計算されるハッシュの問題を解決します。
以下は抜粋です ドキュメントから :
CachedStaticFilesStorageはお勧めしません–ほとんどの場合、ManifestStaticFilesStorageの方が適しています。 CachedStaticFilesStorageを使用すると、実行時にキャッシュミスによってファイルをハッシュする必要があるため、パフォーマンスが低下します。ネストされたファイルパスの場合にファイルハッシュが正しいことを確認するためにいくつかのファイルアクセスが必要なため、リモートファイルストレージでは、キャッシュミスでファイルをハッシュするためにいくつかのラウンドトリップが必要です。
これを使用するには、次の行をsettings.py
に追加するだけです。
STATICFILES_STORAGE = 'Django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
次に、python manage.py collectstatic
を実行します。 MD5を各静的ファイルの名前に追加します。
このソリューションの主な利点は、テンプレートの内容を変更する必要がないことです。
これにより、ビルドバージョンがSTATIC_URL
に追加され、WebサーバーはRewrite
ルールを使用してそれを削除します。
settings.py
# build version, it's increased with each build
VERSION_STAMP = __versionstr__.replace(".", "")
# rewrite static url to contain the number
STATIC_URL = '%sversion%s/' % (STATIC_URL, VERSION_STAMP)
したがって、最終的なURLは、たとえば次のようになります。
/static/version010/style.css
そして、Nginxは/static/style.css
に書き戻すルールを持っています
location /static {
alias /var/www/website/static/;
rewrite ^(.*)/version([\.0-9]+)/(.*)$ $1/$3;
}
@ deathangel908コードの更新があります。今ではS3ストレージでも(そして私が思う他のどのストレージでも)うまく動作します。違いは、ファイルのコンテンツを取得するために静的ファイルストレージを使用することです。 OriginalはS3では機能しません。
appname/templatetags/md5url.py:
import hashlib
import threading
from Django import template
from Django.conf import settings
from Django.contrib.staticfiles.storage import staticfiles_storage
register = template.Library()
class UrlCache(object):
_md5_sum = {}
_lock = threading.Lock()
@classmethod
def get_md5(cls, file):
try:
return cls._md5_sum[file]
except KeyError:
with cls._lock:
try:
md5 = cls.calc_md5(file)[:8]
value = '%s%s?v=%s' % (settings.STATIC_URL, file, md5)
except OSError:
value = settings.STATIC_URL + file
cls._md5_sum[file] = value
return value
@classmethod
def calc_md5(cls, file_path):
with staticfiles_storage.open(file_path, 'rb') as fh:
m = hashlib.md5()
while True:
data = fh.read(8192)
if not data:
break
m.update(data)
return m.hexdigest()
@register.simple_tag
def md5url(model_object):
return UrlCache.get_md5(model_object)
私はすべてのビューでグローバルベースコンテキストを使用します。静的バージョンをミリ秒に設定します(このように、アプリケーションを再起動するたびに新しいバージョンになります)。
# global base context
base_context = {
"title": settings.SITE_TITLE,
"static_version": int(round(time.time() * 1000)),
}
# function to merge context with base context
def context(items: Dict) -> Dict:
return {**base_context, **items}
# view
def view(request):
cxt = context({<...>})
return render(request, "page.html", cxt)
私のpage.htmlは、私のbase.htmlテンプレートを拡張します。
<link rel="stylesheet" type="text/css" href="{% static 'style.css' %}?v={{ static_version }}">
かなりシンプルで仕事をします
バージョンのあるURLに常にURLパラメータがあり、メジャーリリースがある場合は常にURLパラメータのバージョンを変更するのはどうですか。 DNSでも。したがって、www.yourwebsite.com
がwww.yourwebsite.com/index.html?version=1.0
をロードした場合、メジャーリリース後、ブラウザはwww.yourwebsite.com/index.html?version=2.0
をロードする必要があります
これはソリューション1に似ていると思います。ファイルを追跡する代わりに、ディレクトリ全体を追跡できますか?たとえば、ratehrは/static/style/css?v=2.0
よりも/static-2/style/css
を実行したり、さらに細かく/static/style/cssv2/
にしたりできます。
Djangoの振る舞いを拡張するバージョン管理された静的ファイルのURLを作成する単純なテンプレートタグvstatic
:
_from Django.conf import settings
from Django.contrib.staticfiles.templatetags.staticfiles import static
@register.simple_tag
def vstatic(path):
url = static(path)
static_version = getattr(settings, 'STATIC_VERSION', '')
if static_version:
url += '?v=' + static_version
return url
_
STATIC_VERSIONを現在のgit commitハッシュに自動的に設定する場合は、次のスニペットを使用できます(必要に応じてPython3コードを調整します)。
_import subprocess
def get_current_commit_hash():
try:
return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).strip().decode('utf-8')
except:
return ''
_
_settings.py
_でget_current_commit_hash()
を呼び出すので、これは1回だけ計算されます。
_STATIC_VERSION = get_current_commit_hash()
_