Django无法刷新静态文件

88

我在 Django 模板中引用了一个 JavaScript 文件:

 <script src="{% static 'js/login.js' %} "></script>

我对那个js文件进行了一些更改。然后,我刷新页面,但是我看不到更改发生。
如果我从文件中删除JavaScript并将其放入HTML中,则它可以正常工作,但是如果我尝试使用外部js文件,则不行。我已经尝试关闭服务器并多次运行runserver,还尝试从Firefox更改为Chrome。这完全没有意义。请帮助我理解,虽然我可以在HTML中包含所有js,但我无法以正常方式完成它让我烦恼。
关于此错误的更多详细信息(我发现的最奇怪的事情):
JavaScript大致如下:
old_sentence = "Dig that hole, forget the sun"  // this is what I want to change
$("#jqselector").text(old_sentence)

new_sentence = "Run, rabbit, run"  // this is the new sentence, it just won't show up.

所以,我更改了js并重新启动了服务器,但html仍然显示旧句子。然后我删除了对login.js文件的引用,并将所有js放在HTML的script标签中,当然,新的句子出现了。然后我包含了login.js文件,注释掉html中的js,但我删除了login.js文件中的所有内容,使其成为空文件...但是旧句子仍然出现。
因此,旧的login.js文件必须被缓存到我不知道的某个地方。然后我打开Chrome再次尝试,仍然存在同样的问题。
可能是什么原因呢?有没有选项强制Django刷新静态文件?我认为重新启动服务器就足够了。我需要重启电脑吗?

6
你尝试过运行python manage.py collectstatic吗?听起来像是你正在修改工作副本中的JavaScript文件,而它引用了已收集但过期的文件。 - cziemba
33
你尝试过按下Ctrl-F5以清除缓存并刷新页面了吗? - Andrew_Lvov
1
谢谢您的评论和宝贵时间。我已经找到了错误,确实是一个奇怪的错误。我发现Django将本地环境的静态文件指向了我在部署时使用的AWS Bucket。因此...运行collectstatic可能是解决方案的一部分,其余部分是重新配置我的静态文件设置和解决AWS Bucket问题。 - Alejandro Veintimilla
如果您正在使用uwsgi与django,则可能需要重新启动uwsgi以避免提供旧内容。https://dev59.com/jWjWa4cB1Zd3GeqPvfGu#12632061 - Edward Moffett
1
我不确定这是否仍然相关,但在开发环境中如果您设置了staticfiles_dirs而不仅仅是静态根目录,则Django会从_dirs而不是_root中提供静态文件。这就是我的情况所在。如果我在根目录中处理静态文件,则在运行collectstatic之前不会应用任何更改。如果我在_dir中处理静态文件,则Ctrl+F5才会应用更改。 - Greg
18个回答

89
  • 清除静态文件 python manage.py collectstatic --noinput --clear。这将在使用前先清除静态文件。(注意使用前请阅读。)

  • 清除浏览器缓存。

  • 在 JavaScript 文件包含后添加一个随机字符串,例如每次加载时的 jquery.js?rand=23423423


3
你如何向 <script src="{% static 'js/login.js' %} "></script> 添加随机参数? - statBeginner
为什么要清除所有静态文件?这不意味着你必须重新上传它们吗? - almost a beginner
14
这毁了我的服务器!它删除了我的整个Git仓库。为什么这是被选中的答案? - rcd
8
我尝试了你的第一种方法,它删除了我所有的静态文件 -.- - almost a beginner
它曾经有所帮助,但它并没有帮助Django自己完成这个任务。 - Ashnur
显示剩余3条评论

31

看起来你的两个浏览器都已经缓存了javascript文件。在Chrome中,你可以通过按下Ctrl+Shift+Del,并选择只清除“缓存的图像和文件”来清除缓存。Firefox可能有类似的快捷键。

你可以查看这个问题,获取有关完全禁用开发服务器静态文件缓存的提示。


