Django Templates, Blocks, and Inheritance Made Simple

Django’s template system gets powerful the moment you stop repeating page markup. With template inheritance, a site-wide layout can live in one place while each page fills in only the parts that differ. This guide shows how blocks work, how to structure base templates, and how to avoid the common mistakes that make templates messy.

1 base Keep shared HTML in one layout template.
Named blocks Let child templates replace only what they need.
Less duplication Update navigation, footer, and metadata once.

Why template inheritance matters

A lot of beginners start by creating each page as a separate HTML file with its own <head>, navigation bar, footer, and styles. That works for two pages. It becomes a headache at ten.

The moment your app has a homepage, dashboard, blog list, contact page, and account pages, repeated markup turns into a maintenance problem. Change the navigation once, and suddenly you have to update five different files.

Template inheritance solves this by giving you one parent layout and multiple child templates that fill named regions called blocks.

In practice, that means your app becomes easier to scale, easier to restyle, and much easier to reason about.

The core idea

Django templates use two key template tags for inheritance:

  • {% extends "base.html" %} tells a template to inherit from a parent.
  • {% block content %}{% endblock %} defines a replaceable section.

The parent template declares the structure. The child template replaces one or more named blocks.

{# parent template #}
<main>
  {% block content %}{% endblock %}
</main>

{# child template #}
{% extends "base.html" %}

{% block content %}
  <h1>Hello from a child template</h1>
{% endblock %}

Once this clicks, Django templates stop feeling repetitive and start feeling composable.

Building a base template

Your base template should contain the HTML skeleton shared by most pages:

  • document structure
  • site header and navigation
  • footer
  • global CSS and JS links
  • named blocks for page-specific content
<!-- templates/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{% block title %}My Django Site{% endblock %}</title>
  <link rel="stylesheet" href="{% static 'css/site.css' %}">
  {% block extra_head %}{% endblock %}
</head>
<body>
  <header>
    <nav>
      <a href="/">Home</a>
      <a href="/articles/">Articles</a>
      <a href="/about/">About</a>
    </nav>
  </header>

  <main class="container">
    {% block content %}{% endblock %}
  </main>

  <footer>
    <p>&copy; 2026 My Django Site</p>
  </footer>

  <script src="{% static 'js/site.js' %}"></script>
  {% block extra_scripts %}{% endblock %}
</body>
</html>

This base layout defines four useful blocks:

title

Lets each page set its own browser tab title.

extra_head

Good for page-specific meta tags, styles, or preload hints.

content

The main body of the page.

extra_scripts

Lets a page load only the JavaScript it actually needs.

Creating child templates

A child template starts with extends, then overrides the blocks it needs. It does not repeat the entire page structure.

<!-- templates/pages/home.html -->
{% extends "base.html" %}

{% block title %}Home | My Django Site{% endblock %}

{% block content %}
  <section class="hero">
    <h1>Welcome to the site</h1>
    <p>This page uses the shared layout from base.html.</p>
  </section>
{% endblock %}

Another child template can reuse the same parent while rendering completely different content:

<!-- templates/pages/about.html -->
{% extends "base.html" %}

{% block title %}About | My Django Site{% endblock %}

{% block content %}
  <h1>About us</h1>
  <p>We build clean Django apps with reusable templates.</p>
{% endblock %}
That is the key payoff: one shared layout, many focused pages.

Includes and partials

Inheritance handles full-page structure. Includes handle smaller reusable pieces. Think of them as partial templates for components like alerts, navbars, cards, or pagination.

<!-- templates/includes/alert.html -->
<div class="alert alert-{{ level|default:'info' }}">
  {{ message }}
</div>
<!-- inside another template -->
{% include "includes/alert.html" with level="success" message="Profile updated." %}

Use include for small reusable fragments. Use extends for page-level structure. Keeping those roles separate helps templates stay clear.

Useful block patterns

You do not need dozens of blocks. A few well-chosen ones usually cover most real projects.

  1. Page title block. Make every page set a specific title for better usability and SEO.
  2. Main content block. This is the most important block and should exist in nearly every base template.
  3. Head extension block. Useful for per-page metadata or canonical links.
  4. Script block. Keeps page-specific JavaScript from loading site-wide.

For more complex apps, you can even use nested inheritance. For example, a dashboard section could inherit from base.html, and then dashboard subpages could inherit from dashboard_base.html.

<!-- templates/dashboard/dashboard_base.html -->
{% extends "base.html" %}

{% block content %}
  <div class="dashboard-layout">
    <aside>Sidebar</aside>
    <section>
      {% block dashboard_content %}{% endblock %}
    </section>
  </div>
{% endblock %}
<!-- templates/dashboard/reports.html -->
{% extends "dashboard/dashboard_base.html" %}

{% block title %}Reports | Dashboard{% endblock %}

{% block dashboard_content %}
  <h1>Reports</h1>
  <p>Metrics and summaries go here.</p>
{% endblock %}

This gives larger sections of your app their own reusable internal layout without abandoning the global site shell.

Common mistakes

Forgetting extends at the top

The extends tag should be the first template tag in the file. If it is buried lower, you can get confusing results.

Too many tiny blocks

Overengineering your layout with excessive blocks makes templates harder to follow. Start simple.

Repeating shared markup in child templates

If the navbar or footer keeps reappearing in page files, the base template is not doing enough.

Using includes instead of inheritance

Includes are great for fragments, but they are not a substitute for a true page layout.

Suggested folder structure

A clean template directory makes inheritance easier to manage, especially once your project grows beyond a few pages.

templates/
├── base.html
├── includes/
│   ├── alert.html
│   ├── navbar.html
│   └── pagination.html
├── pages/
│   ├── home.html
│   ├── about.html
│   └── contact.html
└── dashboard/
    ├── dashboard_base.html
    ├── overview.html
    └── reports.html

This structure makes it obvious what is global, what is a reusable partial, and what belongs to a specific section.