Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static file versioning with Django

I am setting far-future expires headers for my CSS/Javascript so that the browsers don't ever ask for the files again once they get cached. I also have a simple versioning mechanism so that if the files change, the clients will know.

Basically I have a template tag and I do something like

<script type="text/javascript" src="{{ MEDIA_URL }}{% versioned "javascript/c/c.js" %}"></script>

which will become

<script type="text/javascript" src="http://x.com/media/javascript/c/c.min.js?123456"></script>.

The template tag opens a file javascript/c/c.js.v where it finds the version number and appends it to the query string. The version is generated by a shell script (run manually for now, will probably add pre-commit hook) which checks whether the file has changed (using git diff).

This is all working fine, EXCEPT:

I want to implement the same kind of versioning for images as well. But images can be referenced from CSS - which is a static file (served by nginx) - so no template tag there.

What is a better approach for file versioning?

Alternatively, I am thinking about replacing the template tag with a middleware which changes all links before returning the response. That is better than the template tag, which can be mistakenly omitted. But still doesn't solve the issue of images referenced from CSS.

Also, I'm aware that having the version as part of the query string might cause trouble with certain proxies not caching the file - so I consider making the version part of the filename - for example javascript/c/c.123456.js.

Note: It looks like there is no way to solve this issue using Django (obviously - since I don't even serve the CSS through Django). But there has to be a solution, perhaps involving some nginx tricks.

like image 410
ibz Avatar asked Nov 26 '22 12:11

ibz


1 Answers

Stylesheet Assets

For your stylesheet referenced assets, you're much better off using Sass & Compass. Compass has a mixin that will automatically add version query parameters on the end of static assets referenced within a stylesheet. The version number only changes when you rebuild the stylesheet (which is trivial with compass watch while you develop locally).

Template Assets

For other files, I would actually use a post-pull hook of some kind that rewrites a python module whose sole purpose is to contain the current version.

/var/www/aweso.me/
    ./files/
    ./private-files/
    ./static/
    ./project/
        ./manage.py
        ./fabfile.py
        ./.gitignore
        ./base/
            ./__init__.py
            ./wsgi.py
            ./settings/
                ./__init__.py
                ./modules
                    ./__init__.py
                    ./users.py
                    ./email.py
                    ./beta.py
                    ./redis.py
                    ./haystack.py
                ./version.py
                ./default.py
                ./local.py
                ./live.py

Your post pull hook would create :

/var/www/aweso.me/project/base/settings/version.py

Which would contain the latest (or previous) git commit hash :

__version__ = "0763j34bf"

Then with a simple from .version import __version__ as ApplicationVersion in your settings.live, your template tag can simply use from settings import ApplicationVersion to write that query parameter as teh cache buster.

like image 85
airtonix Avatar answered Nov 29 '22 04:11

airtonix