Templates

Reviewed & published by Brayan K

A Django template is an HTML file containing the Django Template Language — placeholders and tags that Django fills in with data from your views to produce the final page sent to the browser.

Part of the free Django course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

In this lesson you'll learn how to render a template from a view, pass data through a context dictionary, output variables, drive logic with template tags, and reshape values with filters.

What You'll Learn in This Lesson

1 Rendering a Template

A view's job is to gather data and hand it to a template. The render() shortcut takes the request, the template's filename, and a context dictionary, then returns a finished HttpResponse with the rendered HTML.

The keys of the context dictionary become the variable names you can use inside the template. So if your context is {'title': 'Welcome'}, the template can output that value with {{ title }}.

# blog/views.py
from django.shortcuts import render

def home(request):
    context = {
        "title": "Welcome to my blog",
        "author": "Alice",
    }
    return render(request, "index.html", context)

And the matching template file might look like this:

<!-- templates/index.html -->
<h1>{{ title }}</h1>
<p>Posted by {{ author }}</p>
# Django's render() substitutes context values into placeholders.
# We can simulate that substitution with str.format so it runs here,
# while the real Django version is shown in the lesson above.

template = "<h1>{title}</h1>\n<p>Posted by {author}</p>"

context = {
    "title": "Welcome to my blog",
    "author": "Alice",
}

# Django does this fill-in step for you when you call render().
rendered_html = template.format(**context)
print(rendered_html)

# In real Django the view would simply return:
#   return render(request, "index.html", context)

# ✅ Expected output:
# <h1>Welcome to my blog</h1>
# <p>Posted by Alice</p>

2 Variables and Template Tags

The Django Template Language has two main building blocks. Variables use the double-brace syntax to print a value: {{ user.name }}. You can even reach into attributes and dictionary keys with a dot.

Tags use the brace-percent syntax to run logic. The {% for %} tag loops over a list and the {% if %} tag branches. Block tags must be closed: a for-loop ends with {% endfor %} and an if ends with {% endif %}.

<!-- templates/posts.html -->
<h1>{{ heading }}</h1>

{% if posts %}
  <ul>
    {% for post in posts %}
      <li>{{ post.title }} by {{ post.author }}</li>
    {% endfor %}
  </ul>
{% else %}
  <p>No posts yet.</p>
{% endif %}
# Simulating a {% for %} loop and {{ variable }} output in Python.
# The template engine walks the list and prints one <li> per item.

heading = "Latest Posts"
posts = [
    {"title": "Django Basics", "author": "Alice"},
    {"title": "Templates 101", "author": "Bob"},
]

# Build the HTML the way the {% for %} tag would
print("<h1>" + heading + "</h1>")
if posts:
    print("<ul>")
    for post in posts:
        # {{ post.title }} and {{ post.author }} become these values
        print("  <li>" + post["title"] + " by " + post["author"] + "</li>")
    print("</ul>")
else:
    print("<p>No posts yet.</p>")

# ✅ Expected output:
# <h1>Latest Posts</h1>
# <ul>
#   <li>Django Basics by Alice</li>
#   <li>Templates 101 by Bob</li>
# </ul>

3 Template Filters

A filter transforms a variable just before it is displayed. You apply one with a pipe character after the variable name. Some filters take an argument after a colon, and you can chain several together.

<!-- templates/profile.html -->
<p>{{ name|upper }}</p>                  <!-- ALICE -->
<p>{{ joined|date:"F j, Y" }}</p>        <!-- June 17, 2026 -->
<p>{{ tags|length }} tags</p>            <!-- 3 tags -->
<p>{{ bio|truncatewords:5 }}</p>         <!-- first 5 words... -->
<p>{{ nickname|default:"Anonymous" }}</p><!-- fallback value -->
# Filters transform a value before it is shown. Here are plain-Python
# stand-ins for the upper, length, default and truncatewords filters.

def f_upper(value):
    return value.upper()

def f_length(value):
    return len(value)

def f_default(value, fallback):
    return value if value else fallback

def f_truncatewords(value, count):
    words = value.split()
    if len(words) <= count:
        return value
    return " ".join(words[:count]) + "..."

name = "alice"
tags = ["python", "django", "web"]
nickname = ""
bio = "Learning Django one template at a time today"

print(f_upper(name))                       # {{ name|upper }}
print(f_length(tags), "tags")              # {{ tags|length }}
print(f_default(nickname, "Anonymous"))    # {{ nickname|default:"Anonymous" }}
print(f_truncatewords(bio, 5))             # {{ bio|truncatewords:5 }}

# ✅ Expected output:
# ALICE
# 3 tags
# Anonymous
# Learning Django one template at...

🎯 Your Turn: Fill the Context

Fill in the blank so the context dictionary has a username key that the template variable {{ username }} would print as jordan.

# 🎯 YOUR TURN: replace ___ with the key name "username"

template = "Hello, {username}!"

context = {
    "___": "jordan",
}

print(template.format(**context))

# EXPECTED OUTPUT:
# Hello, jordan!

Common Errors (And How to Fix Them)

Django cannot find the file because the templates directory is not configured or the name is misspelled.

✅ Fix: set APP_DIRS to True or add your folder to DIRS in the TEMPLATES setting, and confirm the filename matches.

❌ Invalid block tag: 'endblock', expected 'endfor'

