• Stars
    star
    194
  • Rank 200,219 (Top 4 %)
  • Language
    Python
  • License
    BSD 2-Clause "Sim...
  • Created over 15 years ago
  • Updated about 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Template tags for better serving static files from templates in Django

About django-static

What it does

django_static is a Django app that enables as various template tags for better serving your static content. It basically rewrites references to static files and where applicable it does whitespace optmization of the content. By making references to static content unique (timestamp included in the name) you can be very aggressive with your cache-control settings without ever having to worry about upgrading your code and worrying about visitors using an older version.

The five template tags it enables are the following:

  1. staticfile Takes the timestamp of the file, and makes a copy by symlinking as you define. You use it like this:

    <img src="{% staticfile "/images/foo.png" %}"/>
    

    and the following is rendered:

    <img src="/images/foo.123456789.png"/>
    

    ...assuming the epoch timestamp of the file is 123456789.

  2. slimfile Works the same as staticfile but instead of copying the file as a symlink it actually rewrites the file and compresses it through slimmer. This of course only works for .js and .css files but it works wonderfully fast and is careful enough to not break things. The cool thing about doing this for .css files it finds all relative images inside and applies staticfile for all of them too. You use it just like staticfile:

    <script type="text/javascript"
      src="{% slimfile "/javascript/myscript.js" %}"></script>
    
  3. slimcontent is used to whitespace compress content right in the template. It requires a format parameter which can be "js", "css" or "html". So, for example for some inline CSS content you do this:

    <style type="text/css">
    {% slimcontent "css" %}
    h1, h2, h3 {
        font-face: 'Trebuchet MS', Verdana, Arial;
    }
    {% endslimcontent %}
    </style>
    

    ...and you get this:

    <style type="text/css">
    h1,h2,h3{font-face:'Trebuchet MS',Verdana,Arial}
    </style>
    
  4. staticall combines all files between the tags into one and makes the same symlinking as staticfile. Write this:

    {% staticall %}
    <script src="/javascript/foo.js"></script>
    <script src="/javascript/bar.js"></script>
    {% endstaticall %}
    

    ...and you get this:

    <script src="/javascript/foo_bar.123456789.js"></script>
    
  5. slimall does the same compression slimfile does but also combines the files as staticall. Use it like staticall:

    {% slimall %}
    <script src="/javascript/foo.js"></script>
    <script src="/javascript/bar.js"></script>
    {% endslimall %}
    

staticall and slimall fully support async or defer JavaScript attributes. Meaning this:

{% slimall %}
<script defer src="/javascript/foo.js"></script>
<script defer src="/javascript/bar.js"></script>
{% endslimall %}

...will give you this:

<script defer src="/javascript/foo_bar.123456789.js"></script>

Be careful not to mix the two attributes within the same blocks or you might get unexpected results.

Configuration

django_static will be disabled by default. It's not until you set DJANGO_STATIC = True in your settings module that it actually starts to work for you.

By default, when django_static slims files or makes symlinks with timestamps in the filename, it does this into the same directory as where the original file is. If you don't like that you can override the save location by setting DJANGO_STATIC_SAVE_PREFIX = "/tmp/django-static"

If you, for the sake of setting up your nginx/varnish/apache2, want change the name the files get you can set DJANGO_STATIC_NAME_PREFIX = "/cache-forever" as this will make it easier to write a rewrite rule/regular expression that in nginx/varnish/apache2 deliberately sets extra aggressive caching.

Another option is to let django_static take care of setting your MEDIA_URL. You could do this:

<img src="{{ MEDIA_URL }}{% staticfile "/foo.png" %}"/>

But if you're feeling lazy and what django_static to automatically take care of it set DJANGO_STATIC_MEDIA_URL. In settings.py:

DJANGO_STATIC_MEDIA_URL = "//static.example.com"

In your template:

<img src="{% staticfile "/foo.png" %}"/>

And you get this result:

<img src="//static.example.com/foo.1247785534.png"/>

Right out of the box, DJANGO_STATIC_MEDIA_URL will not be active if DJANGO_STATIC = False. If you want it to be, set DJANGO_STATIC_MEDIA_URL_ALWAYS = True.

By default django_static will look for source files in MEDIA_ROOT, but it is possible tell django_static to look in all directories listed in DJANGO_STATIC_MEDIA_ROOTS. The first match will be used.

There is also a setting DJANGO_STATIC_USE_SYMLINK that can be set to False to force django_static to copy files instead of symlinking them.

Advanced configuration with DJANGO_STATIC_USE_MANIFEST_FILE

