86

I have a JavaScript file referenced on a django template:

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

I made some changes to that js file. Then, I refresh the page and I can't see the changes happen.

If I remove the JavaScript from the file and put it in the HTML, it works correctly, but if I try to do it using the external js file then it doesn't. I have tried closing the server and running runserver several times, I've also tried changing from Firefox to Chrome. It makes no sense at all. Please help me understand, I can get away with including all the js inside the HTML but it bothers me that I can't do it the normal way anymore.

More details about this error (the #$&%# weirdest thing I've found):

The JavaScript is something like this:

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.

So, I changed the js and restart the server, still the html shows the old sentence. Then I deleted the reference to the login.js file and put all the js inside script tags in the HTML, of course, the new sentence appears. Then I include the login.js file, comment out the js inside the html but I delete all the content inside the login.js file, making it an empty file... but the old sentence still shows up.

Therefore the old login.js file must be cashed somewhere I don't know. Then I open Chrome and try it all again, same problem.

What can it be? is there an option to force django to refresh staticfiles? I thought restarting the server was enough. Should I reboot my computer?

Alejandro Veintimilla
  • 10,743
  • 23
  • 91
  • 180
  • 6
    have you tried running ```python manage.py collectstatic```? It sounds like you are modifying your working copy of the javascript and it is referencing the collected/out-of-date file. – cziemba Jan 12 '15 at 21:33
  • 32
    Did you try Ctrl-F5 to refresh page with cache clearing ? – Andrew_Lvov Jan 12 '15 at 21:34
  • 1
    Thanks for your comments and your time. I already found the error, it was indeed a weird one. I found that django is pointing local environment staticfiles to the AWS Bucket that I use on deployment. So... running collectstatic is part of the solution I guess, the rest is re-configuring my staticfiles settings and somehow solving the AWS Bucket problem. – Alejandro Veintimilla Jan 12 '15 at 22:40
  • If you are using uwsgi with django, you may need to restart uwsgi to avoid getting old content being served https://stackoverflow.com/a/12632061/4061047 – Edward Moffett Jun 17 '18 at 16:41
  • 1
    I am not sure if this is still relevant, but it can be that in dev environment if you have staticfiles_dirs set, and not only the static root, then django serves the static files from the _dirs not from the _root. That is what happens with me. If I work on the static file in the root, no change applied till collectstatic is run. If I work on a static file in the _dir, Ctrl+F5 applies the change. – Greg Apr 30 '20 at 20:01

18 Answers18

88
  • Clearing static file python manage.py collectstatic --noinput --clear. This will clear the statics beforehand. (Caution: Read before use.)

  • Clear the browser cache

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

double-beep
  • 5,031
  • 17
  • 33
  • 41
Danial Tz
  • 1,884
  • 1
  • 15
  • 20
30

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.

Community
  • 1
  • 1
knbk
  • 52,111
  • 9
  • 124
  • 122
  • 16
    No way , as a good programmer you don't want clients to refresh in this way :( – mullerivan Apr 26 '18 at 01:45
  • Doesn't help and, as @mullerivan already commented, this should not be a solution even if it did work. In addition the above mentioned shortcut deletes cache – rbaleksandar Feb 27 '23 at 13:42
25

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"/>
Micah
  • 1,221
  • 17
  • 42
Derrick Petzold
  • 1,118
  • 13
  • 13
  • 1
    that looks like a good solution! But where exactly should one add this code? – Luiz Tauffer Jun 11 '21 at 14:56
  • 1
    @LuizTauffer Take a look at this: https://docs.djangoproject.com/en/3.2/howto/custom-template-tags/ There should be a folder in the app directory called templatetags, with this file in it (any name you want) and an __init__.py. Then you load it into your template with {% file_name %} – Dzeri96 Nov 21 '21 at 22:48
18

"Changes of staticfiles is not working". There can be multiple reasons for that.

  1. Your browser is storing cache of your static files.

    Solution (1): Open Incognito/Private window

    Solution (2): Use hard refresh:

    • For mac: cmd + shift + r
    • For others: ctr + shift + r
  2. If you're facing this issue in production then follow the steps below:

    • Remove staticfiles folder by following command: sudo rm -rf staticfiles [inside your project directory]

    • Now run collectstatic command: python3 manage.py collectstatic

    • Restart gunicorn, by following command: sudo systemctl restart gunicorn

    • Restart nginx, by following command: sudo systemctl restart nginx

Sometimes browser stores thes staticfiles data (as caches) for a certain time. After couple of hours the problem may gone.

Hope this will fix you issue.

Farid Chowdhury
  • 2,766
  • 1
  • 26
  • 21
13

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" %}" />
The Godfather
  • 4,235
  • 4
  • 39
  • 61
  • This worked a treat. I usually do the catch all reboot: `sudo systemctl daemon-reload && sudo systemctl reload nginx && sudo systemctl restart gunicorn`. However it didnt work on my CSS this time. Adding version direct to stylesheet link did the job. Thanks. – daytony Aug 23 '21 at 09:47
5

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.

Tim Tisdall
  • 9,914
  • 3
  • 52
  • 82
4

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!

Scott Chang
  • 631
  • 1
  • 6
  • 9
4

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
Shayki Abramczyk
  • 36,824
  • 16
  • 89
  • 114
Chandan Sharma
  • 2,321
  • 22
  • 22
2

A simple way to get rid, do a hard refresh cmd+shift+r/ctr+shift+r

A hard refresh is a way of clearing the browser’s cache for a specific page, to force it to load the most recent version of a page. on browser cmd+shift+r/ctr+shift+r

  • Please add some explanation to your answer such that others can learn from it - what makes you think that this works better than other approaches that received dozens of upvotes? – Nico Haase Apr 09 '20 at 12:42
  • Instead of stopping the server and do some extra stuff. i.e run commands or add some code to the project. just refresh your page via cmd+shift+r. (Hard refresh) A hard refresh is a way of clearing the browser’s cache for a specific page, to force it to load the most recent version of a page. – Muhammad Abdullah Apr 09 '20 at 13:24
  • Please add all information to your answer by editing it – Nico Haase Apr 09 '20 at 14:22
1

Simply running python manage.py collectstatic should do the trick. Then hard refresh browser with ctrl + F5 which should work on all browsers.

andypaling1
  • 142
  • 12
1

first run python manage.py collectstatic --link -l then python manage.py collectstatic do not use python manage.py collectstatic --noinput --clear it will bring down your server.

0

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

catavaran
  • 44,703
  • 8
  • 98
  • 85
  • 6
    He's on a dev server using `runserver`. Static files are directly loaded from their original location, so `collectstatic` won't change anything. – knbk Jan 12 '15 at 22:33
0

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.

pragmar
  • 1,004
  • 9
  • 13
0

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.

Chiefir
  • 2,561
  • 1
  • 27
  • 46
0

I was chasing a css static file change tonight. Going thru a Django tutorial. My Django html page would not show the updated css to my base.css file.

I would see the original base.css but no my update to file.This is on a dev environment.

I did not think django cached static on dev and only after running coll ecstatic in production.

For a quick work around I changed the name of my test sites. base.css file to base1.css and the html page link to base1.css

reloaded page and my updated css took affect. No best solution. but quick fix.

0

For a window user, ctrl+f5 does the job on a development server and if this doesn't work then using the command python manage.py collectstatic is working else other ways mentioned in some answers are really risky so it's better to have a backup of your static files.

0

Private Tab works for me. That's why we should use private tabs at the time of development

Juanmi Taboada
  • 539
  • 10
  • 25
-1

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

Jason H
  • 3
  • 7