13.6 Partial Templates vs Blocks: When to Use Each
Right, let’s settle this. You’ve hit that point where you’re copying and pasting the same chunk of HTML across ten templates and the mere thought of changing it in all ten places makes you want to become a beekeeper instead. Django offers you two primary escape routes: {% include %} with partial templates, and {% block %} with template inheritance. They seem similar on the surface, but using the wrong one for the job is like using a screwdriver to hammer a nail—it might eventually work, but you’re gonna have a bad time and leave some ugly dents.
The core difference is one of direction. Think of template inheritance ({% block %}) as a parent speaking to a child: “Here is the entire structure of the page. You may change these specific parts I’ve defined, but the overall frame is mine.” Think of includes ({% include %}) as a peer-to-peer conversation: “I am building my page and I will pull in your complete content right at this spot.”
The Case for Blocks (Template Inheritance)
You use blocks when you have a dominant, overarching layout. This is your base.html file. It defines the <!DOCTYPE html>, the <head>, the primary CSS and JS includes, the main <body> tag, the overall <header>, <main>, and <footer> structure. It’s the skeleton. The {% block %} tags are the places where child templates can inject their own specific content without having to redeclare the entire skeleton.
Your base.html might look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}My Awesome Site{% endblock %}</title>
</head>
<body>
<header>{% include "includes/header.html" %}</header>
<main>
{% block content %}
<!-- Default content can go here, or it can be empty -->
{% endblock %}
</main>
<footer>{% include "includes/footer.html" %}</footer>
{% block extra_js %}
<!-- A place for child templates to add page-specific JS -->
{% endblock %}
</body>
</html>
A child template, say blog_detail.html, then extends it and fills the blocks:
{% extends "base.html" %}
{% block title %}{{ post.title }} | My Awesome Site{% endblock %}
{% block content %}
<article>
<h1>{{ post.title }}</h1>
<div>{{ post.body }}</div>
</article>
{% endblock %}
{% block extra_js %}
<script src="{% static 'js/blog_comments.js' %}"></script>
{% endblock %}
Why this rules: The hierarchy is crystal clear. The base template has absolute control over the global structure. You change your site’s footer in one place (base.html), and it changes everywhere. The extra_js block is a classic best practice—it lets you keep your JS includes at the bottom of the body for performance, while allowing specific pages to opt-in to what they need.
The Case for Includes (Partial Templates)
You use includes for reusable components within that overarching layout. These are the Lego bricks. A navigation bar. A sidebar widget. A user profile card. A comment form. These are snippets of HTML that are useful in multiple places, potentially across different parent layouts or even within different blocks.
Your includes/user_card.html might be a simple component:
<div class="user-card">
<img src="{{ user.avatar_url }}" alt="{{ user.username }}">
<h3>{{ user.username }}</h3>
<p>Member since: {{ user.date_joined }}</p>
</div>
And you’d include it wherever it’s needed, passing the necessary context:
<!-- Inside a blog post template -->
<aside>
<h4>About the Author</h4>
{% include "includes/user_card.html" with user=post.author %}
</aside>
<!-- Inside a comments section -->
<div class="comment">
<p>{{ comment.text }}</p>
{% include "includes/user_card.html" with user=comment.user %}
</div>
Why this rules: It keeps your templates DRY (Don’t Repeat Yourself) at a modular level. You can change the design of the user card in one file, and it updates everywhere it’s included. It makes your templates more readable by abstracting away complex components into separate, focused files.
The Pitfalls and The “Aha!” Moment
The most common rookie mistake is trying to use an {% include %} where a {% block %} is needed. If you find yourself creating a base.html that’s mostly empty just so you can {% include %} a header, main content, and footer… you’re doing inheritance wrong. You’ve just recreated a clunkier, more fragile version of {% extends %}.
The “Aha!” moment comes when you realize they are best friends, not rivals. A well-structured Django project uses them together. Your base.html uses {% block %} to define the major sections and uses {% include %} to pull in common components like the header and footer. Then, your child templates {% extends "base.html" %} and fill the blocks, and can also use {% include %} to pull in their own components.
The Golden Rule: Use {% block %} for defining replaceable sections within a layout hierarchy. Use {% include %} for inserting self-contained components into a template. Master this distinction, and your templates will become a joy to work with, not a tangled mess you swear at.