#7324: {{ block.super }} doesn't work with nested {% block %} statements --------------------------------------+------------------------------------- Reporter: jeverling | Owner: nobody Status: closed | Milestone: Component: Template system | Version: SVN Resolution: invalid | Keywords: block.super template Stage: Unreviewed | Has_patch: 0 Needs_docs: 1 | Needs_tests: 0 Needs_better_patch: 0 | --------------------------------------+------------------------------------- Changes (by lanyjie):
* needs_docs: 0 => 1 Comment: There is lack of explicit specification on what should happen in the template system in some situations. The real issue here is this: when you have multiple definitions of the same block, what should happen? In the documentation, it simply says you should avoid such a situation in the same template, but when it happens, we should give a rule to resolve it. We first study the case when the definition of the same block is repeated in the child template (inheritance). The parent template comes first, and then the child template. And the implicit rule seems to be this: the first valid definition in the parent is the place holder (that is, whatever content is determined for this block shall be included in that place). The later definition will override the content, but not the location. So, this observation gives rise to a natural extension of this rule to resolve the issue of multiple definitions in a single file: the later definitions always override the content of the former ones, but only the first definition (note, this means no valid prior definitions exists) determines the place to include the final content. With this in mind, let's take a look at the test case above: {{{ {% extends "new/test.html" %} {% comment %}Gets around infinite recursion bug by namespacing with a directory{% endcomment %} {% block main %} Top-level main block {% comment %}remove this block.super and it all disappears. But I only want the block.super from inside "submain"{% endcomment %} {{ block.super }} {% block submain %} my new sub-content {{ block.super }} {% comment %}I expect this block.super to contain the content of "submain" from new/test.html, because I'm extending it. It is empty, UNLESS "main" has a block.super call, in which case it's echoed TWICE{% endcomment %} {% endblock %} {% endblock %} }}} First note that the {{ block.super }} will include a definition of submain block, and since we are redefining the block "main" here, so the previous definition of block "submain" loses its meaning as a place holder (it is location-invalid as its definition context is invalidated), but its content is still meaningful. In this quite interesting case, the newly included definition becomes the new place holder definition. Then the new definition of "submain" is the second one in this same file, and according to our extended rule, it will only override the content of the first definition, but will not change the location of the block, nor shall it repeat the content at its own location. Then the logical output of this template naturally follows. One more subtle issue here: what should the {{ block.super }} in the "submain" block be? Is it the content from the outer {{ block.super }}, or is it the one from the parent (note that the content there remains meaningful)? Well, it is probably not important here, as they are identical, but this is still an ambiguity that might cause trouble in other cases. One simple rule is: block.super always gives the content of the definition immediately precedes the current one, as the current one is overriding the former one. This is the rule I prefer, but people may go with the other way: that block.super always use the contents from the parent template. A problem with the latter approach is that we need new ways to access the contents of the same block defined earlier. Both ways yields the same result if no multiple definitions occur in a single template. I think multiple definitions in the same template might be useful as a content-holder, so that its contents may be used later through the block.super call as defined in the preferred way. It is then interesting to consider yet a slightly different situation: {{{ {% extends "new/test.html" %} {% block main %} Top-level main block {% block submain %} my new sub-content {{ block.super }} {% comment %} request the content of a previous definition (in the parent template), it is OK as the former definition can still be used as a content-holder. this one is the place-holder, as the former becomes place-invalid. {% endcomment %} {% endblock %} {{ block.super }} {% comment %} request the content of a previous definition (in the parent template), which includes another definition of the "submain" block, which shall only override the contents of the former definition. The net result is that the new content of "submain" defined above is lost, replaced by the old content! {% endcomment %} {% endblock %} }}} In summary, a block definition has two properties: place and content. We should consider them in terms of place-holders and content-holders, and they could be place- valid, content-valid, place-invalid and/or content-invalid. The first definition will be place- holders unless it becomes place-invalid when its context is redefined. A later definition will make the former ones content-invalid. But it only becomes place-holders if all former ones become place-invalid. Please also refer to ticket #13399 for more discussions. -- Ticket URL: <http://code.djangoproject.com/ticket/7324#comment:7> Django <http://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To post to this group, send email to django-upda...@googlegroups.com. To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-updates?hl=en.