Template refactor

334 views
Skip to first unread message

Gary Reynolds

unread,
May 4, 2012, 7:43:15 PM5/4/12
to mezzani...@googlegroups.com
Hi everyone,

I have just forked new repositories on bitbucket for both Mezzanine and Cartridge to make a change I've discussed with Stephen to hopefully make template customisations better across the project.

In general, my philosophy on templates is that a reusable application should have sensible {% block %} elements to allow a third party to easily override just that portion of the bundled template. Unfortunately this is in direct competition to the way Django's template engine works because if you attempt to simply extend the template you want to override from the reusable application, you end up with a circular dependancy.

Enter the approach I'm championing… lets say I have a template I want to provide called foo.html, which might look like this:

{% extends "base.html" %}

{% block title %}Welcome {{ request.user.first_name }}{% endblock %}
{% block main %}
<h1>Foo!</h1>
{% endblock %}

In you application you want to just change the title block. You wouldn't be able to do this:

{% extends "foo.html" %}
{% block title %}G'day, {{ request.user.username }}{% endblock %}

due to the circular nature of this definition. So instead in the library we actually provide two templates. The first snippet above would infact reside in _foo.html and then foo.html would contain nothing more than:

{% extends "_foo.html" %}

This might look like extra work, and it is. If you were writing an application that wasn't being reused, I would not recommend it as an approach. However, the beauty is that now to override foo.html our user can do:

{% extends "_foo.html" %}
{% block title %}G'day, {{ request.user.username }}{% endblock %}

The repositories can be found at:
What I'd particularly like assistance with is adding {% block %} sections to the base templates at places which an end user might reasonably like to change the output.

Hopefully this will make the lives of UI developers easier, as they won't have to copy base templates just to make minor changes, or do the god-awful symlink dance that I've seen used as well.

Cheers,
Gary

Stephen McDonald

unread,
May 4, 2012, 8:20:57 PM5/4/12
to mezzani...@googlegroups.com
Would really love to hear others' opinions on this change. It technically makes sense to me, and it's technically quite simple, but feels very large and sweeping due to touching all of the templates. Just looking for any caveats or drawbacks that might not come to mind right away. 

There's at least an extra level of complexity (or "mental step" might be a better term) now when getting your head around the template structure. This might be nothing for some people, and large for others. I'm wondering if it takes away from the simplicity of working with templates for the sake of flexibility. Well, it does, what I'm really wondering is if it's a big deal or not, and which is more important.

As with any large changes, the collective opinion of anyone with a voice on here is what will drive the decisions, so if we can at least get some + or - 1's that'd be really helpful.
--
Stephen McDonald
http://jupo.org

Nicola Larosa

unread,
May 5, 2012, 4:55:13 AM5/5/12
to mezzani...@googlegroups.com
[Uhm, this top-posting business plus bad HTML quoting makes replying more
laborious than necessary.]

> Gary Reynolds wrote:
>> lets say I have a template I want to provide called foo.html, which
>> might look like this:
>> [snip]
>> In you application you want to just change the title block. You
>> wouldn't be able to do this:
>>
>> {% extends "foo.html" %}
>> {% block title %}G'day, {{ request.user.username }}{% endblock %}
>>
>> due to the circular nature of this definition.

It's definitely me being thick, but it took a while to understand what
you meant by "circular nature". It's that this template fragment is going
to be put in a file also named "foo.html", right? It seems obvious after
realizing it, but for some reason it took a while. :-)


>> So instead in the library we actually provide two templates. The
>> first snippet above would infact reside in _foo.html and then
>> foo.html would contain nothing more than:
>>
>> {% extends "_foo.html" %}

How about using a more meaningful prefix or suffix, like "def_foo.html"
or "foo_def.html" or "orig_foo.html" or "foo_orig.html" or
"mezz_foo.html" or "foo_mezz.html"?


Stephen McDonald wrote:
> Would really love to hear others' opinions on this change. It
> technically makes sense to me, and it's technically quite simple, but
> feels very large and sweeping due to touching all of the templates.

It's a general principle, so you need to document it once, and apply it
only where needed: maybe not all templates need to be split this way, and
there are some that are not going to ever be overridden (famous last
words :-) ).

--
Nicola Larosa - http://www.tekNico.net/

Everywhere they go, women are being told over and over again, "You are
not good enough. You do not match up. You are flawed." Now remember,
this is key - telling women that they are flawed is key to capitalism.
- Gail Dines, December 2011

Stephen McDonald

unread,
May 5, 2012, 5:12:48 AM5/5/12
to mezzani...@googlegroups.com
On Sat, May 5, 2012 at 6:55 PM, Nicola Larosa <nicola...@gmail.com> wrote:
[Uhm, this top-posting business plus bad HTML quoting makes replying more
laborious than necessary.]

> Gary Reynolds wrote:
>> lets say I have a template I want to provide called foo.html, which
>> might look like this:
>> [snip]
>> In you application you want to just change the title block. You
>> wouldn't be able to do this:
>>
>> {% extends "foo.html" %}
>> {% block title %}G'day, {{ request.user.username }}{% endblock %}
>>
>> due to the circular nature of this definition.

It's definitely me being thick, but it took a while to understand what
you meant by "circular nature". It's that this template fragment is going
to be put in a file also named "foo.html", right? It seems obvious after
realizing it, but for some reason it took a while. :-)

This is what I was referring to as the extra mental step. I had to think about the structure for a bit before it clicked, but once it did it makes sense. I guess what I was getting at is how many people will this happen for, and how big a step is it really. It'll vary across people I guess.
 


>> So instead in the library we actually provide two templates. The
>> first snippet above would infact reside in _foo.html and then
>> foo.html would contain nothing more than:
>>
>> {% extends "_foo.html" %}

How about using a more meaningful prefix or suffix, like "def_foo.html"
or "foo_def.html" or "orig_foo.html" or "foo_orig.html" or
"mezz_foo.html" or "foo_mezz.html"?


I've seen the underscores before in other apps, so I think it's as close to a standard as there is. Maybe base_blah.html
 

Stephen McDonald wrote:
> Would really love to hear others' opinions on this change. It
> technically makes sense to me, and it's technically quite simple, but
> feels very large and sweeping due to touching all of the templates.

It's a general principle, so you need to document it once, and apply it
only where needed: maybe not all templates need to be split this way, and
there are some that are not going to ever be overridden (famous last
words :-) ).

It will definitely need to be in the docs. Perhaps in the FAQs: "What's with all the templates prefixed with underscores?"

I was a bit put off too by this being applied to every single template. There's something to be said for consistency though I guess.
 

--
Nicola Larosa - http://www.tekNico.net/

Everywhere they go, women are being told over and over again, "You are
not good enough. You do not match up. You are flawed." Now remember,
this is key - telling women that they are flawed is key to capitalism.
 - Gail Dines, December 2011

Etienne B. Roesch

unread,
May 5, 2012, 5:27:54 AM5/5/12
to mezzani...@googlegroups.com

On 5 May 2012, at 10:12, Stephen McDonald wrote:

> On Sat, May 5, 2012 at 6:55 PM, Nicola Larosa <nicola...@gmail.com> wrote:
>> [Uhm, this top-posting business plus bad HTML quoting makes replying more
>> laborious than necessary.]

Btw, what is the policy on this mailing list? top or bottom responses?


> [snip]
>
>> It's definitely me being thick, but it took a while to understand what
>> you meant by "circular nature". It's that this template fragment is going
>> to be put in a file also named "foo.html", right? It seems obvious after
>> realizing it, but for some reason it took a while. :-)
>>
> This is what I was referring to as the extra mental step. I had to think about the structure for a bit before it clicked, but once it did it makes sense. I guess what I was getting at is how many people will this happen for, and how big a step is it really. It'll vary across people I guess.

Aaaah, right, now I get it, took a while. For me, as a newbie to both django and mezzanine, and avid programmer, it did not shock me that foo.html would extend foo.html, as it somehow registered in my mind that these were different files, they sit in different places anyway, but I do understand that it could get confusing.


> How about using a more meaningful prefix or suffix, like "def_foo.html"
> or "foo_def.html" or "orig_foo.html" or "foo_orig.html" or
> "mezz_foo.html" or "foo_mezz.html"?