If you enable, in your settings, a variable called DJANGO_STATIC_USE_MANIFEST_FILE you can save filenames to manifest.json which is stored in the first match directory in DJANGO_STATIC_MEDIA_ROOTS. This is for the usecase where we want to manually upload css and javascript files to CDN. On production, where DEBUG=False, django-static will pick the filenames from manifest.json file instead of doing all the calculations.

Advanced configuration with DJANGO_STATIC_FILE_PROXY

If you enable, in your settings, a variable called DJANGO_STATIC_FILE_PROXY you can make all static URIs that django_static generates go though one function. So that you, for example, can do something with the information such as uploading to a CDN. To get started set the config:

DJANGO_STATIC_FILE_PROXY = 'mycdn.cdn_uploader_file_proxy'

This is expected to be the equivalent of this import statement:

from mycdn import cdn_uploader_file_proxy

Where mycdn is a python module (e.g. mycdn.py) and cdn_uploader_file_proxy is a regular python function. Here's the skeleton for that function:

def cdn_uploader_file_proxy(uri, **kwargs):
    return uri

Now, it's inside those keyword arguments that you get the juicy gossip about what django_static has done with the file. These are the pieces of information you will always get inside those keyword argments:

new = False
checked = False
changed = False
notfound = False

The names hopefully speak for themselves. They become True depending on what django_static has done. For example, if you change your foo.js and re-run the template it's not new but it will be checked and changed. The possibly most important keyword argument you might get is filepath. This is set whenever django_static actually does its magic on a static file. So, for example you might write a function like this:

on_my_cdn = {}

def cdn_uploader_file_proxy(uri, filepath=None, new=False,
                            changed=False, **kwargs):
    if filepath and (new or changed):
        on_my_cdn[uri] = upload_to_my_cdn(filepath)

    return on_my_cdn.get(uri, uri)

Advanced configuration with DJANGO_STATIC_FILENAME_GENERATOR

By default, django-static generates filenames for your combined files using timestamps. You can use your own filename generating function by setting it in settings, like so:

DJANGO_STATIC_FILENAME_GENERATOR = 'myapp.filename_generator'

This is expected to be the equivalent of this import statement:

from myapp import filename_generator

Where myapp is a python module, and filename_generator is a regular python function. Here's the skeleton for that function:

def filename_generator(file_parts, new_m_time):
    return ''.join([file_parts[0], '.%s' % new_m_time, file_parts[1]])

Advanced configuration with DJANGO_STATIC_COMBINE_FILENAMES_GENERATOR

By default, django-static generates filenames for your combined files by concatenating the file names. You can also use your own filename generating function by setting it in settings, like so:

DJANGO_STATIC_COMBINE_FILENAMES_GENERATOR = 'myapp.combine_filenames'

This is expected to be the equivalent of this import statement:

from myapp import combine_filenames

Where myapp is a python module, and combine_filenames is a regular python function. Here's the skeleton for that function:

path = None
names = []
extension = None
timestamps = []
for filename in filenames:
    name = os.path.basename(filename)
    if not extension:
        extension = os.path.splitext(name)[1]
    elif os.path.splitext(name)[1] != extension:
        raise ValueError("Can't combine multiple file extensions")

    for each in re.finditer('\.\d{10}\.', name):
        timestamps.append(int(each.group().replace('.','')))
        name = name.replace(each.group(), '.')
    name = os.path.splitext(name)[0]
    names.append(name)

    if path is None:
        path = os.path.dirname(filename)
    else:
        if len(os.path.dirname(filename)) < len(path):
            path = os.path.dirname(filename)


new_filename = '_'.join(names)
if timestamps:
    new_filename += ".%s" % max(timestamps)

new_filename = new_filename[:max_length]
new_filename += extension

return os.path.join(path, new_filename)

Compression Filters

Default (cssmin)

django-static uses cssmin by default if it is installed. Get the source here: https://github.com/zacharyvoase/cssmin

Using jsmin

If you would like to use jsmin instead of default js_slimmer, you just need to set the variable in your settings.py file:

DJANGO_STATIC_JSMIN = True

Using Google Closure Compiler

If you want to use the Google Closure Compiler to optimize your Javascript files you first have to download the compiler.jar file and make sure your systam can run java. Suppose you download it in /usr/local/bin, the set this variable in your settings.py file:

DJANGO_STATIC_CLOSURE_COMPILER = '/usr/local/bin/compiler.jar'

If for some reason the compiler chokes on your Javascript it won't halt the serving of the file but it won't be whitespace optimized and the error will be inserted into the resulting Javascript file as a big comment block.

Using the YUI Compressor

The YUI Compressor is both a Javascript and CSS compressor which requires a java runtime. Just like the Google Closure Compiler, you need to download the jar file and then set something like this in your settings.py:

