Django Tutorial menu

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

text
courses/
    templates/
        courses/
            index.html

The 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

python
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

html
<!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>
Output
Workownix Courses
240 students enrolled.
- Web Development
- Graphic Designing
- SEO

Template Syntax

SyntaxUse
{{ 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

html
<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>
Output
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

html
{% 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 %}
Output
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

html
<!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

html
{% 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.

Build links from the URL names you gave in urls.py, not by typing paths:

Example

html
<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?

Learn Django with a teacher

Join the Full Stack Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp