Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How to get a static file's filepath in a development environment?

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.)

like image 751
S. Kirby Avatar asked Dec 13 '22 05:12

S. Kirby


1 Answers

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)))
like image 142
jpic Avatar answered Mar 01 '23 22:03

jpic