Opened 2 hours ago
Closed 23 minutes ago
#37038 closed Bug (wontfix)
{% extends %}/{% block %} doesn't work as expected with {% partialdef %}/{% partial %}
| Reported by: | Christophe Henry | Owned by: | |
|---|---|---|---|
| Component: | Template system | Version: | 6.0 |
| Severity: | Normal | Keywords: | |
| Cc: | Carlton Gibson, Farhan Ali | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
First, please excuse me if this edge-case is actually documented or if there's already an issue documenting it.
I recently had the use case where I needed to duplicate a block of buttons present a the top of a form, to the bottom of it, on a template that was extended by another to add a few extra buttons.
I wanted to use the newly added {% partialdef %} to solve the problem but realised {% partialdef %} and {% block %}. Take the flowing example:
{% partialdef btns inline %}
{% block btns_block %}
<button type="button">Save</button>
<button type="button">Publish</button>
{% endblock %}
{% endpartialdef %}
<!-- later -->
{% partial btns %}
And second template extending the previous:
{% block btns_block %}
<button type="button">Cancel</button>
<button type="button">Save</button>
<button type="button">Publish</button>
{% endblock %}
In this situation, the partial will be correctly overriden during the first usage but not during the second. In the extending template, the cancel button is present at the top of the page but not at the button.
If {% partialdef %} is not inline, the cancel button is not even there at the top of the extending template.
I created a minimal reproducing example to illustrate this problem: https://github.com/christophehenry/extends-partials-bug.
Change History (1)
comment:1 by , 23 minutes ago
| Cc: | added |
|---|---|
| Resolution: | → wontfix |
| Status: | new → closed |
Hello Christophe Henry, thanks for the report!
After carefully reviewing the template engine internals, I will close this ticket as
wontfixas a design limitation rather than a bug.{% partialdef %}/{% partial %}and{% block %}/{% extends %}are two distinct, independent features of the template system. Partials create an isolated rendering context by design (just like{% include %}) to keep them portable and predictable. Block inheritance resolution lives in that rendering context, so it is intentionally not visible when a partial is rendered via{% partial %}.The fact that the inline partial's first render in your example project happens to see the block context is an implementation side effect, not a design guarantee, and relying on it would be fragile. For the use case you describe ("rendering the same button section at the top and bottom of a form, with child templates able to customize it") the idiomatic Django approach is to extract the shared markup into a helper template and use
{% include %}inside two distinct blocks. If the button markup is simple, overriding both blocks inline is sufficient. If the button row is more complex and you want to avoid duplicating the override, you can define the extra content once using {% partialdef %} in the child template and reference it via thetemplate_name#partialsyntax:The default button markup (and potentially its "row" display) lives in one place (
_action_btns.html). The two blocks add a single line of duplication inbase.html, but that cost is low and the intent is explicit. If the child's override is also long or reused across multiple templates, it can be extracted into its own helper template or, as shown, defined with{% partialdef %}directly in the child.I'm cc'ing Carlton and Farhan for their thoughts, we may consider re-opening to add a note to the
{% partialdef %}docs clarifying that{% block %}tags inside a partial are not connected to the template inheritance chain.