Templates
Building HTML with strings in a view gets messy fast. Templates are HTML files with placeholders that Django fills in with data.
Rendering a template
This example runs right here. Its first lines configure Django, the job a project's settings.py normally does:
import django
from django.conf import settings
settings.configure(TEMPLATES=[{"BACKEND": "django.template.backends.django.DjangoTemplates"}])
django.setup()
from django.template import Context, Template
page = Template("<h1>{{ title }}</h1><p>{{ count }} lessons, taught by {{ teacher.name }}.</p>")
print(page.render(Context({"title": "Python", "count": 64, "teacher": {"name": "Mira"}}))){{ title }}is replaced by the value oftitlein the context, the dictionary of data passed in.{{ teacher.name }}looks inside: a dictionary key, an attribute or a method, whichever exists.
Templates in a project
In a real project, templates are files. By convention each app keeps them in templates/<app name>/:
courses/
templates/
courses/
course_list.html
course_detail.htmlThe repeated courses folder looks odd, but it's deliberate: Django searches every app's templates folder, so the extra level stops two apps' detail.html files from clashing.
A view renders a template with render:
from django.shortcuts import render
from .models import Course
def course_list(request):
courses = Course.objects.order_by("title")
return render(request, "courses/course_list.html", {"courses": courses})render(request, template_name, context) loads the template, fills it with the context, and returns an HttpResponse.
Sharing a layout: extends and block
Every page of a site shares a header, a footer and the same CSS. Put them in one base template, and let each page fill in the parts that differ:
import django
from django.conf import settings
settings.configure(TEMPLATES=[{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"OPTIONS": {"loaders": [("django.template.loaders.locmem.Loader", {
"base.html": (
"<html><head><title>{% block title %}CodeMIRAI{% endblock %}</title></head>\n"
"<body><header>CodeMIRAI</header>\n"
"<main>{% block content %}{% endblock %}</main>\n"
"<footer>Learn to code</footer></body></html>"
),
"courses/course_list.html": (
"{% extends 'base.html' %}\n"
"{% block title %}Courses | {{ block.super }}{% endblock %}\n"
"{% block content %}<h1>All courses</h1><ul>{% for c in courses %}<li>{{ c }}</li>{% endfor %}</ul>{% endblock %}"
),
})]},
}])
django.setup()
from django.template.loader import render_to_string
print(render_to_string("courses/course_list.html", {"courses": ["Python", "SQL", "React"]}))- The base template marks replaceable areas with
{% block name %}...{% endblock %}. - A child template starts with
{% extends "base.html" %}and overrides only the blocks it needs. {{ block.super }}inserts the parent's content for that block, here keeping "CodeMIRAI" in the title.
(The locmem loader in this example holds the template files in memory, standing in for files on disk.)
Reusing pieces: include
import django
from django.conf import settings
settings.configure(TEMPLATES=[{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"OPTIONS": {"loaders": [("django.template.loaders.locmem.Loader", {
"courses/card.html": "<div class='card'><h3>{{ course.title }}</h3><p>{{ course.lessons }} lessons</p></div>",
"courses/grid.html": "{% for course in courses %}{% include 'courses/card.html' %}\n{% endfor %}",
})]},
}])
django.setup()
from django.template.loader import render_to_string
courses = [{"title": "Python", "lessons": 64}, {"title": "SQL", "lessons": 23}]
print(render_to_string("courses/grid.html", {"courses": courses})){% include %} inserts another template, which sees the same context, including the loop variable. It's the way to reuse a course card, a navigation bar or a form layout on many pages.
Where Django looks
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # project-wide templates, such as base.html
"APP_DIRS": True, # plus each app's templates/ folder
"OPTIONS": {"context_processors": [...]},
},
]A typical project keeps base.html in a top-level templates/ folder listed in DIRS, and each app's own pages inside the app.