Skip to content

Django - Template System

Django’s template system provides a powerful yet designer-friendly way to separate the presentation of a document (HTML) from its data (Python logic). It uses a mini-language, the Django Template Language (DTL), to embed logic and variables within HTML files.

As seen in the Views chapter, the django.shortcuts.render function is commonly used to combine a template with a context dictionary and return an HttpResponse object.

from django.shortcuts import render
import datetime
def current_datetime(request):
now = datetime.datetime.now()
context = {'current_date': now}
return render(request, 'myapp/datetime.html', context)

This function typically takes three arguments:

  • request: The HttpRequest object.
  • template_name: The path to the template file (relative to directories specified in the TEMPLATES setting in settings.py, often within an app’s templates subdirectory).
  • context: A dictionary mapping variable names (keys) to their values. These variables become accessible within the template.

DTL defines syntax for variables, tags, filters, and comments within your template files.

Variables are surrounded by double curly braces: {{ variable }}. When the template engine encounters a variable, it evaluates it using the provided context and replaces the variable tag with the result.

Example: myapp/templates/myapp/datetime.html using the context from the view above:

myapp/templates/myapp/datetime.html
<!DOCTYPE html>
<html>
<head><title>Current Time</title></head>
<body>
<p>The current date and time is: {{ current_date }}</p>
</body>
</html>

Output might look like: The current date and time is: Sept. 11, 2023, 4:01 p.m. (Django automatically formats datetime objects).

Dot Lookup: You can access attributes of variables using dot (.) notation, similar to Python. Django tries dictionary lookup, attribute lookup, and list-index lookup in that order.

Example: If current_date is a datetime object, {{ current_date.year }} would output the year.

Filters modify variables for display. They are applied using a pipe (|) character.

Common Examples:

  • {{ user_bio|truncatewords:30 }}: Truncates the string to the first 30 words.
  • {{ page_title|lower }}: Converts the string to lowercase.
  • {{ item_list|length }}: Returns the length of the list.
  • {{ article.publication_date|date:"Y-m-d" }}: Formats a date object (using PHP date format specifiers).
  • {{ raw_html|safe }}: Marks a string as safe, preventing auto-escaping (use with caution!).
  • {{ value|default:"N/A" }}: Provides a default value if value is False or empty.

Filters can be chained: {{ my_text|escape|linebreaks }}.

Find more built-in filters: Django Built-in Filter Reference

Tags provide logic within templates, such as loops, conditionals, template inheritance, loading external resources, and more. They are surrounded by {% and %}.

{% if %}, {% elif %}, {% else %}, {% endif %}

Section titled “{% if %}, {% elif %}, {% else %}, {% endif %}”

Performs conditional logic.

{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}!</p>
{% elif user.is_guest %}
<p>Welcome, Guest!</p>
{% else %}
<p><a href="{% url 'login' %}">Log in</a></p>
{% endif %}

Loops over items in a sequence (like a list or queryset). The optional {% empty %} block is rendered if the sequence is empty.

<ul>
{% for item in item_list %}
<li>{{ forloop.counter }}: {{ item.name }}</li>
{% empty %}
<li>No items available.</li>
{% endfor %}
</ul>

The forloop variable provides information about the loop’s state (e.g., forloop.counter, forloop.first, forloop.last).

{% extends %} and {% block %} (Template Inheritance)

Section titled “{% extends %} and {% block %} (Template Inheritance)”

This powerful feature allows you to create a base template skeleton containing common site elements, and child templates that override specific parts.

Base Template (myapp/templates/myapp/base.html):

myapp/templates/myapp/base.html
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
<!-- Common CSS/JS -->
</head>
<body>
<header>Site Header</header>
<main>
{% block content %}
<!-- Default content goes here -->
{% endblock %}
</main>
<footer>Site Footer</footer>
</body>
</html>

Child Template (myapp/templates/myapp/specific_page.html):

myapp/templates/myapp/specific_page.html
{% extends "myapp/base.html" %}
{% block title %}Specific Page Title{% endblock %}
{% block content %}
<h2>Welcome to the Specific Page</h2>
<p>This content overrides the base template's content block.</p>
{% endblock %}

The {% extends %} tag must be the first tag in the child template. It specifies the parent template. {% block %} tags define areas that child templates can override.

Generates URLs based on the names defined in your urls.py. This avoids hardcoding URLs, making your application more maintainable.

<a href="{% url 'article-detail' article.id %}">Read More</a>
<form action="{% url 'search' %}" method="get">

Loads custom template tags and filters.

{% load static %}
{% load humanize %}
<img src="{% static 'images/logo.png' %}" alt="Logo">
<p>Value: {{ large_number|intcomma }}</p>

Generates the URL for static files (CSS, JavaScript, images) based on your STATIC_URL setting.

Single-line comments: {# This is a template comment #} Multi-line comments: {% comment %} ... comment text ... {% endcomment %} These comments are not included in the final HTML output.

Further Reading: Django Template Language Documentation