Django from Basics to Production · Django Fundamentals

Templates and Auto-Escaping

Render HTML with Django templates: variables, filters, loops, inheritance, and auto-escaping that prevents XSS.

Create a free account to save this page, take notes and track your progress. Sign in

What you'll build

A base layout and a product list page that extends it, rendered with a context containing a malicious product name, showing that Django escapes it automatically, and where |safe would be dangerous.

The idea

  • Templates use {{ variable }}, {{ value|filter }} and tags like {% for %}, {% if %} and {% url %}.
  • Inheritance: a base template defines {% block %}s; pages {% extends %} it and fill the blocks.
  • Auto-escaping turns < into &lt; in variables, so user content can't inject scripts. |safe and mark_safe turn it off: use them only for HTML you control.
  • Keep logic in views; templates format data.

The code

Inheritance, filters and auto-escaping
import django
from django.conf import settings

settings.configure(SECRET_KEY="dev-only", TEMPLATES=[{
    "BACKEND": "django.template.backends.django.DjangoTemplates",
    "OPTIONS": {"loaders": [("django.template.loaders.locmem.Loader", {
        "base.html": "<title>{% block title %}Shop{% endblock %}</title><main>{% block content %}{% endblock %}</main>",
        "products.html": (
            "{% extends 'base.html' %}{% block title %}Products ({{ products|length }}){% endblock %}"
            "{% block content %}<ul>{% for p in products %}<li>{{ p.name }}: {{ p.price|floatformat:2 }}</li>"
            "{% empty %}<li>No products</li>{% endfor %}</ul>{% endblock %}"),
    })]},
}])
django.setup()

from django.template.loader import render_to_string

products = [{"name": "Mug", "price": 8.5}, {"name": "<script>alert('hi')</script>", "price": 1}]
print(render_to_string("products.html", {"products": products}))
print(render_to_string("products.html", {"products": []}))

Output

<title>Products (2)</title><main><ul><li>Mug: 8.50</li><li>&lt;script&gt;alert(&#x27;hi&#x27;)&lt;/script&gt;: 1.00</li></ul></main>
<title>Products (0)</title><main><ul><li>No products</li></ul></main>

Run this on your computer — see “Get Started” for setup.

Common mistakes

  • |safe on user-provided content, re-enabling cross-site scripting.
  • Complex logic or database queries triggered from templates (N+1 through related objects).
  • Hard-coded URLs instead of {% url 'name' %}, which break when routes change.

Key points

  • Templates extend a base and fill blocks.
  • Variables are auto-escaped; |safe is only for trusted HTML.
  • Prepare data in the view; keep templates simple.

Further reading: The Django template language · Automatic HTML escaping

Practice questions

How do Django templates protect against XSS?

Answer

Variables are HTML-escaped by default, so characters like < and > in user content are rendered as text rather than markup.

When is it acceptable to use |safe?

Answer

Only for HTML you generated and trust (for example sanitised or produced by your own code), never for raw user input.

What does template inheritance give you?

Answer

A base layout with named blocks that child templates extend and override, so common structure is defined once.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?