Open-Source Wikis

/

Django

/

Systems

/

Templates

django/django

Templates

django/template/ is the Django Template Language (DTL) — a tag-and-filter language for rendering HTML (and any text format). Since 1.8, the directory also exposes a backend abstraction so other engines (Jinja2, mostly) can plug in.

Purpose

Provide a sandboxed, designer-oriented templating language with autoescape, template inheritance, and a stable extension model (custom tags and filters via django.template.Library). Pluggable backends let projects use multiple engines side-by-side.

Directory layout

django/template/
├── __init__.py
├── engine.py             # Engine: the central per-engine config
├── loader.py             # get_template, select_template, render_to_string
├── loader_tags.py        # {% extends %}, {% block %}, {% include %}
├── base.py               # Lexer, Parser, Token, Variable, Node, NodeList (~44 KB)
├── context.py            # Context, RequestContext, ContextDict
├── context_processors.py # csrf token processor (others live in contrib apps)
├── defaulttags.py        # {% if %}, {% for %}, {% url %}, {% with %}, … (~55 KB)
├── defaultfilters.py     # |default, |length, |slice, |date, |upper, … (~28 KB)
├── library.py            # Library, simple_tag, inclusion_tag, register_filter
├── response.py           # TemplateResponse, SimpleTemplateResponse
├── smartif.py            # The expression parser used by {% if %}
├── exceptions.py         # TemplateDoesNotExist, TemplateSyntaxError, …
├── utils.py              # InvalidTemplateLibrary, get_app_template_dirs
├── autoreload.py         # Templates aware of the runserver autoreloader
├── backends/
│   ├── base.py           # BaseEngine
│   ├── django.py         # DjangoTemplates (DTL backend)
│   ├── jinja2.py         # Jinja2 backend
│   ├── dummy.py          # No-op backend for tests
│   └── utils.py
└── loaders/
    ├── base.py           # Loader base class
    ├── filesystem.py     # FilesystemLoader
    ├── app_directories.py # AppDirectoriesLoader
    ├── cached.py         # CachedLoader
    └── locmem.py         # LocMemLoader

Key abstractions

Type File Role
Engine engine.py Per-engine config (loaders, dirs, builtins, libraries)
Template base.py A parsed template tree (a list of Nodes)
Lexer, Parser base.py Tokenise and parse the template source
Token base.py A token (text, var, block, comment)
Variable base.py A {{ var.attr }} expression
Node, NodeList base.py Compiled template nodes; render(context)
Context, RequestContext context.py The variable lookup stack
Library library.py The register object for custom tags/filters
BaseEngine backends/base.py The pluggable backend interface
DjangoTemplates, Jinja2 backends/django.py, backends/jinja2.py The two shipped backends
Origin base.py A loader-aware identifier for a template source
TemplateResponse response.py A response that defers rendering until needed

How it works

graph TD
    Source["template source<br/>e.g., 'index.html'"]
    Loader["Loader<br/>(filesystem / app_directories / cached)"]
    Lexer
    Tokens["[Token, Token, …]"]
    Parser
    Tree["NodeList of Node objects"]
    Context["Context (dict-like stack)"]
    Render["Node.render(context)"]
    Output["rendered text (SafeString)"]

    Source --> Loader
    Loader --> Lexer
    Lexer --> Tokens
    Tokens --> Parser
    Parser --> Tree
    Tree --> Render
    Context --> Render
    Render --> Output

Lexing and parsing