I'd cast my humble newbie vote for mezz_foo.html, if you were to decide to go the prefix route.
(and yes, it does sound like a tedious job to change it all to mezz_xxx.html everywhere; maybe worth dividing tasks to people? I volunteer, but I'd understand if you'd rather involve more expert volunteers :) ..)

Have a great weekend!

Etienne

Stephen McDonald

unread,
May 5, 2012, 5:32:47 AM5/5/12
to mezzani...@googlegroups.com
On Sat, May 5, 2012 at 7:27 PM, Etienne B. Roesch <etienne...@gmail.com> wrote:

On 5 May 2012, at 10:12, Stephen McDonald wrote:

> On Sat, May 5, 2012 at 6:55 PM, Nicola Larosa <nicola...@gmail.com> wrote:
>> [Uhm, this top-posting business plus bad HTML quoting makes replying more
>> laborious than necessary.]

Btw, what is the policy on this mailing list? top or bottom responses?

There's no policy :-)
 


> [snip]
>
>> It's definitely me being thick, but it took a while to understand what
>> you meant by "circular nature". It's that this template fragment is going
>> to be put in a file also named "foo.html", right? It seems obvious after
>> realizing it, but for some reason it took a while. :-)
>>
> This is what I was referring to as the extra mental step. I had to think about the structure for a bit before it clicked, but once it did it makes sense. I guess what I was getting at is how many people will this happen for, and how big a step is it really. It'll vary across people I guess.

Aaaah, right, now I get it, took a while. For me, as a newbie to both django and mezzanine, and avid programmer, it did not shock me that foo.html would extend foo.html, as it somehow registered in my mind that these were different files, they sit in different places anyway, but I do understand that it could get confusing.


> How about using a more meaningful prefix or suffix, like "def_foo.html"
> or "foo_def.html" or "orig_foo.html" or "foo_orig.html" or
> "mezz_foo.html" or "foo_mezz.html"?

I'd cast my humble newbie vote for mezz_foo.html, if you were to decide to go the prefix route.
(and yes, it does sound like a tedious job to change it all to mezz_xxx.html everywhere; maybe worth dividing tasks to people? I volunteer, but I'd understand if you'd rather involve more expert volunteers :) ..)

If you look at Gary's original post in this thread, he's already done the work. Thanks for the offer though.
 

Have a great weekend!

Etienne

Stephen McDonald

unread,
May 5, 2012, 5:51:52 AM5/5/12
to mezzani...@googlegroups.com
Couple more thoughts:

How would this affect the experience of the collecttemplates command? Needs a lot of thought. If we only copy blah.html (not _blah.html) then the developer gets an almost empty file. If we copy _blah.html then they lose the notion of being able to use blah.html extending _blah.html - if we give them both then it may be overkill, eg: "what are all these extra files? I only want one for each template".

And here's a crazy idea: what if we extend and replace Django's extend tag with our own that allows for circular references. I may be missing something, but taking a look at the source for extends, it doesn't seem like it would be too hard. So if page.html extends page.html, we just ensure that the physical path of the extending template isn't searched for when looking for the version to extend from. It might not even be possible.

On Sat, May 5, 2012 at 9:43 AM, Gary Reynolds <gary.r...@touchtechnology.com.au> wrote:

Gary Reynolds

unread,
May 5, 2012, 9:47:00 AM5/5/12
to mezzani...@googlegroups.com
I'll try and answer inline to each comment rather than top posting ;)
It's definitely me being thick, but it took a while to understand what
you meant by "circular nature". It's that this template fragment is going
to be put in a file also named "foo.html", right? It seems obvious after
realizing it, but for some reason it took a while. :-)
This is what I was referring to as the extra mental step. I had to think about the structure for a bit before it clicked, but once it did it makes sense. I guess what I was getting at is how many people will this happen for, and how big a step is it really. It'll vary across people I guess.
Sure, I can appreciate that it is not immediately obvious, which is why…
It will definitely need to be in the docs. Perhaps in the FAQs: "What's with all the templates prefixed with underscores?"
It's not documented in my fork yet, but it most certainly needs to be. Before we write the documentation though, I'd like us to commit to a specific approach first of all.
Aaaah, right, now I get it, took a while. For me, as a newbie to both django and mezzanine, and avid programmer, it did not shock me that foo.html would extend foo.html, as it somehow registered in my mind that these were different files, they sit in different places anyway, but I do understand that it could get confusing.
Well, they are different files; but they reside at the same/conflicting level in the template hierarchy and asking foo.html to extend foo.html is nonsense.
It's a general principle, so you need to document it once, and apply it
only where needed: maybe not all templates need to be split this way, and
there are some that are not going to ever be overridden (famous last
words :-) ).
I was a bit put off too by this being applied to every single template. There's something to be said for consistency though I guess.
I disagree that it should only be applied where needed - I believe it should be applied universally, otherwise we only complicate matters when it comes time to document it and ask for buy in. I also feel that if some templates are to be excluded from receiving the treatment then we should justify why this is so. And what of any new templates in the future, should they adopt the approach or not?

I think applying the rule even handedly actually makes the concept easier to grasp overall.
How about using a more meaningful prefix or suffix, like "def_foo.html"
or "foo_def.html" or "orig_foo.html" or "foo_orig.html" or
"mezz_foo.html" or "foo_mezz.html"?
I've seen the underscores before in other apps, so I think it's as close to a standard as there is. Maybe base_blah.html
I adopted the approach of the underscore from a suggestion I read a couple of years ago that encouraged users to symlink the original template as _original.html (assuming original.html) and to then extend it. It made sense, but irritated me that a supposedly reusable app needed this step.

In my head I like to think of the leading underscore like private method names. We're providing the default functionality, and we allow you to call into the template and replace just the pieces you need. I don't think the extra few characters in the filename add much value, particularly when we add documentation which explains the convention.
How would this affect the experience of the collecttemplates command? Needs a lot of thought. If we only copy blah.html (not _blah.html) then the developer gets an almost empty file. If we copy _blah.html then they lose the notion of being able to use blah.html extending _blah.html - if we give them both then it may be overkill, eg: "what are all these extra files? I only want one for each template".
I dislike the collecttemplates command and would actively discourage it's use. Rather, I the templates should be better documented - we should advise developers as to what templates are used by which views.

The information that django-debug-toolbar Templates panel provides would form great basis for this. Particularly the template and context that is made available.
And here's a crazy idea: what if we extend and replace Django's extend tag with our own that allows for circular references. I may be missing something, but taking a look at the source for extends, it doesn't seem like it would be too hard. So if page.html extends page.html, we just ensure that the physical path of the extending template isn't searched for when looking for the version to extend from. It might not even be possible.
From my earlier attempts at this in another project, I don't think it is possible - from https://docs.djangoproject.com/en/1.3/topics/templates/#template-inheritance
  • If you use {% extends %} in a template, it must be the first template tag in that template. Template inheritance won't work, otherwise.
I'm glad we've got some lively discussion on the topic anyway, looking forward to more.

Gary

Stephen McDonald

unread,
May 5, 2012, 6:06:44 PM5/5/12
to mezzani...@googlegroups.com
Must...resist...the top-posting :P

I think we agree here at least that the two features work against each other. If we go down the "_name.blah" path (we should give this approach a name) then we should probably get rid of collecttemplates.
 

The information that django-debug-toolbar Templates panel provides would form great basis for this. Particularly the template and context that is made available.
And here's a crazy idea: what if we extend and replace Django's extend tag with our own that allows for circular references. I may be missing something, but taking a look at the source for extends, it doesn't seem like it would be too hard. So if page.html extends page.html, we just ensure that the physical path of the extending template isn't searched for when looking for the version to extend from. It might not even be possible.
From my earlier attempts at this in another project, I don't think it is possible - from https://docs.djangoproject.com/en/1.3/topics/templates/#template-inheritance
  • If you use {% extends %} in a template, it must be the first template tag in that template. Template inheritance won't work, otherwise.
I'm glad we've got some lively discussion on the topic anyway, looking forward to more.

Me too! Thanks for the great feedback Gary.
 

Gary

Josh Cartmell

