Django Templates
Templates keep your HTML separate from your Python code. Django fills them with data before sending them to the browser.
Where Templates Live
Create this folder structure inside your app:
Example
courses/
templates/
courses/
index.htmlThe second courses folder avoids name clashes with other apps.
Rendering a Template
Use render() in the view and pass data in a dictionary called the context:
Example
from django.shortcuts import render
def index(request):
context = {
"institute": "Workownix",
"courses": ["Web Development", "Graphic Designing", "SEO"],
"students": 240,
}
return render(request, "courses/index.html", context)Example
<!DOCTYPE html>
<html>
<body>
<h1>{{ institute }} Courses</h1>
<p>{{ students }} students enrolled.</p>
<ul>
{% for course in courses %}
<li>{{ course }}</li>
{% endfor %}
</ul>
</body>
</html>Workownix Courses 240 students enrolled. - Web Development - Graphic Designing - SEO
Template Syntax
| Syntax | Use |
|---|---|
{{ name }} | Print a variable |
{{ student.name }} | Print an attribute or dictionary key |
{% tag %} | Logic: for, if, block, url, and more |
{# comment #} | A comment |
Filters
A filter changes a value before it is shown. Write it after a vertical bar. Suppose the context has name = "Ayesha Khan", bio = "I love designing logos and posters for shops", joined = a date, no city, and the three courses:
Example
<p>{{ name|upper }}</p>
<p>{{ bio|truncatewords:5 }}</p>
<p>{{ joined|date:"d M Y" }}</p>
<p>{{ city|default:"Karachi" }}</p>
<p>{{ courses|length }} courses</p>AYESHA KHAN I love designing logos and … 15 Oct 2026 Karachi 3 courses
Common filters: upper, lower, title, length, default, date, truncatewords, floatformat.
if and for
Example
{% if students > 200 %}
<p>Big batch this year!</p>
{% elif students > 0 %}
<p>Admissions are open.</p>
{% else %}
<p>No students yet.</p>
{% endif %}
{% for course in courses %}
<p>{{ forloop.counter }}. {{ course }}</p>
{% empty %}
<p>No courses found.</p>
{% endfor %}Big batch this year! 1. Web Development 2. Graphic Designing 3. SEO
{% empty %} shows when the list has no items. forloop.counter counts from 1.
Template Inheritance
Put the shared layout in a base template, and let each page fill in blocks.
courses/templates/courses/base.html:
Example
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Workownix{% endblock %}</title>
</head>
<body>
<header>Workownix Institute</header>
{% block content %}{% endblock %}
<footer>Orangi Town, Karachi</footer>
</body>
</html>courses/templates/courses/index.html:
Example
{% extends "courses/base.html" %}
{% block title %}Courses{% endblock %}
{% block content %}
<h1>Our Courses</h1>
{% endblock %}Change the header once in base.html and every page that extends it updates.
Links with the url Tag
Build links from the URL names you gave in urls.py, not by typing paths:
Example
<a href="{% url 'course-list' %}">All courses</a>
<a href="{% url 'course-detail' 2 %}">Graphic Designing</a>Auto-escaping
Django escapes HTML in variables automatically, so text like <script> from a user is shown as plain text, not run. This protects against XSS.
Exercise
Exercise
Which syntax prints a variable in a Django template?
