Some background first. I'm employing the following "trick" to prevent undesired browser caching of static files (CSS, JS, etc.):
<script src="{{ STATIC_URL }}js/utils.js?version=1302983029"></script>
When the version string changes on a subsequent page load, it makes the browser re-fetch the static file from the server. (Google "css caching" for articles on this trick.)
I want the browser to get the latest version of a static file, but I also want to allow browser caching when the file hasn't changed. In other words, I want the version string to change if and only if the static file has been updated. I also would like to generate the version string automatically.
To do this, I'm using the last-modified time of the static file as the version string. I'm making a custom template tag to do this:
<script src="{% versioned_static 'js/utils.js' %}"></script>
And here's how the template tag works:
import os.path
from django import template
from django.conf import settings
class VersionedStaticNode(template.Node):
...
def render(self, context):
# With the example above, self.path_string is "js/utils.js"
static_file_path = os.path.join(settings.STATIC_ROOT, self.path_string)
return '%s?version=%s' % (
os.path.join(settings.STATIC_URL, self.path_string),
int(os.path.getmtime(static_file_path))
)
To get the static file's last-modified time, I need to know its filepath on the system. I get this filepath by joining settings.STATIC_ROOT
and the file's relative path from that static root. This is all well and good for the production server, since all static files are collected at STATIC_ROOT
.
However, on a development server (where the manage.py runserver command is being used), static files aren't collected at STATIC_ROOT
. So how do I get the filepath of a static file when running in development?
(To clarify my purpose: the caching situation I want to avoid is the browser using a mismatch of new HTML and old CSS/JS. In production, this can greatly confuse users; in development, this can confuse me and other developers, and forces us to refresh pages/clear the browser cache frequently.)
If using django.contrib.staticfiles, here's an extract of the findstatic command (django/contrib/staticfiles/management/commands/findstatic.py) that should help. It uses the finders.find to locate the file.
from django.contrib.staticfiles import finders
result = finders.find(path, all=options['all'])
path = smart_unicode(path)
if result:
if not isinstance(result, (list, tuple)):
result = [result]
output = u'\n '.join(
(smart_unicode(os.path.realpath(path)) for path in result))
self.stdout.write(
smart_str(u"Found '%s' here:\n %s\n" % (path, output)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With