Django has a built-in template system. It is relatively easy to understand, and the source code is not as complicated as other parts of Django. This article is a summary of the notes I took when studying the system.
The online Django documentation has 5 pages dedicated to template.
A Django application developer probably does not need to know all of those details. But it is always a good thing for programmers to know how things work behind the scene.
Django Template Language (DTL) syntax mainly consists of three elements: variable, tag, and filter. Here are some examples:
variable
{{ variable }}
{{ tag.name }}
tag
{% expression %}
{% for startup in tag.startup_set.all %}
...
{% endfor %}
{% extends "base.html" %}
{% block title %}
{{ block.super }} - Tag List
{% endblock title %}
{% if/else/endif %}
{% if not tag.startup_set all and not tag.blog_posts.all %}
filter
{{ startup_date|date:"F jS, Y" }} ▶ July 2nd, 2019
{{ startup.website|urlize }}
{{ startup.description|linebreaks }}
other filters: title, pluralize, truncatewords:20, default:”base.html”
The django.template.loader module defines get_template
and select_template
functions. Both functions can load template files and render them agaist a dict.
The difference is that get_template
accepts a template name and
select_template
accepts a list of template names. Here is an example from
Django official tutorial.
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
The more common code is to use the render
function defined in django.shortcuts
module in views.
from django.shortcuts import render
...
return render(request, 'template_name.html', {'tag': tag})
The render
function itself (Django2.2.2 source code) is very simple and short.
It calls render_to_string
function in django.template.loader module, which in
turn calls get_template
or select_template
depending on template_name.
# in django.shortcuts
def render(request, template_name, context=None, content_type=None,
status=None, using=None):
"""
Return a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request,
using=using)
return HttpResponse(content, content_type, status)
# in django.template.loader
def render_to_string(template_name, context=None, request=None, using=None):
"""
Load a template and render it with a context. Return a string.
template_name may be a string or a list of strings.
"""
if isinstance(template_name, (list, tuple)):
template = select_template(template_name, using=using)
else:
template = get_template(template_name, using=using)
return template.render(context, request)
The django.template module has two classes Template and Context. Those are template system’s lower level APIs. Here is an example:
from django.template import Template, Context
template = Template('Hi, my name is {{ name }}.')
context = Context({'name': 'Andrew'})
template.render(context)
# result is 'Hi, my name is Andrew.'
The source code for Django template system is in django/template directory, and consists of 26 python files.
Bash command wc
outputs number of lines in a file. We know that total number
of lines of Django template system code is 5,863 (Django 2.2.2). The output
below also shows that two files base.py
and defaulttags.py
have over 1,000
lines of code each.
george@STK2M3:~/django-2.2.2/django/template$ wc -l *.py
1044 base.py
81 context_processors.py
280 context.py
907 defaultfilters.py
1474 defaulttags.py
180 engine.py
42 exceptions.py
68 __init__.py
328 library.py
66 loader.py
317 loader_tags.py
145 response.py
208 smartif.py
107 utils.py
5247 total
george@STK2M3:~/django-2.2.2/django/template$ wc -l loaders/*.py
14 loaders/app_directories.py
49 loaders/base.py
95 loaders/cached.py
46 loaders/filesystem.py
0 loaders/__init__.py
27 loaders/locmem.py
231 total
george@STK2M3:~/django-2.2.2/django/template$ wc -l backends/*.py
81 backends/base.py
129 backends/django.py
53 backends/dummy.py
0 backends/__init__.py
108 backends/jinja2.py
14 backends/utils.py
385 total