Django templates are enhanced HTML files processed by a server-side templating engine. The framework includes two built-in engines: Django Template Language (DTL) and Jinja2. The following material focuses on DTL, which is well-suited for monolithic applications, rapid prototyping, and content-driven sites.
Configuring Template Directories
Register template search paths in settings.py before rendering any files. The TEMPLATES setting controls this behavior.
For project-wide templates, create a root-level templates folder and reference it in DIRS:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Setting APP_DIRS to True instructs Django to scan a templates subdirectory inside every installed application.
Global Templates
Create templates/home.html under the project root:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>Welcome to the homepage</h1>
</body>
</html>
Wire a URL to a view in urls.py:
from django.urls import path
from pages.views import home_page
urlpatterns = [
path('', home_page, name='home'),
]
Then return the template from the view:
from django.shortcuts import render
def home_page(request):
return render(request, 'home.html')
render() resolves home.html by searching the directories listed in DIRS.
Application-Level Templates
To isolate templates within a specific app, create pages/templates/pages/dashboard.html. Placing files inside an app-specific subdirectory prevents name collisions when multiple apps define templates with identical filenames.
Ensure the application is registered:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pages',
]
With APP_DIRS = True, Django automatically discovers templates stored in each registered app’s templates folder.
Template Syntax
DTL inserts dynamic content using double braces for variables and brace-percent pairs for logic constructs.
Variables
Pass data from the view via a context dictionary:
def home_page(request):
heading = 'Hello from Django'
return render(request, 'home.html', {'heading': heading})
Insert the value in the template:
<p>{{ heading }}</p>
Conditional Rendering
Use {% if %} blocks to show or hide fragments. Every opening tag must be closed with {% endif %}.
{% if user_tier == 'admin' %}
<div>Administrator Controls</div>
{% elif user_tier == 'member' %}
<div>Member Dashboard</div>
{% else %}
<div>Public Preview</div>
{% endif %}
Iteration
Loop over sequences with {% for %}:
View:
def home_page(request):
skills = ['Python', 'Django', 'PostgreSQL', 'Docker']
return render(request, 'home.html', {'skills': skills})
Template:
<ul>
{% for skill in skills %}
<li>{{ skill }}</li>
{% endfor %}
</ul>
Cycling Values
The cycle tag rotates through a set of values on each iteration. Its commonly used to apply alternating row styles:
<style>
.stripe-a { background: #ffffff; }
.stripe-b { background: #e5e7eb; }
</style>
<table>
{% for skill in skills %}
<tr class="{% cycle 'stripe-a' 'stripe-b' %}">
<td>{{ skill }}</td>
</tr>
{% endfor %}
</table>
Autoescaping
Django automatically escapes HTML characters to protect against cross-site scripting. If a variable contains trusted markup, disable escaping explicitly:
def home_page(request):
nav_link = '<a href="/about/">About Us</a>'
return render(request, 'home.html', {'nav_link': nav_link})
Template:
<div>
{% autoescape off %}
{{ nav_link }}
{% endautoescape %}
</div>
When autoescape is on—the default—characters such as < and > are converted to HTML entities.
Filters
Filters modify variables at render time. They follow a pipe symbol.
Change text casing:
{{ headline|upper }}
{{ headline|lower }}
Convert to URL-friendly slug:
{{ page_title|slugify }}
Provide a fallback for empty values:
{{ display_name|default:'Guest' }}
Count characters or items:
{{ headline|length }}
Remove unwanted substrings:
{{ description|cut:'lorem ' }}
Limit length with an ellipsis:
{{ summary|truncatechars:80 }}
Join list elements into a string:
{{ tags|join:', ' }}
Access the first or last item:
{{ tags|first }}
{{ tags|last }}
Round floating-point numbers:
{{ score|floatformat:2 }}
Comments
Hide single lines using {# ... #}:
{# This line is ignored by the parser #}
Hide larger blocks with the comment tag:
{% comment %}
This entire region
will not appear in the rendered output.
{% endcomment %}
Loading Static Assets
Reference CSS, JavaScript, and images with the {% static %} tag.
First, define the static URL and additional directories in settings.py:
STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
In templates, load the tag library before using it:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="{% static 'css/main.css' %}">
</head>
<body>
<img src="{% static 'images/logo.png' %}" alt="Company Logo">
<script src="{% static 'js/app.js' %}"></script>
</body>
</html>
Template Inheritance
Define a master layout to eliminate repetition. Create templates/base.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
<header>Primary Navigation</header>
{% block content %}
{% endblock %}
<footer>Contact Information</footer>
</body>
</html>
Child templates extend the parent and populate named blocks:
{% extends 'base.html' %}
{% block title %}User Dashboard{% endblock %}
{% block content %}
<h1>Welcome back</h1>
{% endblock %}
Including Partials
Reuse common fragments with {% include %}. Define a partial such as templates/components/notice.html:
<aside class="notice">{{ notice_text }}</aside>
Embed it in any page:
{% include 'components/notice.html' %}
This approach lets you compose pages from modular, reusable pieces.