Django won't refresh staticfiles

假装没事ソ 提交于 2019-11-28 18:11:01
  • Clearing static file python manage.py collectstatic --noinput --clear. This will clear the statics beforehand.

  • Clear the browser cache

  • Add a random string after the js file include, e.g jquery.js?rand=23423423, with each load.

Did it help?

knbk

It sounds like both your browsers have the javascript file cached. In Chrome you can clear the cache by pressing Ctrl + Shift + Del and ticking just 'Cached images and files'. Firefox probably has a similar shortcut.

You can take a look at this question on tips to disable caching of static files on your development server altogether.

Derrick Petzold

You need to bust the browser cache. This template tag will output a time based uuid when DEBUG=True. Otherwise it will look for a PROJECT_VERSION environment variable. If that is not found it will output a static version number.

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)

You would use in a template like this:

{% load cache_bust %}

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

and here is the resulting output:

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

I have also struggled with this problem for hours. I have tried to inject random string using Javascript, but this method seems stupid and ugly-looking. One possible way to handle this problem is to introduce a custom tag. See this document for details:

Specifically, you need to create a package called templatetags in whatever apps you have created (or create a new one if you want). And you create any file in this package, and write something like this:

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)

then you can use tag {% static_no_cache '.../.../path...' %} to create a path with random arguments!

I hope this would help!

Instead of using complicated solutions you can add extra parameter to your includes in the templates.

For static includes:

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

For direct includes:

<link rel="stylesheet" type="text/css" href="/site_media/css/style.css?version=1" />  

Note the ?version=1 in the code. Every time you're modifying the css/js file, change this version in the template, so browser will be forced to reload the file.

And if you want to avoid caching at all for some unknown reason, you may use the current timestamp instead of version:

<link rel="stylesheet" type="text/css" href="/site_media/css/style.css?{% now "U" %}" />

To refresh static files you should run python manage.py collectstatic again.

If nothing else works, search for the file name in the project and look for an unexpected copy. If you saved to the wrong location (different app) at some point, or splintered off a new app from an old, load priority may be playing tricks on you.

If you don't want to refresh the browser cache each time you change your CSS and JavaScript files, or while styling images, you need to set STATIC_URLdynamically with a varying path component. With the dynamically changing URL, whenever the code is updated, the visitor's browser will force loading of all-new uncached static files. In this recipe, we will set a dynamic path for STATIC_URL using time of last edit in os.

import os
from datetime import datetime    

def get_file_changeset(absolute_path):
    timestamp = max(map(lambda x: os.path.getmtime(x[0]), os.walk(os.path.join(absolute_path, 'static'))))
    try:
        timestamp = datetime.utcfromtimestamp(int(timestamp))
    except ValueError:
        return ""
    changeset = timestamp.strftime('%Y%m%d%H%M%S')
    return changeset

And next change in your SETTINGS:

from utils.misc import get_file_changeset
STATIC_URL = "/static/%s/" % get_file_changeset(BASE_DIR)

How it works:
The get_file_changeset()function takes the absolute_path directory as a parameter and calls the os.path.getmtime() to each file in each nested directory and finds the last-edited file (with its max edit time). The timestamp is parsed; converted to a string consisting of year, month, day, hour, minutes, and seconds; returned; and included in the definition of STATIC_URL.

Note: With this you have to reload dev server each time when you edit your static files.

One solution is to change the settings to the following:

STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

What this does is create a copy of the static file with a content hash in the file name (when running collectstatic). This way when the contents are changed the filename is changed and the old cache won't be used. The only problem with this is it doesn't get used when in DEBUG = True mode so you have to do a shift-reload to do a hard reload.

You can read the docs on ManifestStaticFilesStorage for more info.

EDIT: I found a solution for making sure static files are not cached in dev and posted it on another question.

Chandan Sharma

For me after re collecting the static files Just Changes reflected for me.

$ python manage.py collectstatic --noinput --clear

Now run your server, hope it works.

$ python manage.py runserver

Your browser will cache images and files (javascript included). First, clear just your cached images and files. Then use incognito mode in chrome or private browsing in firefox while you are making changes to your .js files so you see them instantly after a page refresh

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!