This tutorial explains how to add a favicon to a Django website. The trick is it requires configuring your static files properly.

Complete source code can be found on Github.

To start things off, create a local directory for your code. This can exist anywhere easily accessible but if you’re on a Mac (as I am) the Desktop is a convenient choice. Navigate there from the command line and create a new directory called favicon, then change into it.

$ cd ~/Desktop
$ mkdir favicon
$ cd favicon

Now install Django with Pipenv and start the virtual environment with the shell command. (If you need help installing it see here). You’ll know it works correctly because the directory name will be parentheses (favicon).

$ pipenv install django==2.2.2
$ pipenv shell
(favicon) $

Ok, so far so good. Next create a new Django project with the startproject command called favicon_project. Include a period . at the end of the command so that a duplicate directory isn’t created by Django.

(favicon) $ django-admin startproject favicon_project .
(favicon) $ python manage.py migrate
(favicon) $ python manage.py runserver

Go to http://127.0.0.1:8000/ and see the Django Welcome page.

Django Welcome Page

Pages app

Now we’ll add a basic homepage. This requires a dedicated app we’ll call pages. Stop the local server with the Control+c command.

(favicon) $ python manage.py startapp pages

Add it to the bottom of the INSTALLED_APPS configuration within favicon_project/settings.py to notify Django of it.

# favicon_project/settings.py
INSTALLED_APPS = [
    ...
    'pages.apps.PagesConfig', # new
]

We need a URL, a view, and a template for the homepage. While the actual order here is optional–you’ll need all three–I prefer to start with URLs.

URLs

This means adding our pages app to the top-level favicon_project/urls.py file and setting a URL path for it. We don’t want any URL changes so we’ll use the empty string '' for this. Also note that we must import include on the second line as well.

# favicon_project/urls.py
from django.contrib import admin
from django.urls import path, include # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('pages.urls')), # new
]

For some reason Django’s startapp command does not generate a urls.py file for us even though we almost need one. So create one now within pages.

(favicon) $ touch pages/urls.py

And then populate it as follows, referencing a HomePageView we will create in the next step.

# pages/urls.py
from django.urls import path

from .views import HomePageView

urlpatterns = [
    path('', HomePageView.as_view(), name='home'),
]

Views

Now we’re on to the view which we know will be called HomePageView and can rely on Django’s built-in TemplateView. Note that it references a template called home.html that we’ve yet to create.

# pages/views.py
from django.views.generic import TemplateView

class HomePageView(TemplateView):
    template_name = 'home.html'

Templates

And finally our template. We could place this within pages by creating a pages/templates/pages/ directory structure but I prefer creating a top-level templates directory instead. Let’s do that now and add our home.html template.

(favicon) $ mkdir templates
(favicon) $ touch templates/home.html

Now we must tell Django to look here as well as in the app-level templates directory. We do that by updating the DIRS configuration within our settings.py file.

# favicon_project/settings.py
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')], # new
        ...
    }
]

The template itself can just say “Homepage” for now.

<!-- templates/home.html -->
<h1>Homepage</h1>

All set. Make sure the server is running.

(favicon) $ python manage.py runserver

Then check out our new homepage at http://127.0.0.1:8000/.

Home Page

Static Files

How to add a favicon now? We must set up static files where it will live.

Django relies on the staticfiles app to manage static files from across our entire project. The startproject command already comes with a STATIC_URL configuration, which sets the URL we use to reference static files.

We’ll need to set up STATICFILES_DIRS which defines the location of static files in local development. In our project these will all live within a top-level static directory.

# favicon_project/settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),] # new

Create a local static folder for our favicon stopping the local server Control+c if necessary.

(favicon) $ mkdir static

Favicon

There are any number of favicon generators available online. If you want one to use in this project, you can download it here.

Move this file into your project within the static directory so it should be static/favicon.ico.

For the final step, update our template so that we include load static at the top and then add an href for our favicon.ico file.

<!-- templates/home.html -->
{% load static %}
<!doctype html>
<html lang="en">
  <head>
    <title>Django Favicon Tutorial</title>
    <link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}"/>
  </head>
  <body>
    <h1>Homepage</h1>
  </body>
</html>

Start up the server again with python manage.py runserver and refresh the page at http://127.0.0.1:8000/.

Favicon

Boom! There’s our favicon.

If you want to compare your code with the official source code, it can be found on Github.