skip to content

Engines, Loaders & Context

The TEMPLATES setting picks the DjangoTemplates or Jinja2 engine, loaders find files, and context processors inject request, user and messages. Interviewers probe loader order and the cached loader.

part ofDjangooverview, primer and where to startread it →
on this pageshow

explore

questions

4

In Django's TEMPLATES setting, what do DIRS and APP_DIRS do, and in what order does Django search for a template name?

level: juniorimportance: must knowfreq 58%

answer

  1. project folders versus app folders
  2. one loader per source
  3. first match wins
  4. INSTALLED_APPS order matters
  5. a subfolder named after the app

basics

~10 s

DIRS lists project template directories searched first, in order; APP_DIRS=True adds each installed app's templates/ subdirectory, searched in INSTALLED_APPS order. Django uses the first file that matches and raises TemplateDoesNotExist if none does.

solid answer

~40 s

`TEMPLATES` is a list of engine configurations; with the `DjangoTemplates` backend, `DIRS` is a list of directories the filesystem loader searches **in the order given**, and `APP_DIRS: True` adds the app-directories loader, which looks in the `templates/` subdirectory of every app in `INSTALLED_APPS`, **in INSTALLED_APPS order**. By default the filesystem loader runs first, so a project-level `templates/admin/base_site.html` in `DIRS` overrides the admin's own copy. The first match wins; if nothing matches, `TemplateDoesNotExist` is raised and the debug page lists every path tried. `APP_DIRS` defaults to `False`, though `startproject` sets it to `True`. Because all app template folders share one namespace, put an app's templates under `templates/<app_label>/` so two apps' `detail.html` files never shadow each other.

code

python · 11 lines
python
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            BASE_DIR / "templates" / "overrides",  # searched first
            BASE_DIR / "templates",
        ],
        "APP_DIRS": True,  # then <app>/templates/ in INSTALLED_APPS order
        "OPTIONS": {"context_processors": ["django.template.context_processors.request"]},
    },
]

go deeper

for a junior

Know that DIRS holds project template folders, APP_DIRS searches each app's templates folder, and the first match wins.

for a middle

Explain loader order — filesystem over DIRS, then app directories in INSTALLED_APPS order — and why app templates live in a subfolder named after the app.

for a senior

Use search order deliberately to override third-party templates, and debug missing templates from the loader postmortem instead of guessing.

for a principal

Set template-layout conventions (project overrides, namespaced app folders) so reusable apps and per-tenant overrides never shadow each other by accident.

## The TEMPLATES setting `TEMPLATES` is a **list of engine configurations**. Its default in Django's global settings is an empty list; the `settings.py` that `startproject` generates contains one entry: ```python TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ] ``` (The generated file ships `DIRS` empty; adding a project-level folder as above is the usual first edit.) | Key | Meaning | Default | |---|---|---| | `BACKEND` | engine class: `DjangoTemplates` or `Jinja2` | required | | `DIRS` | directories to search, in order | `[]` | | `APP_DIRS` | also search inside installed apps | `False` (startproject sets `True`) | | `OPTIONS` | backend-specific options: `context_processors`, `loaders`, `debug`, `autoescape`, `libraries`, ... | `{}` | ## How a name is resolved When a view asks for `"storefront/home.html"`, the `DjangoTemplates` engine runs its **template loaders** in order. With `DIRS` and `APP_DIRS` set and no explicit `loaders` option, that order is: 1. the **filesystem loader**, trying each directory in `DIRS` in the order listed; 2. the **app-directories loader**, trying `<app>/templates/` for each app in `INSTALLED_APPS`, in that order. The **first file found wins**. If no loader finds it, Django raises `TemplateDoesNotExist`; with `DEBUG` on, the error page includes a "template-loader postmortem" listing every path tried, which is the fastest way to debug a wrong location. If several engines are configured, `get_template()` tries each engine in order until one succeeds. ## Overriding templates from other apps The search order is how you customize templates you don't own: - A file in a `DIRS` folder beats every app template of the same name, so `templates/admin/base_site.html` at project level overrides the admin's version regardless of app order. - Between apps, **`INSTALLED_APPS` order decides**: an app listed before `django.contrib.admin` can override admin templates from its own `templates/admin/` folder; listed after, its copy is ignored. ## Namespacing app templates All app `templates/` folders are merged into one search space, so two apps both shipping `templates/detail.html` collide and the first app in `INSTALLED_APPS` silently wins. The convention is a subdirectory named after the app: - `stores/templates/stores/detail.html`, loaded as `"stores/detail.html"`; - `catalog/templates/catalog/detail.html`, loaded as `"catalog/detail.html"`. The duplicated folder name looks redundant, but it is what keeps names unique. ## Where to put which template - **Project-wide layouts** (`base.html`, error pages, overrides of third-party templates): a `DIRS` folder such as `BASE_DIR / "templates"`. - **App-owned pages and fragments**: `<app>/templates/<app>/`, so the app stays reusable. - **Per-store or per-tenant overrides**: an extra `DIRS` entry listed earlier, since `DIRS` order is the search order. ## Common mistakes - Forgetting `APP_DIRS: True` and wondering why app templates are not found. - Relying on `INSTALLED_APPS` order to pick between two unnamespaced templates. - Setting both `APP_DIRS` and an explicit `OPTIONS["loaders"]` list, which Django rejects with `ImproperlyConfigured`.

  • Your app ships templates/admin/base_site.html but the admin still shows its default header. Why?
    The app-directories loader searches apps in `INSTALLED_APPS` order and uses the first match, so if `django.contrib.admin` is listed before your app, the admin's own file wins. Move your app above the admin, or put the override in a `DIRS` folder, which the filesystem loader searches before any app.
  • How do you see which paths Django tried when TemplateDoesNotExist is raised?
    With `DEBUG = True`, the error page includes a template-loader postmortem listing, for each engine and loader, every path it tried and why it failed. It shows immediately whether the file is in the wrong folder, missing the app-name subdirectory or hidden by `APP_DIRS` being off.

saying these in an interview costs you the question

  • Django searches app templates before the DIRS folders.
  • APP_DIRS defaults to True in Django's settings.
  • Each app's templates are isolated, so same-named files never collide.
  • INSTALLED_APPS order has no effect on which template is used.
  • If two templates match, Django merges or reports the conflict.
open as a page

In Django, how would you write a context processor that exposes the current store's branding to every template, and when does it run?

level: middleimportance: must knowfreq 52%

basics

~20 s

Write a function that takes the request and returns a dict such as {'store': ...}, add its dotted path to OPTIONS['context_processors'], and it runs on every render that has a request — render(), render_to_string(..., request=request), generic views — but never on a request-less render.

open as a page

In Django 6.1, when is the cached template loader active, and what changes if you set OPTIONS['loaders'] in TEMPLATES yourself?

level: seniorimportance: should knowfreq 38%

basics

~20 s

With DjangoTemplates and no OPTIONS['loaders'], Django wraps its filesystem and app-directories loaders in cached.Loader in every environment; setting loaders yourself replaces that default, forbids APP_DIRS, and caches only if you wrap the list in the cached loader.

open as a page

In a Django project, what changes when you configure the Jinja2 template backend alongside or instead of DjangoTemplates?

level: middleimportance: nice to knowfreq 25%

basics

~20 s

The Jinja2 backend loads templates from each app's jinja2/ folder, knows none of Django's tags or filters, adds only request, csrf_input and csrf_token globals, and is customised through an environment callable; the admin still requires a DjangoTemplates engine.

open as a page