skip to content

In Django's {% include %} tag, what context does the included template see, and how do the with and only options change it?

level: middleimportance: should knowfreq 50%

answer

  1. render, not paste
  2. inherits the caller's variables
  3. extra keyword variables for one include
  4. isolation drops more than you think
  5. blocks already rendered

basics

~20 s

A plain {% include %} renders the other template with the full current context; with key=value adds variables for that include only; only restricts it to the with values, dropping view and context-processor variables such as user and request.

solid answer

~40 s

`{% include 'bookings/_fare_summary.html' %}` renders that template with the **current context** — the view's variables, loop variables like `booking` and `forloop`, and context-processor values — and inserts the resulting HTML. `with total=booking.price currency='EUR'` pushes extra variables for that one include and pops them afterwards. Adding `only` renders the included template with just the `with` values: nothing from the view, and none of the context-processor variables such as `user` or `request`, which regularly surprises people. An include is a separate render, not textual pasting, so blocks inside an included file are already rendered output and cannot be overridden by a template that extends the includer. A missing included template raises `TemplateDoesNotExist` when the tag renders.

code

django · 10 lines
django
{# bookings/list.html #}
{% for booking in bookings %}
  {# plain: sees booking, forloop, user, request... #}
  {% include 'bookings/_card.html' %}

  {# explicit inputs only: user and request are NOT available #}
  {% include 'bookings/_fare.html' with total=booking.price currency=booking.currency only %}
{% empty %}
  <p>No trips booked yet.</p>
{% endfor %}

go deeper

for a junior

Know that a plain include sees everything the including template sees, and that with adds variables for just that include.

for a middle

Explain that only builds a fresh context without context-processor values, and that include is an independent render, so its blocks cannot be overridden.

for a senior

Show the judgment of isolating reusable fragments with with ... only, and be ready to diagnose the missing user or CSRF token that isolation causes.

for a principal

Frame the choice as explicit inputs versus implicit coupling: shared fragments across many pages should declare their inputs even though it costs verbosity.

## What `{% include %}` does `{% include %}` loads another template and renders it in place. On a travel-bookings site it is the usual way to reuse a fragment such as a fare summary or a booking card on several pages: ```django {% for booking in bookings %} {% include 'bookings/_card.html' %} {% endfor %} ``` The template name can be a quoted string, a relative path such as `'./_card.html'`, a variable holding a name, a variable holding a compiled template object, or an iterable of names — in which case the first one that loads is used. From Django 6.0 the name may also point at a single partial inside a file, `'bookings/list.html#booking-row'`. Django's documentation is explicit about the model: `include` means **"render this subtemplate and include the HTML"**, not "parse this subtemplate as if it were part of the parent". Each include is an independent rendering pass. ## The three context modes | Form | What the included template can read | |---|---| | `{% include 'x.html' %}` | the whole current context: view variables, loop variables, context-processor values | | `{% include 'x.html' with a=b %}` | all of the above, plus `a` for this include only | | `{% include 'x.html' with a=b only %}` | only `a` (and the literals `True`, `False`, `None`) | The `with` values are resolved in the includer's context, then pushed onto the context stack while the included template renders and popped afterwards, so they never leak back into the includer. Inside a loop, the default mode means the fragment sees the loop variable and `forloop` directly, which is convenient but couples the fragment to whatever name the caller's loop happened to use. ## `only` removes more than the view's variables `only` builds a fresh context containing just the `with` values. It does **not** re-run context processors, so variables that normally appear on every page — `user`, `request`, `perms`, `messages`, the CSRF token — are all absent inside an `only` include. A fragment that renders a form with `{% csrf_token %}` or checks `user.is_authenticated` silently breaks under `only` unless those values are passed explicitly through `with`. The trade-off: - **Plain include** — easiest to write, but the fragment depends invisibly on names in the caller's scope. - **`with ... only`** — the fragment's inputs are explicit and it behaves the same on every page, at the cost of passing everything it needs, including values you took for granted. ## An include is a render, not a paste Because the included template is rendered independently: 1. **Blocks inside an included file are already rendered.** If `_sidebar.html` defines `{% block promo %}`, a child template that extends the page including it cannot override `promo`; that block is part of finished HTML by the time inheritance sees it. 2. **No state is shared back.** Variables set inside the included template do not appear in the includer. 3. **Errors surface at render time.** A missing included template raises `TemplateDoesNotExist` when the tag renders. Within one render, the include tag caches the compiled template it loaded, so an include inside a loop does not reload the file on every iteration; each iteration is still a separate render of the fragment. ## Choosing between include and extends - Use **`extends`** when a page *is a kind of* layout: it fills named holes in a skeleton. - Use **`include`** when a page *contains* a reusable fragment: a card, a fare summary, a pagination bar. - When the fragment needs Python logic to compute its own data, a custom template tag is the tool; that is a separate topic. Keep fragment files small and name their inputs; `with ... only` is the discipline that makes a fragment safe to drop anywhere.

  • A fragment included with only renders a form whose POST now fails CSRF validation. Why?
    `only` builds a new context from the `with` values alone and does not run context processors again, so the CSRF token variable that `{% csrf_token %}` reads is missing and the tag outputs nothing. Pass what the fragment needs explicitly, or drop `only` for that fragment.
  • What happens if the template named in {% include %} does not exist?
    The include tag raises `TemplateDoesNotExist` when it renders. If you pass a list of names, the tag tries them in order and uses the first that loads, which is a way to express a fallback fragment.

saying these in an interview costs you the question

  • An included template only sees variables passed to it with the with keyword.
  • With only, context-processor variables like user and request are still available.
  • Blocks inside an included file can be overridden by a child template.
  • Include pastes the other file's source in before the page is parsed.
  • Variables set inside an included template become visible in the includer.