DJANGO_STATIC_YUI_COMPRESSOR = '/path/to/yuicompressor-2.4.2.jar'

If you configure the Google Closure Compiler and YUI Compressor, the Google Closure Compiler will be first choice for Javascript compression.

Using the slimmer

slimmer is an all python package that is capable of whitespace optimizing CSS, HTML, XHTML and Javascript. It's faster than the YUI Compressor and Google Closure but that speed difference is due to the start-stop time of bridging the Java files.

How to hook this up with nginx

Read this blog entry on peterbe.com

More Repositories

1

premailer

Turns CSS blocks into style attributes
Python
1,041
star
2

mincss

Tool for finding out which CSS selectors you're NOT using.
Python
855
star
3

minimalcss

Extract the minimal CSS used in a set of URLs with puppeteer
JavaScript
351
star
4

autocompeter

A really fast AJAX autocomplete service and widget
Python
277
star
5

django-cache-memoize

Django utility for a memoization decorator that uses the Django cache framework.
Python
158
star
6

github-pr-triage

A dashboard of Github Pull Requests
JavaScript
149
star
7

django-fancy-cache

A Django `cache_page` decorator on steroids.
Python
145
star
8

tornado-utils

Utility scripts for a Tornado site
Python
135
star
9

tiler

App for allowing you to host some huge ass photos on the web.
JavaScript
127
star
10

django-mongokit

Bridging Django to MongoDB with the MongoKit ODM (Object Document Mapper)
Python
122
star
11

govspy

Go vs. Python
Python
112
star
12

django-sockjs-tornado

Makes it easy to run a SockJS server in Django through Tornado.
Python
102
star
13

hashin

Helping you write hashed entries for packages in your requirements.txt
Python
98
star
14

whatsdeployed

What's deployed from a Github repo on various server environments?
JavaScript
84
star
15

python-gorun

Using (py)inotify to run commands when files change
Python
66
star
16

toocool

too cool for me
JavaScript
62
star
17

worklog

Tornado app behind DoneCal
JavaScript
59
star
18

django-peterbecom

Code for my personal home page
CSS
54
star
19

django-html-validator

A tool to do validation of your HTML generated from your Django app.
Python
47
star
20

tornado_gists

Collaborative collection of Tornado related Github gists
Python
39
star
21

htmltree

Finding out which DOM nodes weigh the most
CSS
28
star
22

premailer.io

A website that uses premailer
JavaScript
25
star
23

docsql

docsQL - Getting an overview over your Markdown file in your Jamstack site
TypeScript
22
star
24

grymt

Preps a set of HTML files for deployment
Python
20
star
25

groce

A mobile web app to help families do grocery and meal planning.
TypeScript
19
star
26

buggy

A client-side wrapper on the bugzilla.mozilla.org REST API.
JavaScript
16
star
27

optisorl

Django backend plugin for sorl-thumbnail that optimizes thumbnails
Python
14
star
28

fastestdb

A collection of benchmarks for which database is the fastest for Tornado
JavaScript
13
star
29

workon

Personally opinionated Todo list in React
JavaScript
9
star
30

minimalcss-website

Single-page-app website for showcasing minimalcss
JavaScript
9
star
31

minimalcss-server

Node Express server to wrap calling minimalcss
JavaScript
8
star
32

django-fastest-redis

Trying different configurations for django-redis
Python
8
star
33

bgg

A love story with Bugzilla, git and Github
Python
8
star
34

django-jingo-offline-compressor

Using jingo and django_compressor but miss offline compression?
Python
8
star
35

next-peterbecom

New front-end for www.peterbe.com
CSS
7
star
36

github-action-tricks

Tips and tricks to make you a GitHub Actions power-user
Shell
7
star
37

django-spellcorrector

Spellcorrector app for Django
Python
6
star
38

json-schema-reducer

Extract from a JSON/dict ONLY whats in the JSON Schema
Python
6
star
39

youshouldwatch-next

A to-watch list of movies and TV shows
TypeScript
6
star
40

IssueTrackerProduct

A bug/issue tracker for Zope2
Python
5
star
41

django-spending

Bengtsson Household Spending app
Python
5
star
42

remix-peterbecom

Front-end for www.peterbe.com in Remix
TypeScript
5
star
43

sockshootout

Comparing WebSockets vs. jQuery AJAX using Tornado
JavaScript
5
star
44

jest-ts-and-http

Node/TypeScript project that uses `jest` to test a local server
TypeScript
5
star
45

slimmer

slimmer
Python
5
star
46

headsupper

