Html 使用Django进行静态文件版本控制
我正在为我的CSS/Javascript设置far future expires头,这样浏览器在缓存文件后就不会再请求文件了。我还有一个简单的版本控制机制,这样,如果文件发生更改,客户端就会知道 基本上我有一个模板标签,我做了一些类似Html 使用Django进行静态文件版本控制,html,django,nginx,web-optimization,Html,Django,Nginx,Web Optimization,我正在为我的CSS/Javascript设置far future expires头,这样浏览器在缓存文件后就不会再请求文件了。我还有一个简单的版本控制机制,这样,如果文件发生更改,客户端就会知道 基本上我有一个模板标签,我做了一些类似 这将成为 模板标记打开一个文件javascript/c/c.js.v,在其中找到版本号并将其附加到查询字符串中。该版本由一个shell脚本生成(目前手动运行,可能会添加预提交钩子),该脚本检查文件是否已更改(使用git diff) 这一切正常,除了: 我也想为
这将成为
模板标记打开一个文件javascript/c/c.js.v
,在其中找到版本号并将其附加到查询字符串中。该版本由一个shell脚本生成(目前手动运行,可能会添加预提交钩子),该脚本检查文件是否已更改(使用git diff
)
这一切正常,除了:
我也想为图像实现同样的版本控制。但是图像可以从CSS中引用,CSS是一个静态文件(由nginx提供服务),因此没有模板标记
什么是更好的文件版本控制方法
或者,我正在考虑用中间件替换模板标记,该中间件在返回响应之前更改所有链接。这比模板标记要好,模板标记可能会被错误地忽略。但是仍然不能解决从CSS引用图像的问题
也知道,把这个版本作为查询字符串的一部分可能会给某些代理带来麻烦,而不是缓存文件——所以我考虑把文件名的版本部分——例如:代码> JavaScript /C/C.12345 .JS ./P>
注意:使用Django似乎无法解决这个问题(很明显,因为我甚至没有通过Django提供CSS)。但是必须有一个解决方案,可能涉及到一些nginx技巧。我们使用这个简单的templatetag根据文件修改时间生成版本号:
import os
import posixpath
import stat
import urllib
from django import template
from django.conf import settings
from django.contrib.staticfiles import finders
register = template.Library()
@register.simple_tag
def staticfile(path):
normalized_path = posixpath.normpath(urllib.unquote(path)).lstrip('/')
absolute_path = finders.find(normalized_path)
if not absolute_path and getattr(settings, 'STATIC_ROOT', None):
absolute_path = os.path.join(settings.STATIC_ROOT, path)
if absolute_path:
return '%s%s?v=%s' % (settings.STATIC_URL, path, os.stat(absolute_path)[stat.ST_MTIME])
return path
对于1.3版本之前的Django,该标签有更简单的版本:
@register.simple_tag
def staticfile(path):
file_path = os.path.join(settings.MEDIA_ROOT, path)
url = '%s%s?v=%s' % (settings.MEDIA_URL, path, os.stat(file_path)[stat.ST_MTIME])
return url
用法:
<link rel="stylesheet" href="{% staticfile "css/style.css" %}" type="text/css" media="screen" />
将在我的预提交脚本中添加另一个步骤,用最小化CSS中版本文件的链接替换所有直接链接 看来没有更好的办法了。如果你有任何想法,请告诉我,我会考虑把这个标记为已接受的答案。
谢谢你的评论 这也可能有帮助:我认为一个简单的解决方案可能是:
样式表资产 对于样式表引用的资产,最好使用Sass和Compass。Compass有一个mixin,它将在样式表中引用的静态资产的末尾自动添加版本查询参数。版本号仅在重新生成样式表时更改(在本地开发时,使用
compass-watch
很简单)
模板资产
对于其他文件,我实际上会使用某种类型的post-pull钩子重写python模块,该模块的唯一目的是包含当前版本
/var/www/aweso.me/
./files/
./private-files/
./static/
./project/
./manage.py
./fabfile.py
./.gitignore
./base/
./__init__.py
./wsgi.py
./settings/
./__init__.py
./modules
./__init__.py
./users.py
./email.py
./beta.py
./redis.py
./haystack.py
./version.py
./default.py
./local.py
./live.py
您的后拉钩将创建:
/var/www/aweso.me/project/base/settings/version.py
其中将包含最新(或以前)的git提交哈希:
__version__ = "0763j34bf"
然后,在
设置.live
中使用简单的from.version导入
,您的模板标签就可以简单地使用from settings import ApplicationVersion
将该查询参数写入缓存buster。下面的@paluh答案是您的最佳选择。从Django中的文件中提取文件MTIME不会比直接检查Django中文件的MTIME节省任何东西。这只会增加一层复杂性和另一个故障点(作为cron作业运行的shell脚本)。事实上,mtime可以使我的设置更简单-减少运行脚本的需要和对git的依赖。我通常不信任MTIME(在复制到另一个文件系统或备份时,MTIME可能会更改,或者…),但在这种情况下,我想这并不重要,因为源代码树总是在同一个位置。另外,如果mtime真的因为某种原因而改变,最糟糕的情况就是缓存失效。还不错。在部署前处理CSS文件怎么样?我也做了类似的事情,但没有用Django。这是一个定制的PHP,我首先想到了一个预提交步骤,在这个步骤中我处理文件,但这将不必要地污染我的git时间表。预部署并没有破坏我的git repo,但它还有另一个问题:您没有机会真正查看更改—如果出现问题,您发现可能太晚了。为了便于审查,我会选择预提交而不是预部署。由于图像不会经常更改,上述缺点并没有那么大。与我最初的解决方案有相同的问题。无法处理CSS中引用的图像(除非我通过Django提供CSS)。希望我能找到更好的方法。是的,如何最好地处理CSS文件中的图像是一个长期存在的问题。您不能利用MEDIA\u URL
,并且,与您的情况一样,您不能添加查询字符串或类似的内容来实现缓存。也就是说,除非您通过Django提供文件,但这是一个完全不同的can或WORM。然而,由于您的问题是使修改后的文件的缓存无效,因此可以推测,CSS引用的图像在修改时无论如何都会对应于CSS文件中的编辑。不一定总是这样,但在这里自我管理缓存失效应该不会太困难。