skip to content

Extends, Blocks & Partials

{% extends %} and {% block %} with {{ block.super }} build layouts, {% include %} reuses fragments, and 6.0 partials render one named piece of a file. Interviewers probe partials for fragment updates.

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

explore

questions

4

In Django templates, how do {% extends %}, {% block %} and {{ block.super }} work together to build a site-wide page layout?

level: juniorimportance: must knowfreq 72%

answer

  1. parent declares, child replaces
  2. named regions with default content
  3. first tag in the child
  4. unfilled regions keep the default
  5. add to the parent's content

basics

~20 s

A child template starts with {% extends 'base.html' %}; each {% block %} it defines replaces the same-named block in the parent, blocks it skips keep the parent's default, and {{ block.super }} inserts the parent block's content instead of discarding it.

solid answer

~40 s

A base template such as `base.html` lays out the whole page and marks replaceable regions with `{% block name %}...{% endblock %}`; whatever sits inside a block is its default. A child template begins with `{% extends 'base.html' %}` — it must be the first template tag — and defines blocks with the same names. At render time Django renders the *parent*, substituting the child's version of each block it overrides and keeping the parent's default for every block it doesn't. Inside an overriding block, `{{ block.super }}` renders the next level up's content for that block, so a page can add to it (an extra stylesheet, a title suffix) instead of copying it. Chains work too: a page can extend `bookings/base_bookings.html`, which extends `base.html`, and the most-derived override of each block wins.

code