unread,
May 5, 2012, 6:16:10 PM5/5/12
to mezzani...@googlegroups.com
So it took me a few minutes to understad how this worked, but I agree with Steve that once I got it it made sense.  The biggest problem I see with it is that it will create an entry barrier for other Django developers as it works differently than what you would traditionally see in a Django app.

A thought I had to make extending easier without adding syntax that is not always easy to understand is the following:

Move all templates, in mezzanine, to a directory called mezzanine.  So instead of index.html and pages/page.html etc... we would have mezzanine/index.html and mezzanine/pages/page.html etc...

If you were visiting the index page we would still ask Django for index.html (not mezzanine/index.htlm).  Then in the mezzanine template middleware we could add mezzanine/template_name.html to the path.  So first Django would look for index.html, then mezzanine/index.html (this would be similar to the way we can add specific device or host templates).

If you wanted to extend index.html you would simply make a template called index.html that looked like this:

{% extends "mezzanine/index.html" %}
...
your template
...

You could put anything you wanted in there because there would be no circular import (extending mezzanine/index.html rather than index.html).  If you didn't create your own index.html it wouldn't matter because the middleware would make it so that Django looked for index.html and mezzanine/index.html

You would also be free to create an index.html and not extend mezzanine/index.html because index.html would come before mezzanine/index.html in the template search.

I got the idea for this based on the way django allows you to override admin templates on a per app basis :

What do you guys think?  I think this preserves all the power of Gary's idea without making things more confusing.

Ken Bolton

unread,
May 5, 2012, 6:28:10 PM5/5/12
to mezzani...@googlegroups.com
yes please

Gary Reynolds

unread,
May 5, 2012, 6:40:16 PM5/5/12
to mezzani...@googlegroups.com
On Sunday, 6 May 2012 at 8:16 AM, Josh Cartmell wrote:
You could put anything you wanted in there because there would be no circular import (extending mezzanine/index.html rather than index.html).  If you didn't create your own index.html it wouldn't matter because the middleware would make it so that Django looked for index.html and mezzanine/index.html
I'm not convinced that there is any less of a conceptual jump here simply by prefixing the template filename with mezzanine (or cartridge in that related project) and keeping the two files side-by-side rather than hiding the "default" file in a lower level directory.

However it does make it slightly more tedious to look up a file in a different directory, rather than a sibling with the same name in the same directory?
You would also be free to create an index.html and not extend mezzanine/index.html because index.html would come before mezzanine/index.html in the template search.
Sure, in fact mezzanine/index.html will never be in the template search - it would only get loaded when asked for by an extends tag.
I got the idea for this based on the way django allows you to override admin templates on a per app basis :

What do you guys think?  I think this preserves all the power of Gary's idea without making things more confusing.
No matter the approach, template editors will need to have an understanding of template inheritance. At the moment they don't get the opportunity to exploit it's benefits because collectstatic drops the whole template across. Worrying too much about the name/path of the parent file feels a bit like bike-shedding. Once a pattern is decided upon it will take the same amount of brain power to take advantage of it.

Having said that, I'm happy to amend the patch to this convention if that is consensus, though.

Gary Reynolds

unread,
May 5, 2012, 6:53:41 PM5/5/12
to mezzani...@googlegroups.com
On Sunday, 6 May 2012 at 8:16 AM, Josh Cartmell wrote:
Move all templates, in mezzanine, to a directory called mezzanine.  So instead of index.html and pages/page.html etc... we would have mezzanine/index.html and mezzanine/pages/page.html etc...
Actually, I have an argument against this on further thought.

When the default template is index.html then it seems to make sense, but lets expose multiple depth templates in the two scenarios.

Current proposal:

index.html -> _index.html (0)
page/page.html -> page/_page.html (0)
gallery/album/index.html -> gallery/album/_index.html (0)

Counter proposal:

index.html -> mezzanine/index.html (1)
page/page.html -> mezzanine/page/page.html (2)
gallery/album/index.html -> mezzanine/gallery/album/index.html (3)

The number of brackets are the additional number of directories and "distance" from the original file. Computationally there is no difference, Django template resolution will deal with this just fine.

However I tend to think that since they are so tightly coupled, they should reside together. Also, when you look at django-debug-toolbar output, the template inheritance would look like this (using my fictitious gallery/album/index.html example):

.../gallery/album/index.html
.../mezzanine/gallery/album/index.html
.../gallery/album/base.html
.../mezzanine/gallery/album/base.html
.../gallery/base.html
.../mezzanine/gallery/base.html
.../base.html
.../mezzanine/base.html

rather than

.../gallery/album/index.html
.../gallery/album/_index.html
.../gallery/album/base.html
.../gallery/album/_base.html
.../gallery/base.html
.../gallery/_base.html
.../base.html
.../_base.html

I think the latter (my current proposal) is conceptually cleaner. Maybe that is the programmer as opposed to designer in me? Is there something scary about the underscores?

Gary

Josh Cartmell

unread,
May 5, 2012, 7:25:32 PM5/5/12
to mezzani...@googlegroups.com
Hmm, I still think that my proposal is a bit different than yours.

The way I outlined things you wouldn't necessarily have to create an index.html that looked like this:

{% extends "mezanine/index.html" %}

Mezzanine would simply look for index.html and failing that it would look for mezzanine/index.html.  I mentioned a middleware in my response but this could also be implemented in a custom mezzanine template loader, or any other feasible way.  Using this method we wouldn't have to create two templates for every template which is what introduced the confusion for me.  Handling collecttemplates would also be easy as they could be copied as normal, and just remove the mezzanine prefix from the path.  Then we could document that if you only want to override parts of a template throw in {% extends mezzanine/whatever.html %} and delete the parts of the template you don't want to override.

My idea is definitely conceptually based on yours, just implemented a bit differently.  I really do like your idea and the additional power it can bring, I just think it could be a bit confusing and potentially create a mental barrier when moving from working on a project that uses it to one that doesn't (like most other django stuff).  I also think it would be nice to not have to create all the duplicate templates.  The way the template inheritance would look in my proposal doesn't bother me personally but if it did bother a lost of people than I would agree that maybe it wouldn't be the best approach.

Josh Cartmell

unread,
May 5, 2012, 7:26:46 PM5/5/12
to mezzani...@googlegroups.com
I forgot to mention but I think there is something a bit scary about the underscores, I'm not sure what it is, probably just the fact that it is different than normal =)

Joe Julian

unread,
May 5, 2012, 8:19:32 PM5/5/12
to mezzani...@googlegroups.com
I agree. Though I have no fear of, and they conceptually suggest an internal object, using underscores, I have to agree that a "template path" seems more Django-like to me. Taking that a step further, this also opens up the opportunity to publish other templates. They would also be added in middleware. My Pixel template would extend the mezzanine template, and your site template could further extend my Pixel one. It makes sense to me.

Josh Cartmell <joshc...@gmail.com> wrote:

>So it took me a few minutes to understad how this worked, but I agree with
>Steve that once I got it it made sense. The biggest problem I see with it
>is that it will create an entry barrier for other Django developers as it
>works differently than what you would traditionally see in a Django app.
>
>A thought I had to make extending easier without adding syntax that is not
>always easy to understand is the following:
>

>Move all templates, in mezzanine, to a directory called mezzanine. So
>instead of index.html and pages/page.html etc... we would have
>mezzanine/index.html and mezzanine/pages/page.html etc...
>

>If you were visiting the index page we would still ask Django for
>index.html (not mezzanine/index.htlm). Then in the mezzanine template
>middleware we could add mezzanine/template_name.html to the path. So first
>Django would look for index.html, then mezzanine/index.html (this would be
>similar to the way we can add specific device or host templates).
>
>If you wanted to extend index.html you would simply make a template called

>index.html that looked like this:
>

>{% extends "mezzanine/index.html" %}
>...
>your template
>...
>

>You could put anything you wanted in there because there would be no
>circular import (extending mezzanine/index.html rather than index.html).
> If you didn't create your own index.html it wouldn't matter because the
>middleware would make it so that Django looked for index.html and
>mezzanine/index.html
>

>You would also be free to create an index.html and not extend
>mezzanine/index.html because index.html would come before
>mezzanine/index.html in the template search.
>

>I got the idea for this based on the way django allows you to override
>admin templates on a per app basis :
>https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
>
>What do you guys think? I think this preserves all the power of Gary's
>idea without making things more confusing.
>

