Templates
A template is an HTML file with a few extra pieces of syntax for dropping in Python values and light logic. It's how Django keeps HTML out of your view functions and view logic out of your HTML.
Rendering a template
Templates live in a templates/ folder inside an app, and a view uses render() instead of building an HttpResponse by hand:
<h1>{{ page_title }}</h1>
<p>We have {{ post_count }} posts.</p>
from django.shortcuts import render
def home(request):
return render(request, 'home.html', {
'page_title': 'Welcome',
'post_count': 12,
})
<h1>Welcome</h1> <p>We have 12 posts.</p>
The third argument to render() is the context — a dictionary whose keys become variables the template can use with {{ }}. Django substitutes each one directly into the output.
Tags: loops and conditionals
Anything that isn't a plain variable — loops, if-statements, template inheritance — uses {% %} instead:
<ul>
{% for post in posts %}
<li>{{ post.title }}{% if post.featured %} — Featured{% endif %}</li>
{% endfor %}
</ul>
{% for %} and {% if %} both need an explicit closing tag ({% endfor %}, {% endif %}) — there's no indentation-based block like in Python itself.
Template inheritance
Most pages on a site share a header, navigation, and footer. A base template defines that shared layout with named blocks that child templates fill in:
<html>
<body>
<nav>My Site</nav>
{% block content %}{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block content %}
<h1>{{ page_title }}</h1>
{% endblock %}
{% extends %} must be the very first line of a child template. Everything the child puts inside {% block content %} gets inserted into the matching block in base.html — so every page that extends it automatically shares the same nav bar without repeating it.
post.title. This is intentional: it keeps real logic in views, where it belongs, instead of scattered across HTML files.