Django Templates That Don’t Make You Want to Cry

Templates are where Django developers either fall in love with the framework or start pulling their hair out. I’ve seen beautiful applications ruined by messy templates, and I’ve seen average applications elevated by thoughtful template design.

The difference isn’t just about making things look pretty – it’s about creating maintainable, reusable code that other developers (including future you) can actually work with. Let me show you the template patterns that have saved my sanity on countless projects.

Template Inheritance – Your Best Friend

Template inheritance is like CSS for your HTML structure. Get it right once, and every page benefits. Get it wrong, and you’ll be copying and pasting code until you hate yourself.

Here’s the base template that I use for almost every Django project:





    
    
    
    
    {% block title %}Bookstore{% endblock %} | Django Books
    
    
    
    
    
    
    
    
    {% block extra_css %}{% endblock %}


    
    

    
    {% if messages %}
    
{% for message in messages %} {% endfor %}
{% endif %}
{% block content %} {% endblock %}
Django BookStore

Your friendly neighborhood bookstore, now online!

© 2022 BookStore. Built with Django and love.

{% block extra_js %}{% endblock %}

Building Beautiful List Pages

Now let’s create a book listing page that actually looks professional:


{% extends 'base.html' %}
{% load static %}

{% block title %}
    {% if current_category %}{{ current_category }} Books{% else %}All Books{% endif %}
{% endblock %}

{% block meta_description %}
    Browse our collection of {% if current_category %}{{ current_category|lower }} {% endif %}books with great prices and fast shipping.
{% endblock %}

{% block content %}
Filters
Categories
Sort By
{% if search_query %}
Showing results for "{{ search_query }}" ({{ books|length }} book{{ books|length|pluralize }} found) Clear search
{% endif %}
{% for book in books %}
{% if book.featured %} Featured {% endif %}
{{ book.title|truncatechars:50 }}

by {% for author in book.authors.all %} {{ author.full_name }}{% if not forloop.last %}, {% endif %} {% endfor %}

{{ book.category.name }}
£{{ book.price }}

{% if book.is_in_stock %} In Stock {% else %} Out of Stock {% endif %}
View Details {% if book.is_in_stock %} {% endif %}
{% empty %}

No books found

{% if search_query %}

Try adjusting your search terms or browse all books.

{% else %}

No books are available in this category yet.

{% endif %}
{% endfor %}
{% if is_paginated %} {% endif %}
{% endblock %} {% block extra_js %} {% endblock %}

Creating Detailed Product Pages

The book detail page is where customers make buying decisions. It needs to be informative and persuasive:


{% extends 'base.html' %}
{% load static %}

{% block title %}{{ book.title }}{% endblock %}

{% block meta_description %}
    {{ book.title }} by {% for author in book.authors.all %}{{ author.full_name }}{% if not forloop.last %}, {% endif %}{% endfor %}. {{ book.description|truncatechars:150 }}
{% endblock %}

{% block content %}


{% if book.featured %}
Featured Book
{% endif %}

{{ book.title }}

{% if book.subtitle %}

{{ book.subtitle }}

{% endif %}

by {% for author in book.authors.all %} {{ author.full_name }}{% if not forloop.last %}, {% endif %} {% endfor %}

{% if average_rating > 0 %}
{% for i in "12345" %} {% if forloop.counter <= average_rating %} {% else %} {% endif %} {% endfor %}
({{ average_rating }}/5 from {{ reviews.count }} review{{ reviews.count|pluralize }})
{% endif %}
Category: {{ book.category.name }}
Publisher: {{ book.publisher }}
Publication Date: {{ book.publication_date|date:"F j, Y" }}
Pages: {{ book.pages }}
ISBN: {{ book.isbn_13 }}
£{{ book.price }}
{% if book.is_in_stock %} In Stock ({{ book.stock_quantity }} available) {% else %} Out of Stock {% endif %}
{% if book.is_in_stock %}
{% else %} {% endif %}
Free shipping on orders over £25
{{ book.description|linebreaks }}
{% if reviews %} {% for review in reviews %}
{{ review.title }}
{% for i in "12345" %} {% if forloop.counter <= review.rating %} {% else %} {% endif %} {% endfor %}
{{ review.created_at|date:"M j, Y" }}