>> - If you use {% extends %} in a template, it must be the first

Lee Matos

unread,
May 5, 2012, 8:35:36 PM5/5/12
to mezzani...@googlegroups.com
I'm not sure what you mean by circular importing? I thought I had a decent handle on django tempting and imports/extending/overriding and this doesn't seem to be solving anything for me. Is this being used anywhere else across the Django community? If it's not something that is widely used/ miles better than the current solution, I think it could be a stumbling block for new users as well. Can someone try and explain what circular dependency issue we are looking to solve? I'm genuinely curious but slightly confused as I'm being blinded by "the magic" at hand. :) I'm not trying to flame and I'm not saying this is necessarily a bad idea, I'm just not sure of the implications.

-Lee

Stephen McDonald

unread,
May 5, 2012, 8:47:40 PM5/5/12
to mezzani...@googlegroups.com
I'll have a crack at it:

* page view looks for page.html - uses the version in the project's templates directory, otherwise app directory (probably in Mezzanine)
* developer wants to customize page.html in their project, so they copy it to the project's template directory
* they only want to modify one block in it, not copy the entire template, which may include a lot of functionality, that could change in future versions.
* they can't have proj/templates/page.html extend the app version of page.html, Django doesn't know how to deal with extending the same template name/path
* proposed solution: view still looks for page.html, but app's page.html has one line: {% extends "_page.html" %}, and all the functionality lives in _page.html in the app
* developer can then in their project's templates directory, either have page.html with {% extends "_page.html" %} and overriding only the block they need, or _page.html and reimplement the page's functionality entirely, depending on their needs (this is what currently occurs btw)

Current discussion are around:

* is this separation confusing - something that will definitely vary dev to dev. There's no question around the benefit it provides, it's a very good thing.
* naming convention - should it be something other than _name.html, perhaps in a different directory, perhaps requiring middleware
* can we modify the "extends" template tag, to allow this to occur without splitting things out. eg: page.html in proj/templates can {% extend "page.html" %} and the app version will be extended.

If I've missed anything please correct me.

Stephen McDonald

unread,
May 5, 2012, 8:51:52 PM5/5/12
to mezzani...@googlegroups.com
Also discussed: the bearing this has on the collecttemplates command. If every view has two templates, do we copy both? One or the other? Do we drop the command from the project?

Stephen McDonald

unread,
May 5, 2012, 9:01:44 PM5/5/12
to mezzani...@googlegroups.com
Debating the naming convention might seem like bikeshedding, but I think it's really important. If one approach clearly communicates the intention and another doesn't, then it's worthwhile discussing it.

So here's another idea: instead of page.html and _page.html, we use page.html and page.base.html - this way at least all the template lines up together in a large directory listing, and it clearly indicates the intention. I was first thinking page.html.base which would line up even close, but you'd lose syntax highlighting in your editor.

Gary Reynolds

unread,
May 6, 2012, 4:10:35 AM5/6/12
to mezzani...@googlegroups.com
I think page.base.html is okay as a compromise (although I think base.base.html looks bit funny!). My strongest objection for any of the alternatives would be with prefixing the path; I think it's important that the templates reside alongside each other.

I'd be against adding a middleware, we don't need to complicate it any more when it can be done easily using nothing more than "traditional" inheritance with a less-traditional hierarchy to provide greater template flexibility.

In a nutshell those are my two biggest points for the contribution.

Stephen McDonald

unread,
May 6, 2012, 4:12:07 AM5/6/12
to mezzani...@googlegroups.com
Yeah I'd like to avoid middleware for this if possible.

Josh Cartmell

unread,
May 6, 2012, 1:20:03 PM5/6/12
to mezzani...@googlegroups.com
I admit defeat =)

The more I think about it adding another middleware probably wouldn't be the best solution.  The only other way I can imagine my proposal working would be having every Mezzanine view add multiple template to the search path and that might be to clunky, what do you think?

I have a couple of comments on the proposal (index.html and index.base.html):

Does it make more sense to have the default index.html (or any template) be:

{% extends "index.base.html" %}

or 

{% include "index.base.html" %}

I think they will produce the same result but I am wondering if one is semantically more correct?

My other comment is about collecttemplates.  I don't think copying both templates is a good idea as that in my mind at least partially defeats the purpose of doing this in the first place.  For example if you override the main block in a template but not some other block, and then you pull in Mezzanine changes you could any updates to blocks besides main without having to modify your templates.  If both templates had been copied this wouldn't be true.

I think it should work so that if you ask it to copy index.html it actually makes a copy of index.base.html, renames it to index.html and adds

{% extends "index.base.html" %}

and leaves index.base.html's extends in place (commented out)

{# {% extends "whatever index.base.html extends" %} #}

Then a comment should be placed directly beneath with something to the effect of:
If you only want to override specific blocks use the first extends and leave only those blocks you want to override.  If you want to completely override the template use the second extends (or none) and do whatever you want.  Feel free to delete this comment and the extends you are not using.

I think the collecttemplates command is quite useful and having it do something like I outlined would help people understand this new template inheritance and why they should use it.  I think including both extends would help people know their options and do exactly what they want (similar to the multiple commented out home page options in the default projects urls).  Does anyone else have thoughts on this, or how they imagine collecttemplates working?

Stephen McDonald

unread,
May 6, 2012, 4:43:12 PM5/6/12
to mezzani...@googlegroups.com
On Mon, May 7, 2012 at 3:20 AM, Josh Cartmell <joshc...@gmail.com> wrote:
I admit defeat =)

The more I think about it adding another middleware probably wouldn't be the best solution.  The only other way I can imagine my proposal working would be having every Mezzanine view add multiple template to the search path and that might be to clunky, what do you think?

I have a couple of comments on the proposal (index.html and index.base.html):

Does it make more sense to have the default index.html (or any template) be:

{% extends "index.base.html" %}

or 

{% include "index.base.html" %}

I think they will produce the same result but I am wondering if one is semantically more correct?

As I understand it they'll produce the same result only in the app versions of the templates where that's the only line in the file. If it's actually being used beyond (most likely in the project's templates dir) then using include wouldn't make any sense. Might as well have the app versions use the intended approach with extends.
 

My other comment is about collecttemplates.  I don't think copying both templates is a good idea as that in my mind at least partially defeats the purpose of doing this in the first place.  For example if you override the main block in a template but not some other block, and then you pull in Mezzanine changes you could any updates to blocks besides main without having to modify your templates.  If both templates had been copied this wouldn't be true.

I think it should work so that if you ask it to copy index.html it actually makes a copy of index.base.html, renames it to index.html and adds

{% extends "index.base.html" %}

and leaves index.base.html's extends in place (commented out)

