Django Template Inheritance
Introduction
One of Django's most powerful features is its template inheritance system. In web development, most sites share common elements across multiple pages - headers, navigation bars, footers, etc. Coding these elements repeatedly for each page would be inefficient and difficult to maintain.
Django solves this problem through template inheritance, allowing you to create a "base" template containing all the common elements of your site and define "blocks" that child templates can override. This approach follows the DRY principle (Don't Repeat Yourself), making your code cleaner, more maintainable, and easier to update.
In this tutorial, we'll explore how Django's template inheritance works and how to implement it in your projects.
Understanding Template Inheritance
Template inheritance in Django works similar to object-oriented programming inheritance:
- You create a base template (parent) that defines the common structure
- You create child templates that extend the base template
- The child templates override specific sections (blocks) of the parent template
Creating a Base Template
Let's start by creating a base template that will be used throughout our website:
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Django Website{% endblock %}</title>
<link rel="stylesheet" href="/static/css/style.css">
{% block extra_css %}{% endblock %}
</head>
<body>
<header>
<h1>My Awesome Website</h1>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/blog/">Blog</a></li>
<li><a href="/contact/">Contact</a></li>
</ul>
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2023 My Django Website</p>
</footer>
<script src="/static/js/main.js"></script>
{% block extra_js %}{% endblock %}
</body>
</html>
The key elements in this base template are the {% block %}
tags. These define sections that can be overridden by child templates. In this example, we've defined three blocks:
title
: For the page titlecontent
: For the main content of the pageextra_css
andextra_js
: For page-specific CSS and JavaScript files
Creating Child Templates
Now, let's create a child template that extends our base template:
<!-- home.html -->
{% extends "base.html" %}
{% block title %}Home | My Django Website{% endblock %}
{% block content %}
<h2>Welcome to My Django Website</h2>
<p>This is the homepage of our awesome Django project!</p>
<div class="features">
<div class="feature">
<h3>Fast Development</h3>
<p>Django makes developing web applications quick and efficient.</p>
</div>
<div class="feature">
<h3>Secure By Default</h3>
<p>Django includes security features out of the box.</p>
</div>
<div class="feature">
<h3>Scalable</h3>
<p>Django applications can scale from small projects to large websites.</p>
</div>
</div>
{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="/static/css/home.css">
{% endblock %}
This child template begins with {% extends "base.html" %}
, which tells Django that this template inherits from base.html
. Then we override three blocks: title
, content
, and extra_css
.
Using Multiple Inheritance Levels
Django supports multiple levels of template inheritance. For example, you could have:
- A site-wide
base.html
template - Section-specific templates that extend
base.html
- Page templates that extend the section templates
Let's create a blog section template:
<!-- blog/base_blog.html -->
{% extends "base.html" %}
{% block title %}Blog | My Django Website{% endblock %}
{% block content %}
<div class="blog-container">
<div class="blog-sidebar">
<h3>Categories</h3>
<ul>
<li><a href="/blog/django/">Django</a></li>
<li><a href="/blog/python/">Python</a></li>
<li><a href="/blog/html-css/">HTML/CSS</a></li>
</ul>
<h3>Recent Posts</h3>
<ul>
{% block sidebar_recent_posts %}
<li>No recent posts</li>
{% endblock %}
</ul>
</div>
<div class="blog-content">
{% block blog_content %}
{% endblock %}
</div>
</div>
{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="/static/css/blog.css">
{% endblock %}
Now, individual blog post pages can extend base_blog.html
:
<!-- blog/post_detail.html -->
{% extends "blog/base_blog.html" %}
{% block title %}{{ post.title }} | Blog | My Django Website{% endblock %}
{% block blog_content %}
<article>
<h2>{{ post.title }}</h2>
<div class="meta">
Published on {{ post.published_date }} by {{ post.author }}
</div>
<div class="content">
{{ post.content|safe }}
</div>
<div class="tags">
{% for tag in post.tags.all %}
<span class="tag">{{ tag.name }}</span>
{% endfor %}
</div>
</article>
<div class="comments">
<h3>Comments ({{ post.comments.count }})</h3>
{% for comment in post.comments.all %}
<div class="comment">
<strong>{{ comment.author }}</strong> on {{ comment.created_date }}
<p>{{ comment.text }}</p>
</div>
{% empty %}
<p>No comments yet. Be the first to comment!</p>
{% endfor %}
</div>
{% endblock %}
{% block sidebar_recent_posts %}
{% for recent_post in recent_posts %}
<li><a href="{{ recent_post.get_absolute_url }}">{{ recent_post.title }}</a></li>
{% endfor %}
{% endblock %}
Block Inheritance Techniques
Including Parent Block Content
Sometimes, you want to add to a parent block rather than completely replacing it. You can do this with the {{ block.super }}
variable:
<!-- about.html -->
{% extends "base.html" %}
{% block title %}About Us | {{ block.super }}{% endblock %}
{% block extra_css %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/about.css">
{% endblock %}
{% block content %}
<h2>About Our Company</h2>
<p>We are a team of passionate developers...</p>
{% endblock %}
In this example, {{ block.super }}
in the title
block will include the content from the parent template's title block, resulting in "About Us | My Django Website". Similarly, in the extra_css
block, we include both the parent CSS and add our page-specific CSS file.
Empty Blocks
You can define empty blocks in your base template as placeholders for optional content:
{% block sidebar %}
{% endblock %}
Child templates can choose to implement this block or ignore it.
Named Endblocks
For better readability, especially in templates with many blocks, you can name your endblock tags:
{% block content %}
<!-- lots of content here -->
{% endblock content %}
Real-World Example: Creating a Dashboard Layout
Let's create a real-world example of a dashboard with template inheritance:
First, our base dashboard template:
<!-- dashboard/base_dashboard.html -->
{% extends "base.html" %}
{% block title %}Dashboard | {{ block.super }}{% endblock %}
{% block content %}
<div class="dashboard-container">
<aside class="sidebar">
<div class="user-profile">
<img src="{{ user.profile.avatar.url }}" alt="{{ user.username }}">
<h3>{{ user.get_full_name|default:user.username }}</h3>
<p>{{ user.email }}</p>
</div>
<nav class="dashboard-nav">
<ul>
<li><a href="{% url 'dashboard:home' %}">Dashboard Home</a></li>
<li><a href="{% url 'dashboard:profile' %}">My Profile</a></li>
<li><a href="{% url 'dashboard:settings' %}">Settings</a></li>
<li><a href="{% url 'dashboard:messages' %}">Messages</a></li>
<li><a href="{% url 'dashboard:analytics' %}">Analytics</a></li>
{% block extra_nav_items %}{% endblock %}
</ul>
</nav>
</aside>
<div class="main-content">
<header class="dashboard-header">
<h2>{% block dashboard_title %}Dashboard{% endblock %}</h2>
<div class="actions">
{% block dashboard_actions %}{% endblock %}
</div>
</header>
<div class="dashboard-content">
{% block dashboard_content %}
{% endblock %}
</div>
</div>
</div>
{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="/static/css/dashboard.css">
{% block dashboard_css %}{% endblock %}
{% endblock %}
{% block extra_js %}
<script src="/static/js/dashboard.js"></script>
{% block dashboard_js %}{% endblock %}
{% endblock %}
Now let's create a specific dashboard page for user analytics:
<!-- dashboard/analytics.html -->
{% extends "dashboard/base_dashboard.html" %}
{% block dashboard_title %}User Analytics{% endblock %}
{% block dashboard_actions %}
<button class="btn btn-primary" id="export-data">Export Data</button>
<div class="date-picker">
<input type="date" id="start-date" name="start-date">
<span>to</span>
<input type="date" id="end-date" name="end-date">
<button class="btn" id="filter-date">Apply</button>
</div>
{% endblock %}
{% block dashboard_content %}
<div class="analytics-overview">
<div class="stat-card">
<h3>Total Users</h3>
<div class="stat-value">{{ user_count }}</div>
<div class="trend up">+{{ new_users_percentage }}% from last month</div>
</div>
<div class="stat-card">
<h3>Active Users</h3>
<div class="stat-value">{{ active_users_count }}</div>
<div class="trend up">+{{ active_users_percentage }}% from last month</div>
</div>
<div class="stat-card">
<h3>Average Session</h3>
<div class="stat-value">{{ avg_session_time }}</div>
<div class="trend down">-{{ session_time_change }}% from last month</div>
</div>
</div>
<div class="analytics-charts">
<div class="chart">
<h3>User Growth</h3>
<canvas id="userGrowthChart"></canvas>
</div>
<div class="chart">
<h3>User Engagement</h3>
<canvas id="engagementChart"></canvas>
</div>
</div>
<div class="data-table">
<h3>Recent User Activity</h3>
<table>
<thead>
<tr>
<th>User</th>
<th>Action</th>
<th>Date</th>
<th>Time</th>
<th>Page</th>
</tr>
</thead>
<tbody>
{% for activity in recent_activity %}
<tr>
<td>{{ activity.user.username }}</td>
<td>{{ activity.action }}</td>
<td>{{ activity.timestamp|date:"M d, Y" }}</td>
<td>{{ activity.timestamp|time:"H:i" }}</td>
<td>{{ activity.page }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5">No recent activity found</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block dashboard_css %}
<link rel="stylesheet" href="/static/css/analytics.css">
{% endblock %}
{% block dashboard_js %}
<script src="/static/js/chart.min.js"></script>
<script src="/static/js/analytics.js"></script>
{% endblock %}
Common Template Inheritance Patterns
Inclusion Tags and Partials
For reusable components that don't fit the inheritance model, Django provides the {% include %}
tag:
<!-- In any template -->
<div class="sidebar">
{% include "components/recent_posts.html" %}
{% include "components/categories.html" %}
</div>
This is useful for components that appear in multiple templates but don't always fit into a block structure.
Base Templates for Different Sections
Different sections of your site might have different layouts:
templates/
base.html # Site-wide base
pages/
base_page.html # For static pages
contact.html
about.html
blog/
base_blog.html # For blog pages
post_list.html
post_detail.html
dashboard/
base_dashboard.html # For dashboard
home.html
analytics.html
Best Practices for Template Inheritance
-
Keep templates DRY: Don't repeat common elements in multiple templates.
-
Create meaningful blocks: Name blocks clearly to indicate their purpose.
-
Use consistent block names: Use consistent block names across templates for maintainability.
-
Nest blocks appropriately: You can nest blocks inside other blocks:
{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
-
Don't overuse inheritance: For very small components, consider using
{% include %}
instead. -
Document your templates: Add comments to explain the purpose of complex blocks.
-
Be mindful of block structure: Make sure your block structure is logical and easy to understand.
Summary
Django's template inheritance is a powerful feature that allows you to:
- Create reusable base templates with common elements
- Override specific sections in child templates
- Implement multiple levels of inheritance
- Keep your templates DRY and maintainable
Template inheritance is one of Django's most useful features for frontend development. It enables you to build consistent, maintainable sites while eliminating repetitive code.
Exercises
- Create a base template with header, footer, and content blocks for a personal portfolio site.
- Extend the base template to create home, about, projects, and contact pages.
- Create a second-level template for project pages that extends the base template and includes project-specific blocks.
- Implement a blog section with its own base template that extends your site's main base template.
- Create a components directory with reusable template parts (like a newsletter signup form) and include them in your templates.
Additional Resources
- Django Documentation - Template Inheritance
- Django Template Language
- Two Scoops of Django - A great book with best practices for Django development
- Django Best Practices - More advanced tips on Django development
Happy templating!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)