In Django's {% include %} tag, what context does the included template see, and how do the with and only options change it?
answer
- render, not paste
- inherits the caller's variables
- extra keyword variables for one include
- isolation drops more than you think
- blocks already rendered
basics
~20 sA 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{# 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
Know that a plain include sees everything the including template sees, and that with adds variables for just that include.
Explain that only builds a fresh context without context-processor values, and that include is an independent render, so its blocks cannot be overridden.
Show the judgment of isolating reusable fragments with with ... only, and be ready to diagnose the missing user or CSRF token that isolation causes.
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.