{{ review.review_text }}

by {{ review.reviewer_name }}
{% endfor %} {% else %}

No reviews yet. Be the first to review this book!

{% endif %}
{% if related_books %}

You might also like

{% for related_book in related_books %} {% endfor %}
{% endif %} {% endblock %}

Custom Template Tags and Filters

Sometimes you need functionality that Django’s built-in tags don’t provide. Custom template tags are your secret weapon:

# inventory/templatetags/book_extras.py
from django import template
from django.utils.safestring import mark_safe
from ..models import Book, Category

register = template.Library()

@register.filter
def currency(value):
    """Format a number as currency"""
    try:
        return f"£{float(value):.2f}"
    except (ValueError, TypeError):
        return value

@register.filter
def star_rating(rating):
    """Convert a numeric rating to star icons"""
    if not rating:
        return ""
    
    full_stars = int(rating)
    empty_stars = 5 - full_stars
    
    stars_html = ""
    for i in range(full_stars):
        stars_html += ''
    for i in range(empty_stars):
        stars_html += ''
    
    return mark_safe(stars_html)

@register.simple_tag
def book_count_by_category(category):
    """Return the number of available books in a category"""
    return Book.objects.filter(category=category, is_available=True).count()

@register.inclusion_tag('inventory/partials/book_card.html')
def book_card(book, show_category=True):
    """Render a book card component"""
    return {
        'book': book,
        'show_category': show_category
    }

Create a reusable book card partial:


{{ book.title|truncatechars:50 }}

by {% for author in book.authors.all %} {{ author.full_name }}{% if not forloop.last %}, {% endif %} {% endfor %}

{% if show_category %}

{{ book.category.name }}

{% endif %}
{{ book.price|currency }} {% if book.is_in_stock %} In Stock {% else %} Out of Stock {% endif %}

Now you can use it anywhere:

{% load book_extras %}

{% for book in featured_books %}
{% book_card book %}
{% endfor %}

Making Templates Mobile-Friendly

Responsive design isn’t optional anymore. Here’s how I handle mobile-first templates:


Performance Tips for Templates

Templates can be performance bottlenecks if you’re not careful. Here are my go-to optimization techniques:


{% for book in books %}
    
    

by {% for author in book.authors.all %}{{ author.full_name }}{% endfor %}

Category: {{ book.category.name }}

{% endfor %} {% load cache %} {% cache 3600 book_sidebar %} {% endcache %}

Common Template Mistakes to Avoid

After reviewing hundreds of Django templates, these are the mistakes I see most often:

1. Putting Logic in Templates


{% if book.price > 20 and book.stock_quantity > 5 and book.category.name == "Fiction" %}
    Premium Fiction
{% endif %}


{% if book.is_premium_fiction %}
    Premium Fiction
{% endif %}

2. Not Using Template Inheritance





{% extends 'base.html' %}
{% block content %}
    
{% endblock %}

3. Hardcoding URLs


View Book


View Book

What Makes Templates Maintainable

Great templates follow these principles:

  • Single Responsibility – Each template has one clear purpose
  • DRY Principle – Use includes and template tags to avoid repetition
  • Semantic HTML – Use proper HTML5 elements and structure
  • Progressive Enhancement – Work without JavaScript, better with it
  • Accessibility – Proper ARIA labels, alt text, and keyboard navigation

The Final Piece of the Puzzle

Templates are where your Django application meets your users. They’re not just about making things look pretty – they’re about creating intuitive, accessible experiences that work across devices and browsers.

The templates we built today include responsive design, proper semantics, and reusable components. They’re ready for real-world use and can handle the complexity of modern web applications.

In my final article in this series, we’ll explore Django’s admin interface and how to customize it for content management. I’ll show you how to turn the basic admin into a powerful tool that non-technical users actually want to use.

Remember: templates are code too. Treat them with the same care and attention you give to your Python code, and your future self will thank you.

Author

  • Mohammad Golam Dostogir, Software Engineer specializing in Python, Django, and AI solutions. Active contributor to open-source projects and tech communities, with experience delivering applications for global companies.
    GitHub

    View all posts
Index