Webroot and Favicions

Robert Crowther Jan 2022
Last Modified: Feb 2023

There is a curious problem with favicons in Django. It goes like this… Django has an abstract base representation. The URLs are not locked to a file server structure. Mostly, this is good. But it creates a puzzle when it comes to placing files at webroot. Django has a way of expressing a root URL, but that is not mapped to any file structure.

This puzzle extends to other webroot placements, such as ‘robots.txt’.

Static files

If there is no mapped structure, how does Django map static filess? Well, you don’t need to join in—there is no need to use the module at all—but most sites would use the Django app called Static.

In which case, you would put the static files somewhere in a directory called ‘static’. These ‘static’ directories can be sprinkled round the Django project. A command, ‘collectstatic’ gathers their contents into one definitive directory. Which is then addressed by a configurable URL, usually ‘/static/’.

Take the favicon. To place in Django’s abstraction of ‘webroot’, you would likely place it in the project ‘static’ folder. You could put a favicon anywhere in there, but I suggest the place‐of‐least‐surprise is in the top level,

myProject
└─ myproject
   └─ static
      └─ favicon.ico

Then you would summon the favicon using a link in the header on every page. DRYest place would be in a base template,

<link rel="shortcut icon" type="image/png" sizes="space-separated list of icon dimensions" href="{% static 'favicon.png' %}"/>

The great advantage of this solution is that, when you deploy a Django project, if anything else works, so will the favicon. No difference, no special operations for favicon, it is collected by ‘collectstatic’, then deployed, like any other static file.

The alternative

But maybe you are stubborn, or maybe you don’t like those repetitive headers. Maybe you want the favicon at webroot.

Well, any server you are deploying will have a physical place for the webroot (unlike a Django project). So dump your favicon there. You’ll need a special deployment, but you can gather the favicon with ‘robots.txt’ and ‘sitemap.xml’, while you are at it. Your deployed site will work. Your development site will spew errors, but you know you can ignore them.

Is there a way round the development server issue?

I would not recommend using links on the dev server, and webroot on deployment. It’s going to make a mess of deployment—too tricky, and tricky is not Python.

That said, there are Django tricks to get a favicon working from a URL. If you deploy the URL structure then you will deploy with a wasted URL route. You’ve swapped the repetitive headers for waste in the routing. But some sites don’t use the URL structure, or don’t deliver pages, but may want a favicon available, so try this (N.B. this may not work in SeaMonkey),

from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView

urlpatterns = [
    ...
	path('favicon.ico', RedirectView.as_view(url=staticfiles_storage.url('images/favicon.ico')))
]

Summary

I don’t see this as a great failure or unaddressed issue with Django. The clean layout of Django, and the thinking about static files, is good. What is tricky is that the construction runs into this little problem discussed here. Which problem only means, at worst, ignoring a few error messages—a small price.

References

Wikipedia,

https://en.wikipedia.org/wiki/Favicon

Stackoverflow discussion,

https://stackoverflow.com/questions/21938028/how-can-i-get-a-favicon-to-show-up-in-my-django-app