{# {% extends "whatever index.base.html extends" %} #}

Then a comment should be placed directly beneath with something to the effect of:
If you only want to override specific blocks use the first extends and leave only those blocks you want to override.  If you want to completely override the template use the second extends (or none) and do whatever you want.  Feel free to delete this comment and the extends you are not using.

This is a really good pragmatic approach to the disjoint between the dual templates and the collecttemplates command. I'm a bit worried about providing the developer with something that doesn't match what's actually going on underneath though.
 

I think the collecttemplates command is quite useful and having it do something like I outlined would help people understand this new template inheritance and why they should use it.  I think including both extends would help people know their options and do exactly what they want (similar to the multiple commented out home page options in the default projects urls).  Does anyone else have thoughts on this, or how they imagine collecttemplates working?

On Sun, May 6, 2012 at 1:12 AM, Stephen McDonald <st...@jupo.org> wrote:
Yeah I'd like to avoid middleware for this if possible.


On Sun, May 6, 2012 at 6:10 PM, Gary Reynolds <gary.r...@touchtechnology.com.au> wrote:
I think page.base.html is okay as a compromise (although I think base.base.html looks bit funny!). My strongest objection for any of the alternatives would be with prefixing the path; I think it's important that the templates reside alongside each other.

I'd be against adding a middleware, we don't need to complicate it any more when it can be done easily using nothing more than "traditional" inheritance with a less-traditional hierarchy to provide greater template flexibility.

In a nutshell those are my two biggest points for the contribution.




--
Stephen McDonald
http://jupo.org

Gary Reynolds

unread,
May 6, 2012, 6:05:32 PM5/6/12
to mezzani...@googlegroups.com
Stephen asked a while back for this to have a name, and as the discussion has evolved I've settled more on what I think looks like a good pattern. So I'm going to coin the expression "Abstract Template Inheritance" (assuming it's not been used before, but I haven't heard of it).

This gives us a nice banner under which to reference and champion the approach.

As an addition, I would not slightly alter the name.base.html pattern to become name.abstract.html; and I think this makes sense because we will never directly access name.abstract.html from our views - it's an internal implementation detail, much like an abstract model. It also will prevent the base.base occurrence, not major I know :)

I'd also add to add to what I think should go in the "concrete" template. Previously I had stated that it would only contain the single {% extends %} tag. Now I am revising that to say that it will also include the block structure which is available in the abstract template, but commented out using the shorthand {# block #}. For example:

index.abstract.html:

{% extends "base.html" %}

{% block main %}
{% block heading %}<h1>Heading</h1>{% endblock %}
{% endblock %}

Would have the corresponding index.html:

{% extends "index.abstract.html" %}

{# block main #}
{# block heading #}{# endblock #}
{# endblock #}

This now rules out {% include %} as Josh had pondered, because my thinking here is to let collecttemplates live on. The management command would now grab all templates, excluding those that match the *.abstract.* pattern, and copy them over business as usual. This would have no effect until the template author dives in and uncomments some blocks, but we've saved them a basic step of having to find out what blocks are actually defined for overriding.

Of course if there are no blocks in the abstract template, then it will still be just the one {% extends %} statement. I think this should remain as it would allow us to quickly identify templates that could do with some block tags in them for easier customisation.

So, that changes the proposal yet again - but what do others think of that as a bit more of a compromise?

Gary

Josh Cartmell

unread,
May 6, 2012, 6:40:42 PM5/6/12
to mezzani...@googlegroups.com
I think that is a pretty good compromise.  I think I would add that it would be nice to also include (commented out) the template the abstract one extends.  That way if someone didn't want to use Abstract Template Inheritance it would be easier to know what to directly inherit from.  Even if you were using Abstract Template Inheritance it would help you keep track of the inheritance easier.  In index.html you may want to modify blocks that are inherited from base.html through index.abstract.html.  By including the abstract template's extends statement it would be easier to figure out 

So I would modify your index.html to look like this:

{% extends "index.abstract.html" %}
{# {% extends "base.html" %} #}

{# block main #}
{# block heading #}{# endblock #}
{# endblock #}  

Gary Reynolds

unread,
May 6, 2012, 6:53:57 PM5/6/12
to mezzani...@googlegroups.com
My only hesitation is how far down the rabbit hole do we go? What if the parent extends another base (which is likely), and it extends another (also likely) it could be quite a few levels that the user still needs to trawl to get to a parent template that actually has the blocks in it they are interested in?

I'm rather more of the opinion that if they are choosing to completely ignore the abstract template and go it alone, they know what they are doing - or at least know how to work it out.

We should encourage the use of the excellent django-debug-toolbar as an aide here; out of the box it shows exactly what templates were rendered, in what order (demonstrating the inheritance) and should provide ample data for a template author to handle this scenario.

I guess my point is that we can't protect users from everything - and if they truly want to customise the template themselves, they need to be aware of the whole ecosystem.

In case that isn't clear, in your case below, base.html (the commented extend) will also extend base.abstract.html. At least they would have the blocks in the copied over base.html I suppose, but I think that we can also be too helpful - leaving some areas for them to learn from I don't think is a negative.

Thanks for the positive feedback on the rest though.

Josh Cartmell

unread,
May 6, 2012, 7:45:18 PM5/6/12
to mezzani...@googlegroups.com
I would vote for going one level down the rabbit whole, so we would only list the template that the abstract extends from.  My thinking was that including it would facilitate both potential use cases, inherit from the abstract template and use abstract template inheritance or don't inherit from it and use normal template inheritance.

My opinion is that we should not force people to use abstract template inheritance (Mezzanine would behind the scenes but that wouldn't matter to them).  By including the abstract templates parent it would make it very easy to use one paradigm or the other.  I definitely don't want to protect users from everything but I do want to make it easy for users to do things in the way that they want to.

Even if we don't want to facilitate both use cases I think providing the comment is a nice reference, especially if you are used to normal template inheritance.

Gary Reynolds

unread,
May 6, 2012, 8:37:10 PM5/6/12
to mezzani...@googlegroups.com
OK, well I have taken that on board and put together a script to run over the code base. I've opened a pull requests for each.


I've only addressed code, so I'd appreciate anyone who might have time to work up some docs to do so against my fork and I'll pull them together and keep the pull requests up to date.

Thanks,
Gary

Gary Reynolds

unread,
May 6, 2012, 8:42:34 PM5/6/12
to mezzani...@googlegroups.com
On Monday, 7 May 2012 at 10:37 AM, Gary Reynolds wrote:
OK, well I have taken that on board and put together a script to run over the code base. I've opened a pull requests for each.
For anyone interested, here is the script I used…


Stephen McDonald

unread,
May 6, 2012, 8:45:02 PM5/6/12
to mezzani...@googlegroups.com
Nice one - if we end up going with this, we'll need an automated way to do it with new templates, so this script will end up in the repo.

If the consensus is that we consistently do this for every template, we'll also need tests that ensure every template has an abstract counterpart.

POKOLI I PUNTO

unread,
May 7, 2012, 6:22:45 AM5/7/12
to mezzani...@googlegroups.com
IMHO the collecttemplates command should be dropped and the theme developer would need to include all the extended files in the theme (app) it is developing. This will save the theme to not include the files they are not extending.

This change would force to add a page in the docs describing which is the responsibility of each template. A good example is the wordpress one: http://codex.wordpress.org/Stepping_Into_Templates

Just my 2 cents!

Al 06/05/12 03:01, En/na Stephen McDonald ha escrit:

Josh Cartmell

unread,
May 7, 2012, 2:25:28 PM5/7/12
to mezzani...@googlegroups.com
I agree that some documentation would be good for the templates!

I don't think we should drop the collecttemplates command though because some people don't use a "theme" and just want to put templates in their project's templates directory (that is what I often do).  Collecttemplates can also be used with the -t option to only copy over specific templates so it can be used, and I think should used, to only get the file[s] you are extending.

It also can be educational to copy all templates into a single hierarchy since if you browse the templates in the source they are scattered
among the various Mezzanine apps.  Even if you don't leave all the templates copied over it provides a nice overview of the templates that exist.

On another line of thought:
I was thinking that if we end up going with abstract template inheritance we could add an option to the collecttemplates command which would determine whether or not the abstract template was copied with the requested template (default would be to not copy it).

POKOLI I PUNTO

unread,
May 7, 2012, 2:39:52 PM5/7/12
to mezzani...@googlegroups.com
What's the main objective of copying all the templates to the project specific dir? Change the only ones you need to customize? To avoid duplicating the files i think that the modified templates would be the only once that would need to be copied.

Another option is to deliver mezzanine with a default theme (with all the templates that exist now) and let the theme developer copy this files as base of the new theme if they want. This implies grouping all the templates in a separate dir. This is the way Wordpress works.


Al 07/05/12 20:25, En/na Josh Cartmell ha escrit:
I agree that some documentation would be good for the templates!

I don't think we should drop the collecttemplates command though because some people don't use a "theme" and just want to put templates in their project's templates directory (that is what I often do).� Collecttemplates can also be used with the -t option to only copy over specific templates so it can be used, and I think should used, to only get the file[s] you are extending.


It also can be educational to copy all templates into a single hierarchy since if you browse the templates in the source they are scattered
among the various Mezzanine apps.� Even if you don't leave all the templates copied over it provides a nice overview of the templates that exist.


On another line of thought:
I was thinking that if we end up going with abstract template inheritance we could add an option to the collecttemplates command which would determine whether or not the abstract template was copied with the requested template (default would be to not copy it).

On Mon, May 7, 2012 at 3:22 AM, POKOLI I PUNTO <pok...@gmail.com> wrote:
IMHO the collecttemplates command should be dropped and the theme developer would need to include all the extended files in the theme (app) it is developing. This will save the theme to not include the files they are not extending.

This change would force to add a page in the docs describing which is the responsibility of each template. A good example is the wordpress one: http://codex.wordpress.org/Stepping_Into_Templates

Just my 2 cents!

Al 06/05/12 03:01, En/na Stephen McDonald ha escrit:
Debating the naming convention might seem like bikeshedding, but I think it's really important. If one approach clearly communicates the intention and another doesn't, then it's worthwhile discussing it.

So here's another idea: instead of page.html and _page.html, we use page.html and page.base.html - this way at least all the template lines up together in a large directory listing, and it clearly indicates the intention. I was first thinking page.html.base which would line up even close, but you'd lose syntax highlighting in your editor.

On Sun, May 6, 2012 at 10:51 AM, Stephen McDonald <st...@jupo.org> wrote:
Also discussed: the bearing this has on the collecttemplates command. If every view has two templates, do we copy both? One or the other? Do we drop the command from the project?
On Sun, May 6, 2012 at 10:47 AM, Stephen McDonald <st...@jupo.org> wrote:
I'll have a crack at it:

* page view looks for page.html - uses the version in the project's templates directory, otherwise app directory (probably in Mezzanine)
* developer wants to customize page.html in their project, so they copy it to the project's template directory
* they only want to modify one block in it, not copy the entire template, which may include a lot of functionality, that could change in future versions.
* they can't have proj/templates/page.html extend the app version of page.html, Django doesn't know how to deal with extending the same template name/path
* proposed solution: view still looks for page.html, but app's page.html has one line: {% extends "_page.html" %}, and all the functionality lives in _page.html in the app
* developer can then in their project's templates directory, either have page.html with�{% extends "_page.html" %} and overriding only the block they need, or _page.html and reimplement the page's functionality entirely, depending on their needs (this is what currently occurs btw)

Current discussion are around:

* is this separation confusing - something that will definitely vary dev to dev. There's no question around the benefit it provides, it's a very good thing.
* naming convention - should it be something other than _name.html, perhaps in a different directory, perhaps requiring middleware
* can we modify the "extends" template tag, to allow this to occur without splitting things out. eg: page.html in proj/templates can {% extend "page.html" %} and the app version will be extended.

If I've missed anything please correct me.
On Sun, May 6, 2012 at 10:35 AM, Lee Matos <madmed...@gmail.com> wrote:
On May 5, 2012, at 8:19 PM, Joe Julian wrote:

> I agree. Though I have no fear of, and they conceptually suggest an internal object, using underscores, I have to agree that a "template path" seems more Django-like to me. Taking that a step further, this also opens up the opportunity to publish other templates. They would also be added in middleware. My Pixel template would extend the mezzanine template, and your site template could further extend my Pixel one. It makes sense to me.
>
> Josh Cartmell <joshc...@gmail.com> wrote:
>
>> So it took me a few minutes to understad how this worked, but I agree with
>> Steve that once I got it it made sense. �The biggest problem I see with it

>> is that it will create an entry barrier for other Django developers as it
>> works differently than what you would traditionally see in a Django app.
>>
>> A thought I had to make extending easier without adding syntax that is not
>> always easy to understand is the following:
>>
>> Move all templates, in mezzanine, to a directory called mezzanine. �So

>> instead of index.html and pages/page.html etc... we would have
>> mezzanine/index.html and mezzanine/pages/page.html etc...
>>
>> If you were visiting the index page we would still ask Django for
>> index.html (not mezzanine/index.htlm). �Then in the mezzanine template
>> middleware we could add mezzanine/template_name.html to the path. �So first

>> Django would look for index.html, then mezzanine/index.html (this would be
>> similar to the way we can add specific device or host templates).
>>
>> If you wanted to extend index.html you would simply make a template called
>> index.html that looked like this:
>>
>> {% extends "mezzanine/index.html" %}
>> ...
>> your template
>> ...
>>
>> You could put anything you wanted in there because there would be no
>> circular import (extending mezzanine/index.html rather than index.html).
>> If you didn't create your own index.html it wouldn't matter because the
>> middleware would make it so that Django looked for index.html and
>> mezzanine/index.html
>>
>> You would also be free to create an index.html and not extend
>> mezzanine/index.html because index.html would come before
>> mezzanine/index.html in the template search.
>>
>> I got the idea for this based on the way django allows you to override
>> admin templates on a per app basis :
>> https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
>>
>> What do you guys think? �I think this preserves all the power of Gary's

>> idea without making things more confusing.
>>
>> On Sat, May 5, 2012 at 6:47 AM, Gary Reynolds <
>> gary.r...@touchtechnology.com.au> wrote:
>>
>>> I'll try and answer inline to each comment rather than top posting ;)
>>>
>>> It's definitely me being thick, but it took a while to understand what
>>> you meant by "circular nature". It's that this template fragment is going
>>> to be put in a file also named "foo.html", right? It seems obvious after
>>> realizing it, but for some reason it took a while. :-)
>>>
>>> This is what I was referring to as the extra mental step. I had to think
>>> about the structure for a bit before it clicked, but once it did it makes
>>> sense. I guess what I was getting at is how many people will this happen
>>> for, and how big a step is it really. It'll vary across people I guess.
>>>
>>> Sure, I can appreciate that it is not immediately obvious, which is why�
>>> � - If you use {% extends %} in a template, it must be the first
>>> � template tag in that template. Template inheritance won't work, otherwise.

>>>
>>> I'm glad we've got some lively discussion on the topic anyway, looking
>>> forward to more.
>>>
>>> Gary
>>>

I'm not sure what you mean by circular importing? I thought I had a decent handle on django tempting and imports/extending/overriding and this doesn't seem to be solving anything for me. Is this being used anywhere else across the Django community? If it's not something that is widely used/ miles better than the current solution, I think it could be a stumbling block for new users as well. Can someone try and explain what circular dependency issue we are looking to solve? I'm genuinely curious but slightly confused as I'm being blinded by "the magic" at hand. :) I'm not trying to flame and I'm not saying this is necessarily a bad idea, I'm just not sure of the implications.

-Lee

--
Stephen McDonald
http://jupo.org



--
Stephen McDonald
http://jupo.org

Josh Cartmell

unread,
May 7, 2012, 4:11:01 PM5/7/12
to mezzani...@googlegroups.com
In my opinion the point is that you may not actually be making a "theme" per say, and Mezzanine does not required you to use a "theme".  I'm also not advocating copying all templates, just those that you plan to change.  That is why I mentioned using the -t option with the collecttemplates command.

If you are only making minor modifications and/or don't care about re usability creating a theme just for the purpose of modifying a couple of templates may be overkill.

On Mon, May 7, 2012 at 11:39 AM, POKOLI I PUNTO <pok...@gmail.com> wrote:
What's the main objective of copying all the templates to the project specific dir? Change the only ones you need to customize? To avoid duplicating the files i think that the modified templates would be the only once that would need to be copied.

Another option is to deliver mezzanine with a default theme (with all the templates that exist now) and let the theme developer copy this files as base of the new theme if they want. This implies grouping all the templates in a separate dir. This is the way Wordpress works.


Al 07/05/12 20:25, En/na Josh Cartmell ha escrit:
I agree that some documentation would be good for the templates!

I don't think we should drop the collecttemplates command though because some people don't use a "theme" and just want to put templates in their project's templates directory (that is what I often do).  Collecttemplates can also be used with the -t option to only copy over specific templates so it can be used, and I think should used, to only get the file[s] you are extending.


It also can be educational to copy all templates into a single hierarchy since if you browse the templates in the source they are scattered
among the various Mezzanine apps.  Even if you don't leave all the templates copied over it provides a nice overview of the templates that exist.


On another line of thought:
I was thinking that if we end up going with abstract template inheritance we could add an option to the collecttemplates command which would determine whether or not the abstract template was copied with the requested template (default would be to not copy it).

On Mon, May 7, 2012 at 3:22 AM, POKOLI I PUNTO <pok...@gmail.com> wrote:
IMHO the collecttemplates command should be dropped and the theme developer would need to include all the extended files in the theme (app) it is developing. This will save the theme to not include the files they are not extending.

This change would force to add a page in the docs describing which is the responsibility of each template. A good example is the wordpress one: http://codex.wordpress.org/Stepping_Into_Templates

Just my 2 cents!

Al 06/05/12 03:01, En/na Stephen McDonald ha escrit:
Debating the naming convention might seem like bikeshedding, but I think it's really important. If one approach clearly communicates the intention and another doesn't, then it's worthwhile discussing it.

So here's another idea: instead of page.html and _page.html, we use page.html and page.base.html - this way at least all the template lines up together in a large directory listing, and it clearly indicates the intention. I was first thinking page.html.base which would line up even close, but you'd lose syntax highlighting in your editor.

On Sun, May 6, 2012 at 10:51 AM, Stephen McDonald <st...@jupo.org> wrote:
Also discussed: the bearing this has on the collecttemplates command. If every view has two templates, do we copy both? One or the other? Do we drop the command from the project?
On Sun, May 6, 2012 at 10:47 AM, Stephen McDonald <st...@jupo.org> wrote:
I'll have a crack at it:

* page view looks for page.html - uses the version in the project's templates directory, otherwise app directory (probably in Mezzanine)
* developer wants to customize page.html in their project, so they copy it to the project's template directory
* they only want to modify one block in it, not copy the entire template, which may include a lot of functionality, that could change in future versions.
* they can't have proj/templates/page.html extend the app version of page.html, Django doesn't know how to deal with extending the same template name/path
* proposed solution: view still looks for page.html, but app's page.html has one line: {% extends "_page.html" %}, and all the functionality lives in _page.html in the app
* developer can then in their project's templates directory, either have page.html with {% extends "_page.html" %} and overriding only the block they need, or _page.html and reimplement the page's functionality entirely, depending on their needs (this is what currently occurs btw)

Current discussion are around:

* is this separation confusing - something that will definitely vary dev to dev. There's no question around the benefit it provides, it's a very good thing.
* naming convention - should it be something other than _name.html, perhaps in a different directory, perhaps requiring middleware
* can we modify the "extends" template tag, to allow this to occur without splitting things out. eg: page.html in proj/templates can {% extend "page.html" %} and the app version will be extended.

If I've missed anything please correct me.
On Sun, May 6, 2012 at 10:35 AM, Lee Matos <madmed...@gmail.com> wrote:
On May 5, 2012, at 8:19 PM, Joe Julian wrote:

> I agree. Though I have no fear of, and they conceptually suggest an internal object, using underscores, I have to agree that a "template path" seems more Django-like to me. Taking that a step further, this also opens up the opportunity to publish other templates. They would also be added in middleware. My Pixel template would extend the mezzanine template, and your site template could further extend my Pixel one. It makes sense to me.
>
> Josh Cartmell <joshc...@gmail.com> wrote:
>
>> So it took me a few minutes to understad how this worked, but I agree with
>> Steve that once I got it it made sense.  The biggest problem I see with it

>> is that it will create an entry barrier for other Django developers as it
>> works differently than what you would traditionally see in a Django app.
>>
>> A thought I had to make extending easier without adding syntax that is not
>> always easy to understand is the following:
>>
>> Move all templates, in mezzanine, to a directory called mezzanine.  So

>> instead of index.html and pages/page.html etc... we would have
>> mezzanine/index.html and mezzanine/pages/page.html etc...
>>
>> If you were visiting the index page we would still ask Django for
>> index.html (not mezzanine/index.htlm).  Then in the mezzanine template
>> middleware we could add mezzanine/template_name.html to the path.  So first

>> Django would look for index.html, then mezzanine/index.html (this would be
>> similar to the way we can add specific device or host templates).
>>
>> If you wanted to extend index.html you would simply make a template called
>> index.html that looked like this:
>>
>> {% extends "mezzanine/index.html" %}
>> ...
>> your template
>> ...
>>
>> You could put anything you wanted in there because there would be no
>> circular import (extending mezzanine/index.html rather than index.html).
>> If you didn't create your own index.html it wouldn't matter because the
>> middleware would make it so that Django looked for index.html and
>> mezzanine/index.html
>>
>> You would also be free to create an index.html and not extend
>> mezzanine/index.html because index.html would come before
>> mezzanine/index.html in the template search.
>>
>> I got the idea for this based on the way django allows you to override
>> admin templates on a per app basis :
>> https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
>>
>> What do you guys think?  I think this preserves all the power of Gary's

>> idea without making things more confusing.
>>
>> On Sat, May 5, 2012 at 6:47 AM, Gary Reynolds <
>> gary.r...@touchtechnology.com.au> wrote:
>>
>>> I'll try and answer inline to each comment rather than top posting ;)
>>>
>>> It's definitely me being thick, but it took a while to understand what
>>> you meant by "circular nature". It's that this template fragment is going
>>> to be put in a file also named "foo.html", right? It seems obvious after
>>> realizing it, but for some reason it took a while. :-)
>>>
>>> This is what I was referring to as the extra mental step. I had to think
>>> about the structure for a bit before it clicked, but once it did it makes
>>> sense. I guess what I was getting at is how many people will this happen
>>> for, and how big a step is it really. It'll vary across people I guess.
>>>
>>> Sure, I can appreciate that it is not immediately obvious, which is why…
>>>   - If you use {% extends %} in a template, it must be the first
>>>   template tag in that template. Template inheritance won't work, otherwise.
>>>
>>> I'm glad we've got some lively discussion on the topic anyway, looking
>>> forward to more.
>>>
>>> Gary
>>>

I'm not sure what you mean by circular importing? I thought I had a decent handle on django tempting and imports/extending/overriding and this doesn't seem to be solving anything for me. Is this being used anywhere else across the Django community? If it's not something that is widely used/ miles better than the current solution, I think it could be a stumbling block for new users as well. Can someone try and explain what circular dependency issue we are looking to solve? I'm genuinely curious but slightly confused as I'm being blinded by "the magic" at hand. :) I'm not trying to flame and I'm not saying this is necessarily a bad idea, I'm just not sure of the implications.

-Lee

--
Stephen McDonald
http://jupo.org



--
Stephen McDonald
http://jupo.org

Stephen McDonald

unread,
May 8, 2012, 8:11:58 AM5/8/12
to mezzani...@googlegroups.com
One idea I mentioned earlier in this thread yet didn't get much discussion on, is to somehow allow for circular template inheritance to occur. I've got a working approach to this here, which you'll either love or hate:


One thing is though, that it is a solution to the same problem we're trying to solve, without having to restructure anything at all. All of the differences of opinion in this thread will no longer be an issue. We can keep the collecttemplates command, we don't need two files for every template, and there's no confusion to potentially new developers around what they should be doing. Everything would remain as it currently is, there would just be an extra feature whereby, when you do create a copy of a particular template, you can use it to override *and* extend the template at the same time. 

So given foo/bar.html in your project - it can be a full copy of Mezzanine's foo/bar.html, with all its existing code, overriding it as has always been done. But if desired, you can also use {% extends "foo/bar.html" %} in it, and it will inherit Mezzanine's version, allowing you to override just the blocks you're interested in changing. 

Josh Cartmell

unread,
May 8, 2012, 12:26:57 PM5/8/12
to mezzani...@googlegroups.com
So if I understand that correctly it just looks down the template search path for another instance of the same named template?  I haven't had a chance to try it out yet but I'm wondering what you happen in the following situation:

my INSTALLED_APPS looks like this (default project with custom_app at the end:
INSTALLED_APPS = (
...django stuff...
...mezzanine stuff...
"custom_app"
)

I have index.html in my projects templates directory and it extends index.html. custom_app also has an index.html which extends index.html.   What would custom_app's index.html extend?

To try this out where would we need to put the code from the gist?

Stephen McDonald

unread,
May 8, 2012, 4:29:43 PM5/8/12
to mezzani...@googlegroups.com
On Wed, May 9, 2012 at 2:26 AM, Josh Cartmell <joshc...@gmail.com> wrote:
So if I understand that correctly it just looks down the template search path for another instance of the same named template?  

Yes that's how it works - and it just removes the path of the current template that {% extends %} is being used in, and then the regular ordering of finding the template applies.

 
I haven't had a chance to try it out yet but I'm wondering what you happen in the following situation:

my INSTALLED_APPS looks like this (default project with custom_app at the end:
INSTALLED_APPS = (
...django stuff...
...mezzanine stuff...
"custom_app"
)

I have index.html in my projects templates directory and it extends index.html. custom_app also has an index.html which extends index.html.   What would custom_app's index.html extend?

I don't think it'd handle this situation (eg more than one level of inheritance) - would need to work on it more to get that happening.
 

To try this out where would we need to put the code from the gist?

I put it into mezzanine/boot/__init__.py - a better approach was pointed out to me on IRC and if we go with this, what we'll do is actually move it into its own template tag rather than patching {% extends %}. We could call it {% overextends %} or something, since it's used for both overriding and extending at the same time.

Stephen McDonald

unread,
May 8, 2012, 7:04:44 PM5/8/12
to mezzani...@googlegroups.com
On Wed, May 9, 2012 at 6:29 AM, Stephen McDonald <st...@jupo.org> wrote:

On Wed, May 9, 2012 at 2:26 AM, Josh Cartmell <joshc...@gmail.com> wrote:
So if I understand that correctly it just looks down the template search path for another instance of the same named template?  

Yes that's how it works - and it just removes the path of the current template that {% extends %} is being used in, and then the regular ordering of finding the template applies.

 
I haven't had a chance to try it out yet but I'm wondering what you happen in the following situation:

my INSTALLED_APPS looks like this (default project with custom_app at the end:
INSTALLED_APPS = (
...django stuff...
...mezzanine stuff...
"custom_app"
)

I have index.html in my projects templates directory and it extends index.html. custom_app also has an index.html which extends index.html.   What would custom_app's index.html extend?

I don't think it'd handle this situation (eg more than one level of inheritance) - would need to work on it more to get that happening.

This felt like a show-stopper, even though I think the newly dubbed "Abstract template inheritance" approach would suffer from the same shortcoming. However I've managed to get n levels of inheritance working and updated the gist: https://gist.github.com/2634461

So this approach (dubbing it "overextend") has that going for it as well. This allows for the *extreme* case where someone is developing a reusable theme as an app with page.html, they "overextend" Mezzanine's page.html, and with the theme installed (top of INSTALLED_APPS), the project developer's page.html would overextend the theme app's page.html, which will still overextend Mezzanine's page.html - all the things like {{ block.super }} work as expected, and somehow it all managed to works with Django's cached template loader too.

Gary Reynolds

unread,
May 8, 2012, 10:58:38 PM5/8/12
to mezzani...@googlegroups.com
This felt like a show-stopper, even though I think the newly dubbed "Abstract template inheritance" approach would suffer from the same shortcoming. However I've managed to get n levels of inheritance working and updated the gist: https://gist.github.com/2634461

So this approach (dubbing it "overextend") has that going for it as well. This allows for the *extreme* case where someone is developing a reusable theme as an app with page.html, they "overextend" Mezzanine's page.html, and with the theme installed (top of INSTALLED_APPS), the project developer's page.html would overextend the theme app's page.html, which will still overextend Mezzanine's page.html - all the things like {{ block.super }} work as expected, and somehow it all managed to works with Django's cached template loader too.
 
-1. My reservation is with the monkey-patching of ExtendsNode, so I guess I fall into the camp of hating it. It's a silent change to a well documented feature in the underlying framework.
 
It can be done without this, so I would prefer a patch offered up to Django itself (has anyone checked if this has been ticketed before as a bug or enhancement request, I haven't) - and if at some point it was accepted we could reverse the ATI process, returning index.abstract.html back to index.html and the existing themes would continue to work.
 
Gary

Stephen McDonald

unread,
May 8, 2012, 11:34:41 PM5/8/12
to mezzani...@googlegroups.com
Yeah we can definitely change how it's working - Owen Nelson (who did some Mezzanine work on markdown filtering ages ago) suggested we make it a separate template tag, and don't touch {% extends %}. We'd end up subclassing the the ExtendsNode it uses and implement our own version of get_parent which is the current function. 

So extends goes untouched. We'd have our own tag {% overextends "blah.html" %} or something, that you can use to both override and extend a different version of a template with the same name.

Josh Cartmell

unread,
May 9, 2012, 12:15:50 AM5/9/12
to mezzani...@googlegroups.com
I really like the idea of an {% overextends %} template tag and prefer it to creating a companion template for every template.  It is less invasive and should be easier to maintain.  Either method accomplishes the same purpose so I vote for the simpler one.

It might be nice to be able to optionally specify an app with overextends. So {% overextends "index.html" "mezzanine.core" %} would inherit from mezzanine's index.html (this would help avoid accidentally inheriting from something you didn't intend to).  If an app was not specified then the normal template inheritance hierarchy could be used as discussed.

Stephen McDonald

unread,
May 9, 2012, 4:55:06 PM5/9/12
to mezzani...@googlegroups.com
Optional app arg is a great idea, thanks!

Gary Reynolds

unread,
May 10, 2012, 2:31:58 AM5/10/12
to mezzani...@googlegroups.com
I may be missing something, but template inheritance depends on being {% extends %} being the first template tag in the template. Adding {% overextends %} would require a {% load %}, which as I understand it, would leave this contract broken?

Assuming that isn't an issue, I then suppose that it needs to be considered whether {% overextends %} can therefore exist anywhere in template, or must immediately follow a {% load %} tag, etc.
Also {% overextends %} will be a mezzanine only concept; it would have no point of reference itself in any of the shipped templates because they won't collide by definition - they are the abstract bases using ATI nomenclature. ATI could be an approach any developer writing a reusable application could adopt, with Mezzanine as a blueprint.

Yes, it is a little more invasive, but I think that In the face of ambiguity, refuse the temptation to guess and by having the extra files we satisfy Explicit is better than implicit are both dealt with better by ATI than the overextends approach.

Stephen McDonald

unread,
May 10, 2012, 3:10:54 AM5/10/12
to mezzani...@googlegroups.com
On Thu, May 10, 2012 at 4:31 PM, Gary Reynolds <gary.r...@touchtechnology.com.au> wrote:
I may be missing something, but template inheritance depends on being {% extends %} being the first template tag in the template. Adding {% overextends %} would require a {% load %}, which as I understand it, would leave this contract broken?


We'd need to add the tag lib that {% overextends %} is in to builtins. We used to have our own versions of extends and include to support device-specific templates prior to dropping support for Django 1.2 and earlier since we can use TempleResponse objects to achieve the same thing:

 
Assuming that isn't an issue, I then suppose that it needs to be considered whether {% overextends %} can therefore exist anywhere in template, or must immediately follow a {% load %} tag, etc.

So the tag class for overextends would subclass the tag class for Django's extends tag, which has to be first. overextends would also have to be first. On the surface it'd essentially be an alias for the extends tag, but allow circular extending. Underneath it'd be implemented cleanly, unlike the version I posted that patches extend.
 
Also {% overextends %} will be a mezzanine only concept; it would have no point of reference itself in any of the shipped templates because they won't collide by definition - they are the abstract bases using ATI nomenclature.

With either approach, we'll need to document it :-)
 
ATI could be an approach any developer writing a reusable application could adopt, with Mezzanine as a blueprint.

Yes, it is a little more invasive, but I think that In the face of ambiguity, refuse the temptation to guess and by having the extra files we satisfy Explicit is better than implicit are both dealt with better by ATI than the overextends approach.
 
On 9 May 2012 14:15, Josh Cartmell <joshc...@gmail.com> wrote:
I really like the idea of an {% overextends %} template tag and prefer it to creating a companion template for every template.  It is less invasive and should be easier to maintain.  Either method accomplishes the same purpose so I vote for the simpler one.

It might be nice to be able to optionally specify an app with overextends. So {% overextends "index.html" "mezzanine.core" %} would inherit from mezzanine's index.html (this would help avoid accidentally inheriting from something you didn't intend to).  If an app was not specified then the normal template inheritance hierarchy could be used as discussed.

Stephen McDonald

unread,
May 13, 2012, 4:17:00 AM5/13/12
to mezzani...@googlegroups.com
I've gone ahead with the overextends template tag:


Just wanted to thank everyone for their input in this thread. It may have been the longest one in Mezzanine's history. 

Particular thanks goes to Gary for instigating everything. Even though we ended up with a different solution, the general problem has been solved and Mezzanine's much better for it, so thanks for all your effort on this.
Reply all
Reply to author
Forward
0 new messages