Mastering Django Static Files

Failproof Favicons

In pretty much every Django project I’ve written, I have a URL pattern for ^favicon.ico$' in my urls.py.

I’ve seen a lot of different ways people try to handle favicons; lots of them rely on unstated assumptions, and I really don’t like those. So here’s what I do:

1
2
3
4
5
6
7
8
9
10
11
12
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView

urlpatterns = patterns('',
    url(
        r'^favicon.ico$',
        RedirectView.as_view(
            url=staticfiles_storage.url('favicon.ico'),
            permanent=False),
        name="favicon"
    ),
    # ...

What does that do?

Requests for /favicon.ico get redirected to the URL of 'favicon.ico'according to my staticfiles storage. The storage is what actually serves the favicon, but it’s Django that handles the (first) request.

But why?

I’ve read much more than I wanted to about different browser handling of favicons. I still don’t completely understand it. There are a lot of gotchas. The main thing I’ve taken away is:

Almost all browsers try /favicon.ico by default, so just make sure that points to your favicon and it Should Just Work

How does that redirect really work?

Pretty much in the same way the static template tag does (and if you’re not using it in your templates, you should be).

django.contrib.staticfiles.storage provides staticfiles_storage, which is an instance of your project’s configured static file storage. Storages have a url method that “[r]eturns an absolute URL where the file’s contents can be accessed directly by a Web browser.”, which is exactly what the {% static %} tag uses.

So {% static 'favicon.ico' %} in a template is essentially equivalent to staticfiles_storage.url('favicon.ico') in Python.

Alternatives?

<link> tag

As I mentioned above, lots of people do this:

1
<link rel="icon" href="{% static 'favicon.ico' %}">

Fine enough, if you get the rel attribute right, but (with most staticfiles setups) you’re 404ing when the browser tries /favicon.ico.

I do include this in my markup, but I want to make sure I’m handling /favicon.ico too.

Redirect in your fronting httpd

You might instead handle favicons in front of Django, e.g. with something like the following snippet of nginx config:

1
2
3
4
5
location /favicon.ico {
    alias /path/to/your/static/files/favicon.ico;
    # or
    redirect 301 http://your.static.files.host.example.com/favicon.ico;
}

However with that, you’ve added another deployment requirement to your Django project, and another place where you need to duplicate elements of your static files location. Those aren’t huge problems, but since I can easily avoid them, I’ll gladly do so.

But what about performance?

Sure, you’re having Django handle these requests, even if it is only to return a redirect; from a performance perspective it’d almost certainly be better to deal with them before they reach Django (i.e. in some sort of fronting http proxy like Apache, nginx or HAProxy).

This is a general recommendation, to minimise headaches, and it’ll get you far. If you’re in an environment where this would have significant performance impact, I’d love to hear from you and see your measurements. I doubt many people are.

Stay updated!

Sign up to receive updates on the book’s progress, advice on ways to make your app better, and sample chapters as they become available!

* indicates required

« Stop using STATIC_URL in templates Informal Namespacing »