Hi again,

One thing that I wasn't happy with in the implementation I posted yesterday 
was that you could not override templates included using 'use' in another 
child template. Effectively all blocks inside the 'use' tag and its 
included template where invisible outside of it. This needed to be the case 
so that you didn't get block names clashing with each other and could use 
the 'use' tag to include the same template with the same blocks overridden 
multiple times in one template

One potential solution to this is to enable blocks to have namespaces, so 
for example if you had the template:

# page_heading.html
<div class="page-heading">
    <h1>{% block heading %}My Heading{% endblock %}</h1>
    <h2>{% block sub_heading %}My Subheading{% endblock %}<h2>
</div>

and included it a template such as (note the 'ns page_heading'):

# base_page.html
...
{% use 'page_heading.html' ns page_heading %}
    <h1>{% block heading %}Basic Page Heading{% endblock %}</h1>
{% enduse %}
...

You could then override the 'heading' block in a child template of 
'base_page.html' by doing:

# actual_page.html
{% extends 'base_page.html' %}
{% block page_heading.heading %}Basic Page Heading{% endblock %}

I have updated my implementation to support this here: 
https://gist.github.com/samwillis/af3992f69c2597a16252

It requires that the BlockContext supports namespaces, in my implementation 
there is NsBlockContext which is patched in when required but if this was 
accepted into core then NsBlockContext would replace BlockContext.

This is (almost) fully backwards compatible with existing code as blocks 
already named with periods will just end up in a namespace but continue to 
function fully. The only exception is if you have blocks named both 
'global.block_name' and 'block_name' as these would now address the same 
block. We could give the global namespace a more obscure name (such as 
'__global__') to prevent this but it would make the trick below more clunky.

One interesting use for the 'use' tag with this addition is breaking up 
more complex templates into multiple files. While researching various 
options before developing this I found allot of people discovering that you 
couldn't override a block inside an 'include'ed template. With this 'use' 
tag you would be able to do this, for example you could have base templates 
like this:

# base.html
<html>
<head>
    {% use 'head.html' ns global %}{% enduse %}
</head>
<body>
 ...
</body>
</html>

# head.html
<title>{% block title %}{% endblock %}</title>

and the page template:

# actual_page.html
{% extends 'base.html' %}
{% block title %}My Page Title{% endblock %}

If we switched the 'use' tag to use a namespace other than global:

{% use 'head.html' ns html_head %}{% enduse %}

The page template would then be:

# actual_page.html
{% extends 'base.html' %}
{% block html_head.title %}My Page Title{% endblock %}

I think this will provide very useful in structuring complex templates.

Maybe with this functionality the tag should be called 'embed'?

What do you think?


Sam


