Package: django-static
ContentsWhat it doesConfigurationAdvanced configuration with DJANGO_STATIC_USE_MANIFEST_FILEAdvanced configuration with DJANGO_STATIC_FILE_PROXYAdvanced configuration with DJANGO_STATIC_FILENAME_GENERATORAdvanced configuration with DJANGO_STATIC_COMBINE_FILENAMES_GENERATORCompression FiltersDefault (cssmin)Using jsminUsing Google Closure CompilerUsing the YUI CompressorUsing the slimmerHow to hook this up with nginxWhat it doesdjango_staticis 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:staticfileTakes 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.slimfileWorks the same asstaticfilebut instead of copying
the file as a symlink it actually rewrites the file and compresses
it throughslimmer. This of
course only works for.jsand.cssfiles but it works
wonderfully fast and is careful enough to not break things. The
cool thing about doing this for.cssfiles it finds all relative
images inside and appliesstaticfilefor all of them too. You use
it just likestaticfile:<script type="text/javascript"
  src="{% slimfile "/javascript/myscript.js" %}"></script>slimcontentis 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>staticallcombines all files between the tags into one and
makes the same symlinking asstaticfile. 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>slimalldoes the same compressionslimfiledoes but also
combines the files asstaticall. Use it likestaticall:{% slimall %}
<script src="/javascript/foo.js"></script>
<script src="/javascript/bar.js"></script>
{% endslimall %}staticallandslimallfully supportasyncordeferJavaScript 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.Configurationdjango_staticwill be disabled by default. It’s not until you setDJANGO_STATIC = Truein your settings module that it actually starts
to work for you.By default, whendjango_staticslims 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 settingDJANGO_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 setDJANGO_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 yourMEDIA_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 setDJANGO_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_URLwill not be active
ifDJANGO_STATIC = False. If you want it to be, setDJANGO_STATIC_MEDIA_URL_ALWAYS = True.By default django_static will look for source files inMEDIA_ROOT,
but it is possible tell django_static to look in all directories listed
inDJANGO_STATIC_MEDIA_ROOTS. The first match will be used.There is also a settingDJANGO_STATIC_USE_SYMLINKthat can be set toFalseto force django_static to copy files instead of symlinking them.Advanced configuration with DJANGO_STATIC_USE_MANIFEST_FILEIf you enable, in your settings, a variable calledDJANGO_STATIC_USE_MANIFEST_FILEyou can save filenames to
manifest.json which is stored in the first match directory inDJANGO_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_PROXYIf you enable, in your settings, a variable calledDJANGO_STATIC_FILE_PROXYyou can make all static URIs thatdjango_staticgenerates 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_proxyWheremycdnis a python module (e.g.mycdn.py) andcdn_uploader_file_proxyis a regular python function. Here’s the
skeleton for that function:def cdn_uploader_file_proxy(uri, **kwargs):
    return uriNow, it’s inside those keyword arguments that you get the juicy gossip
about whatdjango_statichas 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 = FalseThe names hopefully speak for themselves. They becomeTruedepending
on whatdjango_statichas done. For example, if you change yourfoo.jsand re-run the template it’s notnewbut it will becheckedandchanged. The possibly most important keyword argument you might
get isfilepath. This is set wheneverdjango_staticactually 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_GENERATORBy 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_generatorWheremyappis a python module, andfilename_generatoris 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_GENERATORBy 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_filenamesWheremyappis a python module, andcombine_filenamesis 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 FiltersDefault (cssmin)django-static uses cssmin by default if it is installed.
Get the source here:https://github.com/zacharyvoase/cssminUsing jsminIf 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 = TrueUsing Google Closure CompilerIf you want to use theGoogle Closure
Compilerto 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 CompressorTheYUI Compressoris
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 CompilerandYUI Compressor,
the Google Closure Compiler will be first choice for Javascript
compression.Using the slimmerslimmeris 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 nginxReadthis blog entry on
peterbe.com