Lexer.tokenize() walks the source string and emits Tokens of four kinds:

  • TOKEN_TEXT — literal text outside of any tag.
  • TOKEN_VAR{{ ... }}.
  • TOKEN_BLOCK{% ... %}.
  • TOKEN_COMMENT{# ... #}.

Parser.parse() turns the token stream into a NodeList. For variable tokens, it builds a VariableNode wrapping a FilterExpression. For block tokens, it consults the parser's tag library to find a compile function that consumes from the parser to produce a Node (e.g., IfNode for {% if %} reads tokens until it sees {% endif %}).

Variable lookup

Variable.resolve(context) is the workhorse for {{ ... }}. It:

  1. Splits on . to get a sequence of attribute lookups.
  2. For each step, tries (in order): dictionary lookup, attribute access, list-index access, callable call (with no args, only if do_not_call_in_templates is not set).
  3. Returns the resolved value or raises VariableDoesNotExist. The default templating treats failure as an empty string, configurable via string_if_invalid.

Filters

FilterExpression parses var|filter:"arg"|filter2 syntax and holds a list of (filter_func, args) tuples. The library lookup happens at parse time; rendering applies each filter in order.

Tags

A custom tag is a Python function that takes a parser and a token, optionally consumes more tokens from the parser (for block tags like {% if %}...{% endif %}), and returns a Node instance whose render(context) produces output.

Library.simple_tag and Library.inclusion_tag are decorators that wrap simple cases. Library.tag is the lower-level decorator for full block tags.

Template inheritance

{% extends %} and {% block %} are implemented in loader_tags.py. ExtendsNode.render():

  1. Loads the parent template (lazily, with select_template).
  2. Walks the parent's NodeList and replaces any BlockNode with the child's override (if present).
  3. Renders the modified parent.

{% include %} similarly loads another template and renders it inline with the current (or a fresh) context.

Pluggable backends

Engine is the DTL configuration object. The bigger BaseEngine interface in backends/base.py lets non-DTL engines participate. Each backend exposes:

  • __init__(params) — accepts a config dict from the TEMPLATES setting.
  • from_string(template_code) — return a Template from a string.
  • get_template(template_name) — return a Template from a loaded file.

The Jinja2 backend (backends/jinja2.py) wraps jinja2.Environment and adapts its API to Django's template protocol. The shared cross-engine surface is template_rendered signal, TemplateResponse, and RequestContext (DTL-only).

Loaders

A loader resolves a template name to source code. The default chain is app_directories (look in <app>/templates/) then filesystem (look in TEMPLATES["DIRS"]). The cached loader wraps another loader and caches parsed Template objects in memory.

Context processors

Context processors are functions that run on every render and inject extra variables into a RequestContext. Built-in:

  • django.template.context_processors.csrf (in template/context_processors.py).
  • django.contrib.auth.context_processors.auth (in contrib/auth/context_processors.py) — adds user and perms.
  • django.contrib.messages.context_processors.messages.
  • django.template.context_processors.{request,debug,i18n,media,static,tz}.

Integration points

  • Views (views) — render(request, template_name, context) and TemplateResponse are the standard view-side entry points.
  • Forms (forms) — render via as_p, as_table, as_div, as_ul or per-template form rendering.
  • Admin (contrib/admin/) — built entirely on the DTL.
  • i18n (django/utils/translation/) — {% trans %}, {% blocktrans %}, {% blocktranslate %} tags are implemented in defaulttags.py.
  • Static files (contrib/staticfiles/) — provides {% static %} tag.
  • Autoreload — the dev server's reloader registers template directories so editing a template invalidates the loader cache.

Entry points for modification

  • Custom tag or filter: create a templatetags/<name>.py in your app, instantiate register = template.Library(), and decorate with @register.simple_tag, @register.filter, etc.
  • Custom loader: subclass django.template.loaders.base.Loader and override get_contents(). Add it to your TEMPLATES["OPTIONS"]["loaders"].
  • Custom backend: subclass BaseEngine in template/backends/base.py. Mirror the API of DjangoTemplates.
  • Built-in tag/filter: edits to defaulttags.py/defaultfilters.py. These changes go through Django's deprecation cycle.

Key source files

File Purpose
django/template/base.py Lexer, Parser, Variable, Node — the language core (~44 KB)
django/template/engine.py Engine
django/template/loader.py get_template, select_template, render_to_string
django/template/defaulttags.py Built-in tags ({% if %}, {% for %}, {% url %}, …)
django/template/defaultfilters.py Built-in filters (default, date, length, …)
django/template/loader_tags.py {% extends %}, {% block %}, {% include %}
django/template/context.py Context, RequestContext
django/template/library.py Library, simple_tag, inclusion_tag
django/template/response.py TemplateResponse, SimpleTemplateResponse
django/template/backends/django.py DTL backend
django/template/backends/jinja2.py Jinja2 backend
django/template/loaders/cached.py Loader cache
django/template/smartif.py {% if %} expression parser

Where to read tests

  • tests/template_tests/ — exhaustive lexer, parser, tag, filter, and inheritance coverage.
  • tests/template_backends/ — backend-level tests.
  • tests/templates/ — fixture templates used by the test apps.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Templates – Django wiki | Factory