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?
answer
- name a fragment inside the page
- define once, render many times
- render in place and keep it
- a hash after the template name
- the fragment's context comes from the view
basics
~20 sWrap 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.
solid answer
~40 sDjango 6.0 added template partials: `{% partialdef booking-row %}...{% endpartialdef %}` names a fragment inside `bookings/list.html`, `{% partial booking-row %}` renders it with the current context, and the `inline` argument also renders it at its definition while keeping it reusable. Because the name is addressable as `bookings/list.html#booking-row` through `get_template()`, `render()` and `{% include %}`, the full page and the endpoint that returns one updated row use the **same markup**: the page loops and renders the partial, and the update view calls `render(request, 'bookings/list.html#booking-row', {'booking': booking})`. Only the fragment renders — not the rest of the file or its `extends` parent — so the view must pass every variable the fragment reads, under the names the page's loop uses. An unknown `#name` raises `TemplateDoesNotExist`.
code
python · 9 linesfrom django.shortcuts import get_object_or_404, render
from .models import Booking
def booking_row(request, pk):
booking = get_object_or_404(Booking, pk=pk, traveller=request.user)
# Renders only the booking-row partial, not list.html or base.html.
return render(request, "bookings/list.html#booking-row", {"booking": booking})go deeper
Recall that Django 6 lets you name a fragment with partialdef and render it with partial, instead of copying markup or making a new file.
Explain inline versus default definitions, that partial uses the current context, and that file.html#name works with render and include.
Design a page and a fragment endpoint that share one partial, pass the exact variables the fragment reads, and know the scoping and error behaviour.
Decide where fragments live: partials keep single-page fragments beside their page, while shared fragments belong in their own files with explicit inputs.
## The problem partials solve A bookings list page renders one row per booking. When a traveller cancels a trip, a script-driven request should get back **just that one row** to swap into the page. Before Django 6.0 the choices were to copy the row markup into a second template or to move it into a separate `_row.html` file and `{% include %}` it from the page. Both work; both split one small piece of UI away from the page that gives it meaning. **Template partials**, built into the Django template language since **6.0**, let the fragment stay in the page's own file while still being loadable on its own. ## The three pieces - **`{% partialdef name %}...{% endpartialdef %}`** defines a named fragment. By default the definition renders **nothing** where it stands; it only registers the fragment. The closing tag may repeat the name (`{% endpartialdef booking-row %}`). - **`inline`** — `{% partialdef booking-row inline %}` — renders the fragment at its definition *and* keeps it registered for reuse. - **`{% partial name %}`** renders a fragment defined in the **same template file**, with the current context, as many times as needed. It takes exactly one argument; to adjust the context, wrap it in `{% with %}`. And the part interviewers probe: - **`template_name#partial_name`** — any template-loading call that takes a name accepts a `#` suffix: `get_template('bookings/list.html#booking-row')`, `render(request, 'bookings/list.html#booking-row', ...)`, `{% include 'bookings/list.html#booking-row' %}`. The engine splits the name on `#`, loads the file, and returns only that fragment. ## Putting it together ```django {# bookings/list.html #} {% extends 'base.html' %} {% partialdef booking-row %} <tr id="booking-{{ booking.pk }}"> <td>{{ booking.destination }}</td> <td>{{ booking.departs_on|date:'j M Y' }}</td> <td>{{ booking.get_status_display }}</td> </tr> {% endpartialdef %} {% block content %} <table> {% for booking in bookings %}{% partial booking-row %}{% endfor %} </table> {% endblock %} ``` The partial is defined outside any block of a child template; that is fine, because definition happens at parse time and a non-inline definition outputs nothing anyway. The page view renders `bookings/list.html` as usual. The cancel view renders only the row: ```python def cancel_booking(request, pk): booking = get_object_or_404(Booking, pk=pk, traveller=request.user) booking.status = Booking.Status.CANCELLED booking.save(update_fields=["status"]) return render(request, "bookings/list.html#booking-row", {"booking": booking}) ``` ## What the fragment render includes and excludes | Rendered for `list.html#booking-row` | Not rendered | |---|---| | the partial's own nodes | the rest of `list.html` | | the context the view passes | the `extends` parent `base.html` | | context-processor values (via `render()`) | variables set by the page's `{% for %}` loop | The last row is the design constraint: in the page, `booking` comes from the loop; in the fragment response it must come from the view. Keep the fragment's inputs few and name them the same way in both places. ## Errors and scoping 1. `{% partial x %}` for a name not defined in the **current file** raises `TemplateSyntaxError` ("Partial 'x' is not defined in the current template") when it renders. Partials are **not inherited** through `extends`: a child cannot `{% partial %}` a fragment defined only in its parent. Use `{% include 'base.html#x' %}` to reach across files. 2. A `#name` that does not exist raises `TemplateDoesNotExist` from the loader. 3. Defining the same partial name twice in one file is a `TemplateSyntaxError` at parse time. 4. A partial may be used before its definition in the same file. ## When to choose which - A fragment used only by one page and its update endpoint: a **partial** in that page's file. - A fragment shared by many unrelated pages: a separate file with `{% include %}` (or `file.html#name` from wherever it lives). - A fragment that needs its own Python to compute data: a custom template tag, a separate topic. Partials came from the third-party `django-template-partials` package; Django 6.0's release notes link a migration guide for projects moving to the built-in tags.
- How do you reuse a partial defined in bookings/list.html from a different template?`{% partial %}` only sees partials in the current file, so use the loader syntax instead: `{% include 'bookings/list.html#booking-row' %}`, optionally with `with ... only` to pass its inputs explicitly.
- What goes wrong if the list page loops with {% for b in bookings %} but the fragment reads booking?Inside the page the partial renders with the current context, where the variable is `b`, so `booking` resolves to nothing and the row renders blank. Either loop with `booking` or wrap the call in `{% with booking=b %}{% partial booking-row %}{% endwith %}` so page and endpoint agree on one name.
- What error does render(request, 'bookings/list.html#no-such-row', {}) raise?`TemplateDoesNotExist`: the engine loads the file, looks the name up among its partials, and raises the loader's not-found error when it is missing, just as for a missing file.
saying these in an interview costs you the question
- A partialdef renders its content where it is defined unless you hide it.
- The #partial_name suffix is a URL fragment the browser scrolls to.
- Rendering list.html#booking-row still renders the base.html layout around it.
- A child template can use {% partial %} on fragments defined in its parent.
- {% partial %} accepts with and only just like {% include %}.
- Partials in Django 6 still require installing a third-party package.