当只有在更新文件时才强制加载时,Django进行缓存失效处理(cache busting)

首先

当开始全面进行Django的Web应用开发时,会越来越多地处理静态文件,如CSS和JS等,而静态文件的缓存问题则会成为一个令人烦恼的事情。

为了减少页面通信和加载时间,浏览器经常会将静态文件保存在缓存中,并在再次访问时重复使用。因此,即使开发人员对静态文件进行了修改,浏览器可能仍然会使用旧数据而导致显示混乱或出现意外行为。

缓存破解是一种被广泛使用的技巧,它通过在HTML静态文件的路径上添加查询字符串并更改路径,从而确保浏览用户始终加载最新的文件。

通过在Django的设置中添加特定常量或使用名为django-static-md5url的库,可以为静态文件路径添加哈希字符串,并且可以每次都强制重新加载。

然而,如果每次都強制讀取,頁面的加載時間就會變得更長,而且會導致使用者端的快取累積浪費。
因此,這次我們將不使用哈希碼,而是附加文件本身的更新日期,只有在文件更新時才強制進行讀取。

环境

項目内容Python3.9.1Django3.2.9使用ブラウザSafari 15.1

实际的代码

前座: 实施环境建设

我們首先創建一個專案應用程式。

pip install django
django-admin startproject sample_proj
cd sample_proj
django-admin startapp sample_app

文件夹结构

标有“追加”的文件是默认不存在的文件。
标有“不要”的文件本次不使用。

sample_proj/
├── sample_app/
│   ├── static/
│   │   ├── css/
│   │   │   └── index.css: 追加
│   ├── templates/
│   │   └── index.html: 追加
│   ├── templatetags/
│   │   └── cache_busting.py: 追加
│   ├── migrations/
│   ├── admin.py: 不要
│   ├── apps.py
│   ├── models.py: 不要
│   ├── tests.py: 不要
│   ├── urls.py: 追加
│   └── views.py
├── sample_proj/
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

導入之前,各種文件的內容

首先创建要显示的页面数据。

{% load static %}
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <link href="{% static 'css/index.css' %}" rel="stylesheet" type="text/css">
    <title>Cache busting test</title>
  </head>
  <body>
    <p class="test-text">hogehogefugoooo</p>
  </body>
</html>
.test-text {
  color: #ff0000;
}

views.py是一个简单的代码,仅用于渲染HTML页面。

from django.shortcuts import render


def index(request, **kwargs):
    return render(request, 'index.html')

根据许多Django开发的惯例,我们需要在sample_proj和sample_app中都创建一个urls.py。

from django.urls import path

from . import views


urlpatterns = [
    path('', views.index, name='index'),
]
from django.contrib import admin
from django.urls import path, include  # includeを追加


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('sample_app.urls')),  # 追加
]

最后,我们要编辑settings.py文件。在INSTALLED_APPS中添加’sample_app’,以便确保其被识别。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sample_app',  # 追加
]

尝试启动

这次没有定义models.py,但是我们还是先进行迁移吧。
如果在collectstatic时出现错误,通常是因为忘记设置STATIC_ROOT。

python manage.py migrate
python manage.py collectstatic
python manage.py runserver
スクリーンショット 2021-12-20 11.01.58.png

现在最基本的准备已经完成了。

本题: 缓存破坏的实施方案

好的,从这里开始实现缓存破坏的代码。这次我们将使用与模板引擎兼容性较高的模板标签(simple_tag)来实现。

如果你不了解模板标签(templatetag),我认为你应该查看以下的网站。

将 static_cache.py 文件写入先前的文件夹结构中。

from pathlib import Path

from django import template
from django.conf import settings
from django.templatetags.static import static


register = template.Library()


@register.simple_tag
def static_cache(filepath) -> str:
    """静的ファイルのURLにファイルの更新日時クエリを付加する

    """
    # Django標準機能を使ってhtml埋め込み用のパスを取得
    res_path = static(filepath)
    # mtimeを取得する
    full_filepath = Path(getattr(settings, 'STATIC_ROOT', '')).joinpath(filepath)
    file_mtime = str(int(full_filepath.stat().st_mtime))
    # パスに結合
    res_path += '?v=' + file_mtime
    return res_path

说明

由于是闲聊话题,折叠了。最初,Django中存在一个名为static的模板标签来处理静态文件的路由,该标签作为标准功能存在。在本例中,通过一个名为static()的函数来利用该模板标签的机制。具体步骤如下:

通过static标签获取静态文件的路径
使用pathlib库(Python标准库)获取实际文件的更新日期和时间
将更新日期和时间截断为整数(转换为秒单位)并作为查询字符串追加
返回编辑后的路径

严格来说,模板标签static在代码中实际上是一个名为do_static()的函数,与本例使用的不同。如果想了解更详细的信息,请查看以下源代码。

https://github.com/django/django/blob/stable/3.2.x/django/templatetags/static.py

我将测试已经实现的模板标签。我要编辑刚才创建的 index.html。

{% load cache_busting %}  <!--変更-->
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <link href="{% static_cache 'css/index.css' %}" rel="stylesheet" type="text/css">  <!--変更-->
    <title>Cache busting test</title>
  </head>
  <body>
    <p class="test-text">hogehogefugoooo</p>
  </body>
</html>

请编辑后重新启动应用程序,并确保显示与初始页面内容相同的内容。
查看开发者工具时,可以看到CSS路径中已添加了以下更新日期查询。

<link href="/static/css/index.css?v=1639965343" rel="stylesheet" type="text/css">

确认操作

最后,我们需要确认已经成功实现的缓存破坏机制能够正常运行。

将 index.css 文件进行以下更改。

.test-text {
  color: #00ff00;
}

编辑完后,我会执行collectstatic操作。

python manage.py collectstatic
スクリーンショット 2021-12-20 11.30.12.png

当您在开发者工具中查看CSS文件路径时,会发现与之前不同的查询字符串。

<!-- 先ほどのクエリ文字列は 1639965343 だった -->
<link href="/staticfiles/css/index.css?v=1639967407" rel="stylesheet" type="text/css">

最终

通过使用缓存破坏,即使用户不必每次都清除缓存并重新加载,服务器端也能够强制加载所需的静态文件。在使用静态文件时,请务必尝试引入缓存破坏!

广告
将在 10 秒后关闭
bannerAds