django · 13 lines
django
{# templates/bookings/base_bookings.html #}
{% extends 'base.html' %}

{% block nav %}
  {{ block.super }}
  <a href="/bookings/upcoming/">Upcoming</a>
  <a href="/bookings/past/">Past</a>
{% endblock nav %}

{% block extra_head %}
  {{ block.super }}
  <link rel="stylesheet" href="/static/css/bookings.css">
{% endblock %}

go deeper

for a junior

Recall the three pieces: extends names the parent and comes first, block marks a replaceable region with a default, and block.super keeps the parent's content inside your override.

for a middle

Explain that the parent is what actually renders, that unoverridden blocks keep defaults, and how block.super climbs one level at a time in a three-level site/section/page chain.

for a senior

Show how you would design a base layout with enough hooks (extra_head, scripts, nav) that pages never copy markup, and how a variable extends lets one view pick a layout.

for a principal

Weigh deep inheritance chains against flatter layouts plus fragments: each extra level adds indirection a reader must trace, so keep chains shallow and hooks purposeful.

## What template inheritance solves A travel-bookings site has dozens of pages — search results, a booking list, a booking detail, checkout — and every one needs the same `<head>`, navigation bar, footer and script tags. Copying that skeleton into each file means one navigation change touches every page. **Template inheritance** in the Django template language (DTL) solves this with two tags and one variable: - **`{% block name %}...{% endblock %}`** marks a named, replaceable region. Whatever sits between the tags is the block's **default content**. - **`{% extends 'base.html' %}`** declares that the current template is a **child** of another template, its **parent**. - **`{{ block.super }}`**, used inside an overriding block, renders the parent's version of that block. ## The parent: a skeleton with named holes ```django {# templates/base.html #} <!DOCTYPE html> <html lang="en"> <head> <title>{% block title %}Trips{% endblock %}</title> {% block extra_head %}{% endblock %} </head> <body> <nav>{% block nav %}<a href="/">Home</a> <a href="/bookings/">My trips</a>{% endblock %}</nav> <main>{% block content %}{% endblock %}</main> </body> </html> ``` The parent is an ordinary template: rendered on its own it outputs its defaults. The `block` tags only announce that a child *may* replace those regions. ## The child: override only what differs ```django {# templates/bookings/list.html #} {% extends 'base.html' %} {% block title %}{{ block.super }} · My bookings{% endblock %} {% block content %} <h1>Upcoming trips</h1> ... {% endblock content %} ``` When Django renders `bookings/list.html`, it sees the `extends` tag, loads the parent, and then renders the **parent** — substituting the child's version of every block the child defines. Here the title becomes `Trips · My bookings`, `content` is replaced, and `extra_head` and `nav` fall back to the parent's defaults because the child never mentions them. A child does **not** have to override every block; Django's own documentation recommends many blocks in the base, because each one is a cheap hook that costs nothing when unused. The closing tag may repeat the name (`{% endblock content %}`) purely for readability. ## `{{ block.super }}`: extend instead of replace Overriding a block replaces its contents entirely. When a page wants to *add* to the parent's content — one more stylesheet in `extra_head`, a suffix on the title, an extra link in `nav` — it writes `{{ block.super }}` where the parent's content should appear. Two details matter: 1. It renders the **next level up** in the chain, not necessarily `base.html`. In a three-level chain, the page's `block.super` returns the section template's override if the section defines that block, and the base's default otherwise. 2. Its output is **marked safe**, so it is not escaped a second time; the parent's variables were already escaped when that block rendered. ## Multi-level inheritance The Django docs describe a common three-level layout: | Level | Example file | Holds | |---|---|---| | Site | `base.html` | `<head>`, global nav, footer | | Section | `bookings/base_bookings.html` | section sub-navigation, section CSS | | Page | `bookings/list.html` | the page's own content | `base_bookings.html` extends `base.html` and overrides `nav` with `{{ block.super }}` plus a bookings sub-menu; each bookings page extends `base_bookings.html`. For every block the most-derived override wins, and each `block.super` walks one level up. ## Rules that keep inheritance working - `{% extends %}` must be the **first template tag** in the child; any other tag before it, even `{% load %}`, raises `TemplateSyntaxError`. - A template may contain **one** `{% extends %}` and may not define two blocks with the same name — both are `TemplateSyntaxError`s at parse time. - `{% extends %}` accepts a quoted name, a relative path such as `'./base_bookings.html'`, or a variable holding either a template name or a compiled `Template` — useful when the layout is chosen per request. - The parent's name is resolved by the configured template loaders like any other template name. The mental model to keep: the child does not wrap the parent. The parent is what gets rendered, and the child is a set of named replacements for its blocks.

  • In a three-level chain, what does {{ block.super }} in the page template return?
    The next level up: the section template's version of that block if the section overrides it (which may itself call `{{ block.super }}`), otherwise the base template's default. Each `block.super` climbs exactly one level, so contributions from every level can be stacked.
  • Can the parent of {% extends %} be chosen at runtime?
    Yes. `{% extends layout %}` takes a variable; if it resolves to a string Django loads that template name, and if it resolves to a compiled `Template` it uses that object directly. An empty value raises `TemplateSyntaxError`, so the view must always supply a valid layout.

A base layout is a printed form with labelled boxes that already hold sample text; a child page is a sheet of sticky notes, one per box it wants to change. Boxes without a note keep the printed text, and {{ block.super }} is copying the printed text onto your note before adding a line.

saying these in an interview costs you the question

  • A child template must override every block its parent declares.
  • {% extends %} can appear anywhere in the child, for example after {% load %}.
  • Overriding a block automatically appends to the parent's content.
  • {{ block.super }} always jumps straight to base.html, skipping middle levels.
  • The child template is rendered first and the parent is wrapped around it.
open as a page

Why does a Django child template that uses {% extends %} silently drop markup placed outside its {% block %} tags?

level: middleimportance: should knowfreq 38%

basics

~10 s

Rendering a child renders its parent; the child contributes only its {% block %} overrides, so text, tags and variables placed outside any block in the child are never output.

open as a page

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%

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.

open as a page

In Django 6.0+, how would you use {% partialdef %} and the template_name#partial_name syntax to re-render one booking row without duplicating its markup?

level: seniorimportance: nice to knowfreq 28%

basics

~20 s

Wrap the row in {% partialdef booking-row inline %} in the list template, loop over it with {% partial booking-row %} or inline, and have the update view call render(request, 'bookings/list.html#booking-row', {'booking': booking}) to return only that fragment.

open as a page