How to create a base template for your Django project

Django templates store the HTML for your projects. Django uses its own templating language to allow you to add data from the back-end into your pages.

Each page of your app will have its own template file but many pages will share some elements like the header and footer. Instead of repeating your HTML in several places, which is bad practice, we can create a base template that each page can reuse.

In this tutorial, we are going to go through how to create a base template base.html, which templates across all apps can use.

If you're just looking for an example to copy, you can jump straight to the code.

The base.html template produces the layout as shown in the screenshot alone. The header and footer have been copied from Bootstrap's examples but can be adapted for any project.

A screenshot of a page with a header and footer. Only page content is a h1 tag with the text "Page Content". Intended to give an example of a base template.

What should base.html contain?

Your base template will be loaded before loading the content of templates that use it. Your base template should do the following things:

  1. Load the CSS your page needs

  2. Include a placeholder for page content

  3. Load the JavaScript your page needs

  4. Define the page layout (e.g. header and footer)

1. Load CSS in a Template

Your <head> tag should include a link to the stylesheets your page is going to use.

If you want to get started quickly, I recommend adding Bootstrap to your base template via a CDN. This means you can style your pages without having to write your own CSS.

For my personal projects, I usually load both Bootstrap and my own stylesheet.

How to add Bootstrap to a Django Template

The quickest way to add Bootstrap to your template is to use a Content Delivery Network (CDN). This means you just have to supply the URL of the asset instead of storing a copy of the Bootstrap stylesheet.

The following snippet gives an example of how Bootstrap has been added to a template. I recommend you check the Bootstrap website to get the URL for the latest version.

# base.html

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Basic Blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <link rel="stylesheet" href="{% static 'css/styles.css' %}" rel="stylesheet">
</head>

If you are also including your own CSS file, make sure it is linked after the Bootstrap stylesheet. If one of your CSS class names matches one of Bootstrap's class names, your CSS will take priority.

Include JavaScript

For Bootstrap to work properly, make sure your template also loads the Bootstrap JavaScript file at the bottom of the template.

Bootstrap uses both Vanilla JavaScript and a package called Popper.js. The snippet below includes both, but Bootstrap allows you to add them separately if you wish.

{% block javascript %}
<scr?pt src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
    crossorigin="anonymous"></scr?pt>
{% endblock %}

If you copy/paste this, be aware there are deliberate typos in the script tags. Script tags in plain text can be interpreted as a XSS attack.

To link your own stylesheet, you will need to place your CSS file in a directory called static. In base.html, make sure you include {% load static %} on Line 1 so that the template can access the files in the static directory.

For full instructions, see my tutorial on adding CSS to a Django project. This includes instructions on how to update your project settings so that Django can locate your static files.

2. Include a placeholder for page content

A base template is never used on its own. Instead, other templates will include HTML that is specific to that page.

Use a content block to create a placeholder. Any HTML on a given template will be rendered inside this block.

<body class="container">

    {% block content %}
    {% endblock %}

</body>

I like to put my content block inside a body that uses Bootstrap’s container class. This will automatically centre the content and apply a sensible maximum width for all devices.

3. Load the JavaScript your page needs

Django template language includes a block for adding JavaScript.

In the example below, I’ve just included the JavaScript for Bootstrap using their CDN. If you want to include your own JavaScript files, then your .js files should be placed inside the static directory. The process is the same for adding your own CSS: you must include {% load static %} at the top of your file.

{% block javascript %}
<scr?pt src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
    crossorigin="anonymous"></scr?pt>
{% endblock %}

4. Add the Page Layout

The base template should include the header and footer.

To get started quickly, I recommend using examples from the Bootstrap website.

Header

I've copied and pasted this from Bootstrap.

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Basic Blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <link rel="stylesheet" href="{% static 'css/styles.css' %}" rel="stylesheet">
</head>

Footer

<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
    <p class="col-md-4 mb-0 text-muted">© 2022 Company, Inc</p>

    <a href="/"
        class="col-md-4 d-flex align-items-center justify-content-center mb-3 mb-md-0 me-md-auto link-dark text-decoration-none">
        <svg class="bi me-2" width="40" height="32">
            <use xlink:href="#bootstrap"></use>
        </svg>
    </a>

    <ul class="nav col-md-4 justify-content-end">
        <li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Home</a></li>
        <li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Features</a></li>
        <li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Pricing</a></li>
        <li class="nav-item"><a href="#" class="nav-link px-2 text-muted">FAQs</a></li>
        <li class="nav-item"><a href="#" class="nav-link px-2 text-muted">About</a></li>
    </ul>
</footer>

How to import base.html into your templates

Inside any templates where you want to use your base template, include {% extends "base.html" %}

If you’re working on a template in a different app, then you will need to include the app name that contains the base template. e.g. {% extends "blog/base.html" %}

Make sure your template includes {% block content %} and {% endblock %}. Only content between those two tags will be displayed.

Example (index.html)

{% extends "base.html" %}

{% block content %}
<h1>Posts</h1>

<div class="row row-cols-1 row-cols-md-3 g-4 mt-4">

    {% for post in posts %}

    <div class="card col-4 m-2" style="width: 18rem;">
        <img src="https://tinyurl.com/22jvzvfj" class="card-img-top" alt={{post.title}}>
        <div class="card-body">
            <h5 class="card-title">{{post.title}}</h5>
            <p class="card-text text-muted">{{post.excerpt}}</p>
        </div>
    </div>

    {% endfor %}
</div>

{% endblock %}

Troubleshooting

Invalid Template Name

Solution:

Wrap the template path in quotations:

{% extends "base.html" %}

Page content is not displayed

Both base.html and your template must include a content block.

Base

{% block content %}
{% endblock %}

There should not be any code between {% block content %} and {% endblock %}

Template

Your template should have all of its HTML inside the content block. For example:

{% extends "base.html" %}

{% block content %}
<h1>Posts</h1>
{% endblock %}

Template isn’t loading custom CSS

First, check that you’re using template tags to load the file. The path css/styles.css is the path inside the static folder, not the absolute file path.

<link rel="stylesheet" href="{% static 'css/styles.css' %}" rel="stylesheet">

Next, check the location of your static folder.

Remember, your static folder can go anywhere you want but you must update settings.py so Django knows where to look. See my tutorial on how to add CSS to a Django project, which goes through how to update your settings.

Full Example

gist.github.com/ctrlz-blog/23b68f8ccd20c06b..

Conclusion

A base template will keep your code DRY (Don’t Repeat Yourself). It stores mark up that will be reused by multiple templates such as headers and footers. It is also where you should load your custom CSS and JavaScript, or load 3rd party packages such as Bootstrap.

The most important part of a base template is to include the {% block content %} and {% endblock %} tags, which create the placeholder for content to be inserted from other templates.

Other templates can use your base template by including {% extends base.html %} at the top of the template and putting your page content between the {% block content %} and {% endblock %} tags.