You opened a {% for %} or {% if %} but never closed it.

✅ Fix: every block tag needs its closing tag — add {% endfor %} or {% endif %}.

❌ Could not parse the remainder of a Python expression

You wrote raw Python (like a function call) where a template tag is needed.

✅ Fix: use a tag such as {% if x %} instead of a Python expression — the template language is not Python.

📋 Quick Reference

SyntaxWhat It Does
{{ variable }}Output a value from the context
{% for x in items %}Loop over a list (close with endfor)
{% if condition %}Show a block conditionally (close with endif)
{{ name|upper }}Apply a filter to transform a value
render(request, "x.html", ctx)Render a template with context data

🏆 Mini Challenge: Render a Product List

Build the HTML a template would produce for a list of products, applying an uppercase transform to each name like the upper filter would.

❓ Frequently Asked Questions

Lesson complete — your views can now render real pages!

You now know how render() combines a template with a context dictionary, how to output variables with double braces, how to drive logic with the for and if tags, and how to reshape values with filters like upper, date, length, default, and truncatewords.

Practice quiz

What does the render() shortcut take and return?

  • A model and returns a QuerySet
  • The request, a template name, and a context, returning an HttpResponse
  • A URL pattern and returns a view
  • A form and returns JSON

Answer: The request, a template name, and a context, returning an HttpResponse. render(request, template, context) fills the template with context and returns an HttpResponse.

Where do the context dictionary's keys become usable in a template?

  • Only in the URL pattern
  • Only inside {% block %} tags
  • As variable names inside double braces, e.g. {{ title }}
  • As filenames Django loads

Answer: As variable names inside double braces, e.g. {{ title }}. Each context key becomes a variable name you output with the double-brace syntax.

Which syntax outputs a value into the page?

  • {{ value }}
  • {% value %}
  • {# value #}
  • << value >>

Answer: {{ value }}. Double braces {{ value }} output a variable's value into the rendered HTML.

Which syntax is used for logic such as loops and branching?

  • {{ ... }}
  • {# ... #}
  • [[ ... ]]
  • {% ... %}

Answer: {% ... %}. Brace-percent {% ... %} tags run logic like {% for %} and {% if %}.

How must a {% for %} loop be closed?

  • With {% endloop %}
  • With {% endfor %}
  • With {% end for %}
  • It closes automatically

Answer: With {% endfor %}. Block tags must be closed; a for loop ends with {% endfor %}.

How do you apply a filter to a variable?

  • With a pipe after the variable, e.g. {{ name|upper }}
  • With a colon before it, e.g. {{ :upper name }}
  • By wrapping it in {% filter %}
  • Filters cannot be applied in templates

Answer: With a pipe after the variable, e.g. {{ name|upper }}. A filter is applied with the pipe character after the variable name, like {{ name|upper }}.

What does the upper filter do in {{ name|upper }}?

  • Counts the characters in name
  • Supplies a default value
  • Converts the text to uppercase
  • Formats name as a date

Answer: Converts the text to uppercase. The upper filter converts the variable's text to uppercase.

How do you pass an argument to a filter like date?

  • With a pipe, as {{ joined|date|'F j, Y' }}
  • With a space, as {{ joined date 'F j, Y' }}
  • Filters never take arguments
  • With a colon, as {{ joined|date:'F j, Y' }}

Answer: With a colon, as {{ joined|date:'F j, Y' }}. An argument follows the filter after a colon, e.g. {{ joined|date:'F j, Y' }}.

What does TemplateDoesNotExist usually indicate?

  • Django could not find the named template file or its directory is not configured
  • The template has a syntax error
  • A context key was missing
  • The view returned None

Answer: Django could not find the named template file or its directory is not configured. It means Django could not locate the template — check DIRS/APP_DIRS and the filename.

Which is the correct call to render a template with context in a view?

  • render('x.html', context)
  • render_template(request, 'x.html')
  • render(request, 'x.html', context)
  • template.render('x.html', request)

Answer: render(request, 'x.html', context). render(request, 'x.html', context) is the standard shortcut for rendering a template.

Continue this course

Frequently asked questions

What is a Django template?

A Django template is an HTML file containing the Django Template Language — special placeholders and tags that Django fills in with data from your view. When a request comes in, the view gathers data into a context dictionary, Django renders the template by substituting that data into the placeholders, and the finished HTML is sent to the browser. Templates let you keep presentation (HTML) separate from logic (Python).

What is the difference between a variable and a tag in a template?

A variable, written with double braces, outputs a value into the page — for example outputting a user's name. A tag, written with brace-percent syntax, performs logic such as looping over a list, branching with if, or extending a base layout. Variables produce text; tags control the structure and flow of the template.

What are template filters?

Filters transform the value of a variable just before it is displayed. You apply a filter with a pipe character after the variable name, like name then pipe then upper to uppercase it. Filters can format dates, change case, truncate long text, count items, and supply default values. You can chain multiple filters and some accept an argument after a colon.

Why do I get TemplateDoesNotExist?

Django could not find the template file you named in render(). This usually means the templates directory is not registered in the TEMPLATES setting's DIRS list, the file is in the wrong folder, or the name is misspelled. Make sure APP_DIRS is True or that DIRS points at your templates folder, and that the filename in render() exactly matches the file on disk.