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.
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<in variables, so user content can't inject scripts.|safeandmark_safeturn it off: use them only for HTML you control. - Keep logic in views; templates format data.
The code
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><script>alert('hi')</script>: 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
|safeon 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;
|safeis 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.