Houston. We have commits coming in.
CSS
5
star
47

peepin

Project superseded by https://github.com/peterbe/hashin
Python
5
star
48

howsmywifi

Measure (repeatedly) your broadband speed using Fast.com in a headless browser.
JavaScript
5
star
49

fake-failbot

Mock server to use locally instead of a real FailBot server
JavaScript
5
star
50

django-fastest-cache

Experiment to see speed of using various caching backends
Python
5
star
51

chiveproxy

Experimental React PWA
JavaScript
4
star
52

cheerio-to-text

Turning a Cheerio objects into plain text
TypeScript
4
star
53

ghdocs-goer

A VS Code Extension for people who contribute to https://github.com/github/docs by editing Markdown files in VS Code.
TypeScript
4
star
54

redunter

Hunting down unused CSS since 2015
Python
4
star
55

gg

Git and GitHub for the productivity addicted
Python
4
star
56

python-reverse-geocode-test

Comparing Google Reverse Geocoding against GeoNames
3
star
57

python-donecal

Python interface for the donecal.com restful HTTP API
Python
3
star
58

sockshootout2019

XHR vs WebSockets 2019
JavaScript
3
star
59

hylite

A CLI for syntax highlighting code to HTML
TypeScript
3
star
60

minimalcss2

A Node library to extract the minimal (critical) CSS based on a string of HTML and a string of CSS.
TypeScript
3
star
61

uslicenseplates

US License Plate Spotter
JavaScript
3
star
62

fwc_mobile

Python
3
star
63

esrun-tsnode-esno

ts-node vs. esrun vs. esno vs. bun
TypeScript
3
star
64

rpsls

Rock Paper Scissors Lizard Spock
3
star
65

render-block-images-in-css

Experimenting with inlining CSS images with data URLs
JavaScript
3
star
66

slowpage

Experimenting with browsers' resource download behaviour
Python
3
star
67

SMTPSink

Very basic script for running a SMTP service to see sent emails
Python
2
star
68

mdn-yari-content

All the MDN documents as index.html and index.yaml.
2
star
69

tornado_gkc

GKC (tornado)
JavaScript
2
star
70

minimalcss-cli

JavaScript
2
star
71

activity

An experiment with logging project activities
JavaScript
2
star
72

react-buggy

Side-project in need of a better name
JavaScript
2
star
73

FriedZopeBase

Misc utility Zope2 Product with nifty base classess
JavaScript
2
star
74

kl

Crosstips.org
Python
2
star
75

programmatically-render-next-page

Programmatically render a Next page without a server in Node
TypeScript
2
star
76

podcasttime2

client-side for podcastti.me
JavaScript
2
star
77

dinnerd

Experiment to plan weekly dinners
JavaScript
2
star
78

express-vs-fastify-vs-polka

Comparing Express, Polka, and Fastify for serving static assets
JavaScript
2
star
79

ZSQL

A Zope2 Product for executing SQL in a file based Zope2 product
Python
2
star
80

mdn-nottranslated

Actually NOT Translated on MDN?
JavaScript
2
star
81

fake-hydro

Receive Hydro send events locally
JavaScript
2
star
82

langdetect

Wrapping whatlanggo as a CLI in Go
Go
2
star
83

battleshits

You will never shit in peace
JavaScript
2
star
84

github-slideshow

A robot powered training repository πŸ€–
HTML
2
star
85

primer-autocomplete

A standalone implementation of @primer/react Autocomplete to build a typehead search feature
TypeScript
2
star
86

ws-sane-demo

A playground to play with WebSockets and Sane.
JavaScript
1
star
87

gityouracttogether

Learning how to pretend a commit never happened
1
star
88

zope_products

Old ZOPE products
Python
1
star
89

justmerge

Automatically merge/land GitHub Pull Requests that are ready
Python
1
star
90

http-request-relay

Make HTTP request via distributed AWS Lambda functions
Python
1
star
91

gitbusy

What are you gitting busy with?
JavaScript
1
star
92

django-thuawood

A website for my mom.
Python
1
star
93

elmo-docs

Documentation for the Mozilla Elmo project
Python
1
star
94

django-stephanie

A website for my friend Stephanie Kearley MΓΌller
CSS
1
star
95

gaffwall

canvas + slippy map
JavaScript
1
star
96

spellthese

"Train your own spell corrector with TextBlob" blog post demo code
HTML
1
star
97

mondayosaseri

1
star
98

lang-analyze

A scrappy script to analyze the state of translated documents in MDN.
JavaScript
1
star
99

classy

An online Bayesian classifier for anybody via a REST API
JavaScript
1
star
100

aroundtheworld

JavaScript
1
star