On Thursday, September 4, 2014 5:28:34 PM UTC+1, Sam Willis wrote:
>
> Curtis,
>
> You are welcome to include it in your project and I'm happy to help out. 
> Depending on what happens here I may still release it as a simple 
> standalone app though.
>
> I do think this is the kind of thing that would do best in core though as 
> it would ensure that there was a standardised patten for creating these 
> reusable template components.
>
>
> Marc,
>
> I am happy to have a look around (and have already to some extent when 
> developing this) and put together a review of the various existing options. 
> This is my first foray into contributing to Django and so I am keep to help 
> in any way.
>
> Does anyone know of anything particular I should be looking at?
>
>
>
> On Thursday, September 4, 2014 2:06:15 PM UTC+1, Marc Tamlyn wrote:
>>
>> I would like to see someone do a review of the various third party 
>> implementations of concepts like this, I think there's a place in core for 
>> some variant, it's just working out which one the "right" one is.
>>
>> The other issue with adding new tags to core (especially with "common" 
>> names) is name clashes with third party code. This shouldn't be too 
>> significant though if we have enough use.
>>
>>
>> On 4 September 2014 12:09, Josh Smeaton <[email protected]> wrote:
>>
>>> I really like this idea, and have wanted something similar every time I 
>>> start a new project and begin building out the main template. I think 
>>> including this (or something like this) in core is a great idea. Just 
>>> because it *can* be implemented in 3rd party code, doesn't mean it has to 
>>> be.
>>>
>>>
>>> On Thursday, 4 September 2014 02:10:33 UTC+10, Sam Willis wrote:
>>>>
>>>>  Hi All,
>>>>
>>>> I would like to propose a new template tag to be included in Django, it 
>>>> is sort of a cross between 'include' and 'extends'. You can find an 
>>>> implementation here: https://gist.github.com/
>>>> samwillis/af3992f69c2597a16252
>>>>
>>>> The main use case for this tag is being able to create reusable 
>>>> 'components' for rendering a website. Say for example a page header, a 
>>>> panel with headers and footers, or a modal window (as seen in the 
>>>> Bootstrap 
>>>> framework). Rather than needing to repeat the html everywhere you need it 
>>>> and having to search out all occurrences to make a change to the structure 
>>>> you can create a simple template and include it.
>>>>
>>>> To some extent this can currently be done with either an included 
>>>> template using the '{% include "template.html" with var="value" %}' syntax 
>>>> or using a custom template tag. However, the former isn't suitable for 
>>>> changing whole blocks in the include template, and the latter can be 
>>>> overkill and may not be suitable for a designer with little knowledge of 
>>>> Python and the Django Template API.
>>>>
>>>> The 'use' tag loads a template and renders it with the current context 
>>>> similar to the 'include' tag. You can pass additional context using 
>>>> keyword 
>>>> arguments as well as override blocks in the included template.
>>>>
>>>> Example (simple) template:
>>>>
>>>> <div class="page-heading {{ extra_class }}">
>>>>     <h1>{% block heading %}{% endblock %}</h1>
>>>> </div>
>>>>
>>>> Example 'use' tag use with the above template:
>>>>
>>>> {% use "page_header.html" %}
>>>>     {% block heading %}Some Title{% endblock %}
>>>> {% enduse %}
>>>>
>>>> {% use "page_header.html" with extra_class="large" %}
>>>>     {% block heading %}Some Title{% endblock %}
>>>> {% enduse %}
>>>>
>>>> As with 'include' use the 'only' argument to exclude the current 
>>>> context when rendering the included template:
>>>>
>>>> {% use "page_header.html" only %}
>>>>     {% block heading %}Some Title{% endblock %}
>>>> {% enduse %}
>>>>
>>>> {% use "page_header.html" with extra_class="large" only %}
>>>>     {% block heading %}Some Title{% endblock %}
>>>> {% enduse %}
>>>>
>>>> The included template receives an additional context variable called 
>>>> 'used_blocks' which is a Dict indicating which blocks were overridden in 
>>>> the 'use' tag. Using this you can conditionally show content around the 
>>>> block. For example, if you had this template for generating a page heading:
>>>>
>>>> <div class="page-heading">
>>>>     <h1>{% block heading %}{% endblock %}</h1>
>>>>     {% if used_blocks.sub_heading %}
>>>>         <h2>{% block sub_heading %}{% endblock %}<h2>
>>>>     {% endif %}
>>>> </div>
>>>>
>>>> and included it using:
>>>>
>>>> {% use "page_header.html" %}
>>>>     {% block heading %}My Page Title{% endblock %}
>>>> {% enduse %}
>>>>
>>>> it would exclude the '<h2>' tags from the empty subheading.
>>>>
>>>> Finally, as syntactic sugar if you are just overriding a single block 
>>>> you can express it as:
>>>>
>>>> {% use "page_header.html" block heading %}
>>>>     My Page Title
>>>> {% enduse %}
>>>>
>>>> These example are a little simple, but this could be incredibly useful 
>>>> for more complex components such a modal windows.
>>>>
>>>> I have made a first pass at an implementation here: 
>>>> https://gist.github.com/samwillis/af3992f69c2597a16252.
>>>>
>>>> Although I have implemented this with the 'use' word, there may be a 
>>>> better word. I considered 'embed' but thought 'use' was a little cleaner
>>>>
>>>> Thanks,
>>>> Sam
>>>>
>>>>  -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "Django developers" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to [email protected].
>>> To post to this group, send email to [email protected].
>>> Visit this group at http://groups.google.com/group/django-developers.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/django-developers/bb252615-f881-4233-a69b-ae40faf3a694%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/django-developers/bb252615-f881-4233-a69b-ae40faf3a694%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/734df53e-344a-445e-b6b0-94b630ca77b1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to