Django 静态文件版本控制
我正在研究一些针对静态文件及其更新问题的通用解决方案。
示例:假设有一个带有 /static/styles.css
文件的网站 - 并且该网站使用了很长时间 - 所以很多访问者在浏览器中缓存了这个文件
现在我们对此 css 文件进行更改,并在服务器上更新,但有些用户仍然有旧版本(尽管服务器返回修改日期)
明显的解决方案是向文件 /static/styles.css?v=1.1
添加一些版本,但在此案例开发人员必须跟踪此文件中的更改并手动增加版本
第二种解决方案是计算文件的 md5 哈希值并将其添加到 url /static/styels.css/?v={mdp5hashvalue}
,这看起来好多了,但 md5 应该以某种方式自动计算。
他们可能的方式我看到它 - 创建一些像这样的模板标签
{% static_file "style.css" %}
,它将呈现
<link src="/static/style.css?v=md5hash">
但是,我不希望这个标签在每个页面加载时计算 md5,并且我不想将哈希存储在 django-cache 中,因为那样我们将有更新文件后清除...
有什么想法吗?
I'm working on some universal solution for problem with static files and updates in it.
Example: let's say there was site with /static/styles.css
file - and site was used for a long time - so a lot of visitors cached this file in browser
Now we doing changes in this css file, and update on server, but some users still have old version (despite modification date returned by server)
The obvious solution is to add some version to file /static/styles.css?v=1.1
but in this case developer must track changes in this file and manually increase version
A second solution is to count the md5 hash of the file and add it to the url /static/styels.css/?v={mdp5hashvalue}
which looks much better, but md5 should be calculated automatically somehow.
they possible way I see it - create some template tag like this
{% static_file "style.css" %}
which will render
<link src="/static/style.css?v=md5hash">
BUT, I do not want this tag to calculate md5 on every page load, and I do not want to store hash in django-cache, because then we will have to clear after updating file...
any thoughts ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
Django 1.4 现在包含
CachedStaticFilesStorage
这正是您所需要的(嗯......几乎)。自 Django 2.2
ManifestStaticFilesStorage<应使用 /code>
代替
CachedStaticFilesStorage
。您可以将其与
manage.pycollectstatic
任务一起使用。像往常一样,所有静态文件都是从您的应用程序中收集的,但此存储管理器还会创建每个文件的副本,并将 MD5 哈希值附加到名称中。例如,假设您有一个css/styles.css
文件,它还会创建类似css/styles.55e7cbb9ba48.css
的内容。当然,正如您所提到的,问题在于您不希望视图和模板始终计算 MD5 哈希值以找出要生成的适当 URL。解决方案是缓存。好吧,您要求的是没有缓存的解决方案,我很抱歉,这就是为什么我说几乎。但确实没有理由拒绝缓存。
CachedStaticFilesStorage
使用名为staticfiles
的特定缓存。默认情况下,它将使用您现有的缓存系统,瞧!但是,如果您不希望它使用常规缓存,也许是因为它是分布式内存缓存,并且您希望避免仅仅为了获取静态文件名而进行网络查询的开销,那么您可以仅为设置特定的 RAM 缓存静态文件
。这比听起来更容易:查看这个优秀的博客文章。它看起来是这样的:Django 1.4 now includes
CachedStaticFilesStorage
which does exactly what you need (well... almost).Since Django 2.2
ManifestStaticFilesStorage
should be used instead ofCachedStaticFilesStorage
.You use it with the
manage.py collectstatic
task. All static files are collected from your applications, as usual, but this storage manager also creates a copy of each file with the MD5 hash appended to the name. So for example, say you have acss/styles.css
file, it will also create something likecss/styles.55e7cbb9ba48.css
.Of course, as you mentioned, the problem is that you don't want your views and templates calculating the MD5 hash all the time to find out the appropriate URLs to generate. The solution is caching. Ok, you asked for a solution without caching, I'm sorry, that's why I said almost. But there's no reason to reject caching, really.
CachedStaticFilesStorage
uses a specific cache namedstaticfiles
. By default, it will use your existing cache system, and voilà! But if you don't want it to use your regular cache, perhaps because it's a distributed memcache and you want to avoid the overhead of network queries just to get static file names, then you can setup a specific RAM cache just forstaticfiles
. It's easier than it sounds: check out this excellent blog post. Here's what it would look like:我建议使用类似 django-compressor 的东西。除了自动为您处理此类内容之外,它还会自动组合和缩小您的文件以实现快速页面加载。
即使您最终没有完全使用它,您也可以检查他们的代码以获取设置类似内容的指导。它比您从简单的 StackOverflow 答案中得到的任何内容都经过了更好的审查。
I would suggest using something like django-compressor. In addition to automatically handling this type of stuff for you, it will also automatically combine and minify your files for fast page load.
Even if you don't end up using it in entirety, you can inspect their code for guidance in setting up something similar. It's been better vetted than anything you'll ever get from a simple StackOverflow answer.
重新发明轮子并创建自己的实现有那么糟糕吗?此外,我希望低级代码(例如 nginx)在生产中为我的静态文件提供服务,而不是 python 应用程序,即使有后端也是如此。还有一件事:我希望链接在重新计算后保持不变,因此浏览器仅获取新文件。所以这是我的观点:
模板.html:
out html:
settings.py:
appname/templatetags/md5url.py:
注意,要应用更改后,应重新启动 uwsgi 应用程序(具体来说是进程)。
Is reinventing the wheel and creating own implementation that bad? Furthermore I would like low level code (nginx for example) to serve my staticfiles in production instead of python application, even with backend. And one more thing: I'd like links stay the same after recalculation, so browser fetches only new files. So here's mine point of view:
template.html:
out html:
settings.py:
appname/templatetags/md5url.py:
Note, to apply changes an uwsgi application (to be specific a process) should be restarted.
Django 1.7 添加了
ManifestStaticFilesStorage
,更好的替代CachedStaticFilesStorage
不使用缓存系统,解决了计算哈希的问题运行时。以下是文档的摘录:摘自文档:
要使用它,只需将以下行添加到
settings.py
中:然后运行
python manage.pycollectstatic
;它会将 MD5 附加到每个静态文件的名称中。Django 1.7 added
ManifestStaticFilesStorage
, a better alternative toCachedStaticFilesStorage
that doesn't use the cache system and solves the problem of the hash being computed at runtime.Here is an excerpt from the documentation:
To use it, simply add the following line to
settings.py
:And then, run
python manage.py collectstatic
; it will append the MD5 to the name of each static file.您的 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 /样式/cssv2/
。How about you always have a URL Parameter in your URL with a version and whenever you have a major release you change the version in your URL Parameter. Even in the DNS. So if
www.yourwebsite.com
loads upwww.yourwebsite.com/index.html?version=1.0
then after the major release the browser should loadwww.yourwebsite.com/index.html?version=2.0
I guess this is similar to your solution 1. Instead of tracking files can you track whole directories? For example ratehr than
/static/style/css?v=2.0
can you do/static-2/style/css
or to make it even granular/static/style/cssv2/
.@deathangel908 代码有更新。现在它也适用于 S3 存储(以及我认为的任何其他存储)。区别在于使用静态文件存储来获取文件内容。原始版本不适用于 S3。
应用程序名称/templatetags/md5url.py:
There is an update for @deathangel908 code. Now it works well with S3 storage also (and with any other storage I think). The difference is using of static file storage for getting file content. Original doesn't work on S3.
appname/templatetags/md5url.py:
该解决方案的主要优点:您不必修改模板中的任何内容。
这会将构建版本添加到
STATIC_URL
中,然后网络服务器将使用Rewrite
规则将其删除。settings.py
所以最终的 url 例如是这样的:
然后 Nginx 有一个规则将其重写回
/static/style.css
The major advantage of this solution: you dont have to modify anything in the templates.
This will add the build version into the
STATIC_URL
, and then the webserver will remove it with aRewrite
rule.settings.py
So the final url would be for example this:
And then Nginx has a rule to rewrite it back to
/static/style.css
简单的模板标签
vstatic
创建扩展 Django 行为的版本化静态文件 url:如果您想自动将 STATIC_VERSION 设置为当前 git 提交哈希,您可以使用以下代码片段(如有必要,请调整 Python3 代码)
:
settings.py
调用get_current_commit_hash()
,因此只会计算一次:Simple templatetag
vstatic
that creates versioned static files urls that extends Django's behaviour:If you want to automatically set STATIC_VERSION to the current git commit hash, you can use the following snippet (Python3 code adjust if necessary):
At
settings.py
callget_current_commit_hash()
, so this will be calculated only once:我在所有视图中使用全局基本上下文,其中我将静态版本设置为毫秒时间(这样,每次重新启动应用程序时它将是一个新版本):
我的 page.html 扩展了我的 base.html 模板,我这样使用它:
相当简单并且可以完成工作
I use a global base context in all my views, where I set the static version to be the millisecond time (that way, it will be a new version every time I restart my application):
my page.html extends my base.html template, where I use it like this:
fairly simple and does the job