16
作为一名优秀的程序员,你肯定不希望客户以这种方式进行刷新。 :( - mullerivan
并没有帮助,正如@mullerivan已经评论的那样,即使它起作用,这也不应该是一个解决方案。此外,上述快捷方式会删除缓存。 - rbaleksandar

25

您需要清除浏览器缓存。当 DEBUG=True 时,此模板标签将输出基于时间的 uuid。否则,它将查找 PROJECT_VERSION 环境变量。如果未找到,则输出静态版本号。

import os
import uuid
from django import template                                                                                                              
from django.conf import settings                                                                                                         

register = template.Library()                                                                                                            

@register.simple_tag(name='cache_bust')                                                                                                  
def cache_bust():                                                                                                                        

    if settings.DEBUG:                                                                                                                   
        version = uuid.uuid1()                                                                                                           
    else:                                                                                                                                
        version = os.environ.get('PROJECT_VERSION')                                                                                       
        if version is None:                                                                                                              
            version = '1'                                                                                                                

    return '__v__={version}'.format(version=version)

你可以在这样的模板中使用:

{% load cache_bust %}

<link rel="stylesheet" href="{% static "css/project.css" %}?{% cache_bust %}"/>

这里是生成的输出结果:

<link rel="stylesheet" href="/static/css/project.css?__v__=7d88de4e-7258-11e7-95a7-0242ac130005"/>

1
看起来这是一个不错的解决方案!但是应该在哪里添加这段代码呢? - Luiz Tauffer
1
@LuizTauffer 看一下这个链接:https://docs.djangoproject.com/en/3.2/howto/custom-template-tags/ 在应用程序目录中应该有一个名为templatetags的文件夹,其中包含此文件(任何名称)和__init__.py。然后你可以使用{% file_name %}将其加载到你的模板中。 - Dzeri96

19

"静态文件的更改未生效"。原因可能有多个。

  1. 您的浏览器存储了缓存您的静态文件。

    解决方法 (1): 打开隐身/私密窗口

    解决方法 (2): 使用硬刷新:

    • 对于mac: cmd + shift + r
    • 对于其他设备: ctr + shift + r
  2. 如果您在生产环境中遇到此问题,请按照以下步骤进行操作:

    • 通过以下命令删除staticfiles文件夹: sudo rm -rf staticfiles [在项目目录内]

    • 现在运行collectstatic命令:python3 manage.py collectstatic

    • 通过以下命令重新启动gunicornsudo systemctl restart gunicorn

    • 通过以下命令重新启动nginxsudo systemctl restart nginx

有时候浏览器会将这些静态文件数据(作为缓存)存储一段时间。几个小时后,问题可能会消失。

希望这能解决您的问题。


1
之前不知道有「硬重整」这个功能,感谢提醒。 - PTaHHHa
第一个点对我解决问题已经足够了。谢谢。 - Piyush Kumar
谢谢,这对我有用!第一点解决了我的问题。 - Dondon Jie

13

不必使用复杂的解决方案,您可以在模板中的包含项中添加额外参数。

对于静态包含:

<script src="{% static 'js/polls/polls.js' %}?version=1"></script>

对于直接包含:

<link rel="stylesheet" type="text/css" href="/site_media/css/style.css?version=1" />  
请注意代码中的?version=1。每当您修改CSS / JS文件时,请在模板中更改此版本,以便强制浏览器重新加载该文件。
如果由于某种未知原因要避免缓存,则可以使用当前时间戳代替版本号:
<link rel="stylesheet" type="text/css" href="/site_media/css/style.css?{% now "U" %}" />

这个方法很有效。我通常会使用全面重启:sudo systemctl daemon-reload && sudo systemctl reload nginx && sudo systemctl restart gunicorn。但是这次在我的CSS上没有起作用。将版本直接添加到样式表链接中就可以了。谢谢。 - daytony

6
一个解决方案是将设置更改为以下内容:
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

这样做的作用是在静态文件名中创建一个内容哈希的副本(运行collectstatic时)。这样当内容更改后,文件名也会更改,旧缓存就不会被使用。唯一的问题是,在DEBUG = True模式下不会使用它,因此您必须进行Shift-Reload来进行硬刷新。
您可以阅读ManifestStaticFilesStorage文档获取更多信息。
编辑:我发现了一个确保静态文件在开发中不被缓存的解决方案并在另一个问题上发布了它。

4
我重新收集静态文件后,只是对我进行了更改反映。
$ python manage.py collectstatic --noinput --clear

现在运行你的服务器,希望它可以正常工作。

$ python manage.py runserver

4
我也曾经为这个问题苦苦挣扎了好几个小时。我试图使用JavaScript注入随机字符串,但这种方法看起来很愚蠢且难看。解决这个问题的一种可能的方法是引入自定义标签。请参阅此文档以获取详细信息:链接 具体来说,您需要在您创建的任何应用程序中创建一个名为templatetags的包(如果需要,可以创建一个新的包)。然后,您可以在该包中创建任何文件,并编写类似于以下内容的代码:
from django import template
from django.utils.crypto import get_random_string
from django.templatetags import static

register = template.Library()


class StaticExtraNode(static.StaticNode):

    def render(self, context):
        return super().render(context) + '?v=' + get_random_string(32)


@register.tag('static_no_cache')
def do_static_extra(parser, token):
    return StaticExtraNode.handle_token(parser, token)


def static_extra(path):
    return StaticExtraNode.handle_simple(path)

然后,您可以使用标签{% static_no_cache '.../.../path...' %}来创建带有随机参数的路径!

希望这能有所帮助!


2

简单的方法是进行硬刷新 cmd+shift+r/ctr+shift+r

硬刷新是一种清除浏览器缓存的方法,以强制加载页面的最新版本。 在浏览器上使用 cmd+shift+r/ctr+shift+r


请在您的回答中添加一些解释,以便其他人可以从中学习-您认为这比其他获得数十个赞的方法更有效的原因是什么? - Nico Haase
不要停止服务器并执行一些额外的操作,例如运行命令或在项目中添加一些代码,只需通过 cmd+shift+r 刷新您的页面即可(硬刷新)。硬刷新是清除浏览器缓存以强制加载页面最新版本的一种方式。 - Muhammad Abdullah
请通过编辑您的答案添加所有信息。 - Nico Haase

2

首先运行 python manage.py collectstatic --link -l,然后再运行python manage.py collectstatic,不要使用python manage.py collectstatic --noinput --clear,否则会导致服务器崩溃。


--link -l 是什么意思? - Joshua Johns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接