Skip to main content

Django Template Includes

When building websites with Django, you'll often need to reuse the same HTML components across multiple pages. For example, navigation bars, footers, and sidebars typically appear on many pages. Copying and pasting the same code across different templates leads to duplication and maintenance headaches. This is where Django's template includes feature comes to the rescue.

What are Template Includes?

Template includes are a powerful Django feature that allows you to insert one template into another. Think of them as reusable components that you can define once and use across your entire website. They help you follow the DRY principle (Don't Repeat Yourself) in your template code.

Basic Syntax

The syntax for including a template within another template is straightforward:

django
{% include "template_name.html" %}

This tag tells Django to replace the line with the contents of the specified template.

Getting Started with Includes

Let's start with a simple example to understand how includes work.

Step 1: Create a Reusable Template Component

First, create a template fragment that you want to reuse. For example, let's create a navigation bar component.

Create a file named navbar.html in your templates directory:

html
<!-- templates/navbar.html -->
<nav class="navbar">
<div class="navbar-brand">
<a href="{% url 'home' %}">My Website</a>
</div>
<div class="navbar-menu">
<a href="{% url 'home' %}">Home</a>
<a href="{% url 'about' %}">About</a>
<a href="{% url 'contact' %}">Contact</a>
</div>
</nav>

Step 2: Include the Component in a Template

Now, you can include this navbar in any template:

html
<!-- templates/home.html -->
<!DOCTYPE html>
<html>
<head>
<title>Home Page</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
{% include "navbar.html" %}

<div class="content">
<h1>Welcome to My Website!</h1>
<p>This is the home page content.</p>
</div>

<footer>
<p>&copy; 2023 My Website</p>
</footer>
</body>
</html>

When Django renders home.html, it will replace {% include "navbar.html" %} with the contents of the navbar.html file.

Passing Variables to Included Templates

One of the powerful features of includes is that they have access to the context of the template that includes them. Additionally, you can pass specific variables to an included template.

Using Context Variables

Any variable available in the parent template is automatically available in the included template:

html
<!-- templates/base.html -->
{% block content %}
{% include "user_profile.html" %}
{% endblock %}

If user is available in the context when rendering base.html, it will also be available in user_profile.html.

Passing Specific Variables

You can pass specific variables to an included template using the with keyword:

django
{% include "user_card.html" with username=user.username avatar=user.profile.avatar %}

Let's see a more complete example:

Parent template:

html
<!-- templates/profiles.html -->
<div class="user-list">
{% for user in users %}
{% include "user_card.html" with username=user.username email=user.email is_admin=user.is_staff %}
{% endfor %}
</div>

Included template:

html
<!-- templates/user_card.html -->
<div class="user-card">
<h3>{{ username }}</h3>
<p>Email: {{ email }}</p>
{% if is_admin %}
<span class="admin-badge">Admin</span>
{% endif %}
</div>

Using only to Restrict Context

Sometimes, you might want to restrict the included template to only access the variables you explicitly pass to it. You can do this with the only keyword:

django
{% include "user_card.html" with username=user.username only %}

This ensures that user_card.html can only access the username variable and not any other variables from the parent template's context.

Practical Example: Building a Blog with Reusable Components

Let's build a simple blog layout using includes for common components.

Step 1: Create the Common Components

First, let's create our reusable components:

Header (templates/components/header.html):

html
<!-- templates/components/header.html -->
<header>
<div class="logo">
<a href="{% url 'home' %}">My Blog</a>
</div>
<nav>
<ul>
<li><a href="{% url 'home' %}">Home</a></li>
<li><a href="{% url 'blog' %}">Articles</a></li>
<li><a href="{% url 'about' %}">About</a></li>
</ul>
</nav>
</header>

Footer (templates/components/footer.html):

html
<!-- templates/components/footer.html -->
<footer>
<div class="footer-content">
<div class="social-links">
<a href="https://twitter.com/myblog"><i class="fab fa-twitter"></i></a>
<a href="https://facebook.com/myblog"><i class="fab fa-facebook"></i></a>
<a href="https://instagram.com/myblog"><i class="fab fa-instagram"></i></a>
</div>
<p>&copy; {% now "Y" %} My Blog. All rights reserved.</p>
</div>
</footer>

Article card (templates/components/article_card.html):

html
<!-- templates/components/article_card.html -->
<div class="article-card">
<div class="article-image">
{% if article.image %}
<img src="{{ article.image.url }}" alt="{{ article.title }}">
{% else %}
<img src="{% static 'images/default_article.jpg' %}" alt="Default Article Image">
{% endif %}
</div>
<div class="article-content">
<h3><a href="{% url 'article_detail' article.slug %}">{{ article.title }}</a></h3>
<div class="article-meta">
<span class="author">By {{ article.author.username }}</span>
<span class="date">{{ article.published_date|date:"F j, Y" }}</span>
</div>
<p class="excerpt">{{ article.excerpt|truncatewords:25 }}</p>
<a href="{% url 'article_detail' article.slug %}" class="read-more">Read more</a>
</div>
</div>

Step 2: Create the Base Template

Now, create a base template that uses these components:

html
<!-- templates/base.html -->
<!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 Blog{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
{% block extra_css %}{% endblock %}
</head>
<body>
{% include "components/header.html" %}

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

{% include "components/footer.html" %}

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

Step 3: Create the Blog Index Page

Finally, create a blog index page that uses the base template and includes article cards:

html
<!-- templates/blog/index.html -->
{% extends "base.html" %}

{% block title %}Blog Articles | My Blog{% endblock %}

{% block content %}
<div class="page-header">
<h1>Latest Articles</h1>
</div>

<div class="article-grid">
{% for article in articles %}
{% include "components/article_card.html" with article=article %}
{% empty %}
<p class="no-articles">No articles have been published yet.</p>
{% endfor %}
</div>

<div class="pagination">
{% if articles.has_previous %}
<a href="?page={{ articles.previous_page_number }}" class="prev">&laquo; Previous</a>
{% endif %}

<span class="current">
Page {{ articles.number }} of {{ articles.paginator.num_pages }}
</span>

{% if articles.has_next %}
<a href="?page={{ articles.next_page_number }}" class="next">Next &raquo;</a>
{% endif %}
</div>
{% endblock %}

Best Practices for Using Template Includes

To make the most of Django template includes, follow these best practices:

  1. Organize includes in subfolders: Store your include templates in a designated subfolder like components/, partials/, or includes/ to keep your templates directory organized.

  2. Keep includes focused: Each include should have a single responsibility. For example, a navigation component should only handle navigation.

  3. Use descriptive names: Name your include templates clearly to indicate their purpose, like navbar.html, footer.html, or product_card.html.

  4. Comment your includes: Add comments in your main templates to help other developers understand why you're including certain components.

  5. Pass only necessary variables: When using with, only pass the variables that the included template needs.

  6. Consider using the only parameter: Use only when you want to ensure the included template only sees the variables you explicitly pass to it.

Debugging Template Includes

If you're having issues with template includes, here are some common problems and solutions:

  1. Template Not Found: If Django can't find your included template, make sure the path is correct. Remember that Django searches for templates in all the directories listed in your TEMPLATES setting.

  2. Variables Not Available: If variables aren't available in your included template, check if you're using only or if the variable is defined in the context.

  3. Recursive Includes: Be careful not to create infinite loops by having templates that include each other. Django has a limit to prevent this, but it's better to avoid the situation.

Summary

Django template includes are a powerful way to reuse HTML components across your website. They help you:

  • Maintain consistent UI elements across your site
  • Reduce code duplication
  • Improve maintainability by centralizing common components
  • Make your templates more modular and easier to understand

By breaking your templates into reusable components, you can create more maintainable, DRY code that's easier to update and extend.

Additional Resources and Exercises

Resources

Exercises

  1. Create a Site-wide Alert System: Build a reusable alert component that can display different types of messages (success, error, warning) and include it in your base template.

  2. Build a Sidebar Widget System: Create multiple sidebar widget templates (recent posts, categories, tags) and include them dynamically in your sidebar.

  3. Create a Comment System: Build a comment form and comment list as separate includes, then use them on article detail pages.

  4. Build a Modal Component: Create a reusable modal dialog component that can be included with different content in various templates.

  5. Create a Form Component: Build a reusable form include that can render any Django form with consistent styling and error handling.

By mastering template includes, you'll take a big step toward writing cleaner, more maintainable Django templates.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)