I have the following structure of templates (simplified for clarity):
base1.html:
<html>
<head>{% block head %}{% endblock %}</head>
<body>{% block body %}{% endblock %}</body>
</html>
base2.html:
{% extends "base1.html" %}
{% block head %}
<meta .... />
<title .... />
css includes etc.
{% endblock %}
{% block body %}
{% block header %}{% endblock %}
{% block featured %}{% endblock %}
{% block navigation %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock %}
{% endblock %}
Also base3.html and base4.html which futher detalize the generic body structure defined in previous base templates (not shown here). The last template extends base4.html, overriding blocks with concrete content (markup is handled by base templates).
The question is: I have two templates: main.html and article.html which both extend base4.html. But in article.html I want the order of body blocks defined in base2.html to be different (featured block to go after navigation). How can I achieve that? Or how to refactor the structure of templates to make this possible? Overriding the block body in top-level template doesn't work.
I don't think that you're going to have any luck going about it that way. A simple solution could be to have an optional variable that base2.html looks at, which determines the alternate order. In fact it may even be that you can define the presence of this variable in the article.html template itself. I haven't tried this, but something like the following may work:
{% with alternate_order=1 %}
{% include base4.html
{% endwith %}
Why do you have so many levels of inheritance? As a note, django provides no limitations, but typically we use the three-level approach. See docs
Here are a few suggestions:
You can probably combine base1.html and base2.html.
If you can put the html code in the parent then do so. I usually implement my templates like this:
<div id='sidebar'>{% block sidebar_content %}{% endblock %}</div>
As for your problem, if you need a different layout, that's when you branch. That is, if using a different css won't work.
Related
In the Wagtail docs (Your first Wagtail site) we are told to create a homepage.html template as follows:
{% extends "base.html" %}
{% load wagtailcore_tags %}
{% block body_class %}template-homepage{% endblock %}
{% block content %}
{{ page.body|richtext }}
{% endblock %}
In the above code, what is that tag {% block body_class %}template-homepage{% endblock %} supposed to be doing? I can't find any mention of it in the text of the tutorial.
The tutorial goes on to instruct us to create two more templates, blog_index_page and blog_page templates, both of which are to contain {% block body_class %} tags. Again, I can find no mention at all of those lines in the docs, let alone an explanation of how they might be used/modified.
A search for "body_class" in the docs finds only the three code blocks just mentioned, and one other mention: in the version 1.2 release notes, under 'What's new — Minor features' the notation: "Simplified body_class in default homepage template."
Any insight as to what I'm supposed to do with these tags? What special meaning or function, if any, does the text enclosed within the tags in those tutorial templates (for example, "template-homepage" in the code above)?
In base.html you have a part that looks like <body class="{% block body_class %}{% endblock %}">. What you add into that block in your templates will be rendered into that section.
For example, lets say on your design your <body> contains a bottom margin, however on a particular template you don't want the margin there and create a css class .remove-margin { margin-bottom: 0 };
You can then add {% block body_class %}remove-margin{% endblock %} into your template and it will apply the class to the <body> tag without you having to modify the base.html template for that one use case.
You are also able to create your own ones. In base.html add a custom block such as {% block my_custom_block %}{% endblock %} and then in your template include some text or html inside that my_custom_block and it will be rendered wherever you've place that part in the base template.
Just to help clarify the correct answers above with a picture as I was also wondering what that block tag was doing, here is the rendered html. As per answer above, this is standard Django.
In the base.html you have this line:
<body class="{% block body_class %}{% endblock %}">
The substitution happens in the home_page.html template:
{% block body_class %}template-homepage{% endblock %}
And it renders as per below screenshot:
<body class="template-homepage">
I'm using twig templates in a slim framework app. I have a template page.phtml which paginates an array of data and has several sub blocks intended for overriding per element specifics like paginating users, events, orders, etc.
page.phtml
<div class="page">
{% block block1 %}default content{% endblock %}
<ul>
...
</ul>
{% block block2 %}{% endblock %}
</div>
I have an event.phtml template which embeds page.phtml and adds some other content to the page; it also overrides the default page's block1 content
event.phtml
<html>
<body>
<h1>Event Page</h1>
{% embed "page.phtml" %}
{% block block1 %}event page content{% endblock %}
{% endembed %}
</body>
</html>
I have a custom event page which needs only modify a few of the event page's blocks so I extended event.phtml like so
custom_event.phtml
{% extends "event.phtml" %}
{% block block2 %}overridden value{% endblock %}
and expected block2's overridden content to show up in the page.phtml template embedded by the parent template. I can output the value of block2 in the parent template and it's there, but in the embedded template it's not. I tried explicitly passing the block in event.phtml in the embed like so
{%embed "page.phtml" %}
{% block block2 %}{{parent()}}{% endblock %}
...
{% endembed %}
But that yielded no difference. How do I get the overridden block2 from the custom_event.phtml template all the way through the extended event.phtml template and into the embedded page.phtml template?
You cannot do this.
{% embed %} technically defines a new (anonymous) template which extends the embedded template (this is how it can overwrite blocks) and gets included into the current templating. This is really just syntactic sugar for {% include %} and {% extends %} to avoid having to store this partial template in its own file and include it only once.
Twig inclusion are not extendable by child templates. Only blocks of the current template are available for extension. And event.phtml does not have any blocks.
I have some html structures that are reused in quite a few different places. It's different from a overall template so I can't extend it, it can also be used to contain complicated content so I don't think defining it as a template tag does a good job. Below is some pseudo code describing my desired outcome, when using template_level2.html you can easily put stuff into the reusable_pattern_template by calling the block inside it. If I do use this code, what you write in 'actual content' of template_level_2.html wouldn't show up. How should I deal with this?
base.html
<html>
<head></head>
<body>
{% block content %}{% endblock %}
</body>
</html>
template_level1.html
{% extends 'base.html' %}
{% block content %}
Something here...
{% include 'reusable_pattern_template.html' %}
Something else here...
{% endblock %}
reusable_pattern_template.html
<div>
<div>
<div>
{% block local_content %}{% endblock %}
</div>
</div>
</div>
template_level2.html
{% extends 'template_level1.html' %}
{% block local_content %}
Actual content here...
{% endblock %}
update:
Sorry, the extends in template_level2.html has some misspelling, I've just corrected it.
It may not be very clear, but the code above is more of a pseudo code describing my desired outcome. In short,
I would like to include small pieces of reusable html patterns in my
templates.
These patterns are like boxes, that you can put whole pieces of html
content in them. So context variables may be a bit of too limited for
my purpose
Django does not process blocks in included files.
The include tag should be considered as an implementation of "render this subtemplate and include the HTML", not as "parse this subtemplate and include its contents as if it were part of the parent". This means that there is no shared state between included templates -- each include is a completely independent rendering process. (Django template tag documentation)
I came across this problem and ended up with the following compromise, hoping someone else might find it useful. It relies on using with blocks in the child templates.
base.html wants to reuse a common nav.html include, but define some blocks where variables inside nav.html might be overriden by child templates.
<!-- base.html: -->
<html>
[...]
<nav class="desktop">
{% block desktop_nav %}
{% include "includes/nav.html" %}
{% endblock %}
</nav>
[...]
<nav class="mobile">
{% block mobile_nav %}
{% include "includes/nav.html" %}
{% endblock %}
</nav>
[...]
The include template depends on a variable called selected, which base.html does not define, by default:
<!--includes/nav.html:-->
About
People
Contact
But child pages can override that value as follows:
<!--about.html:-->
{% extends "base.html" %}
{% block desktop_nav %}{% with selected='about' %}{{ block.super }}{% endwith %}{% endblock %}
{% block mobile_nav %}{% with selected='about' %}{{ block.super }}{% endwith %}{% endblock %}
so, not perfect, I still have to have two separate blocks and use those with blocks twice, but it does allow me to override variables in include blocks from the parent template.
It seems that the final template is trying to extend itself (if it was in quotes).
You really don't need that much of complexity. It's actually pretty much simpler.
The base template should hold the skeleton of your template, then you can extend it to make customizations. For reusable code blocks that you don't want to include in your every view, include them where appropriate but don't use any block, extends or include statement within the included file. Django will not parse those but the context variable passed from the view can still be used.
In short, you can create variables in whichever template you're planning to include e.g.
{{ localcontent }}
and then assign those variables wherever you include the template e.g.
{% include "name_snippet.html" with localcontent="Actual content" %}
You could split reusable_pattern_template into begin and end templates. Then in level1 you can go include begin, block, include end.
Alternatively you could pass a template name into reusable_pattern_template as a context variable and then include it in reusable_pattern_template. This will require changing the relationship between level1 and level2 in your example but is generally more powerful.
Not the exact thing but you can do this (I've used it for including navigation bars):
Use with and only
snippet.html:
<div>
{{ listItem1 }}{{ listItem2 }}...{{ listItemN }}
</div>
index.html:
{% include 'snippet.html' with listItem1='<li>HOME</li>' listItem2 ='<li>ABOUT</li>' only %}
Since, we have used only after listItem2, all further variables will be ignored.
Apologies, this is pretty basic. I have abstracted my static html navigation bar to a block so that it can be dynamically rendered from a model. I have created a new block marker in base.html with the following syntax
{% block navigation %}{% endblock %}
How can I ensure this is rendered on every page? Do I need to create some sort of middle layer for this? Everything I have done so far has simply used the primary block.
EDIT Sunday, 14 August 2011 11:25 AM
I didn't explain this very well. The content of navigation block is
{% extends 'base.html' %}
{% block navigation %}
<nav>
<ul>
{% for item in items %}
<li>{{ item.name }}</li>
{% endfor %}
</ul>
</nav>
{% endblock %}
I want to render this on every page without having to go through child templates of base.html individually and add it to them, if that is possible.
You have got static navigation bar, so you can just write code in your base.html page and then use it with {% extends 'base.html' %} tag on every new page. Your markup will be in every page. Also, if you use only extends tag in your child page and then render it - you will see base.html without any edition.
If you have got code, which need to appear on few pages, but not on everyone - create 'includes' directory, save code there and extend your base template with {% include %} tag. It won't avoid repating, but make your code shorter.
And last thing you'll need in future, maybe with dynamic code - caching. With {% cache %} tag you can cache block for some time.
Your block is not doing anything here, but if you want something to appear in all the templates, you have to define it in a base template (base.html) and make the others extend from it:
base.html
Yor menu and the stuff you want to appear everywhere
{% block content %}{% endblock %}
Another template
{% extends "base.html" %}
{% block content %}
The actual content of the page
{% endblock %}
{% block FOO %}{% endblock %} reserves a space to be overwritten in sub templates.
{% include "foo.html" %} pulls content from another file into the current file.
To get {% block navigation %}{% endblock %} to display on every page, you need to add content
{% block navigation %}SHOW ME{% endblock %}
The master template in my Django app looks like this:
{% block parent %}
Some text...
{% block child %}
Default content here...
{% endblock child %}
...some more text
{% endblock parent %}
Now, this template should be overwritten in a way that the child block is changed:
{% extends "master.html" %}
{% block child %}
New content here...
{% endblock child%}
However, the rendering stays the same (printing "default content here..."). Have I missed something obvious or are nested blocks not possible? (Or, violating the DRY principle, have I to re-define the parent block?)
Edit: I'm working with Django 1.1, if that matters.
OK, it's a bug in Django's template system. For most other cases, Ben James is right (see his comment to my question above).
In my case, the child block was inside a {% ifnotequal a b %} block, and that breaks the block inheritance. I consider that to be a bug, since there are dozens of natural use cases for such operations.
The corresponding ticket.
Do this:
{% extends "master.html" %}
{% block parent %}
{% block child %}
New content here...
{% endblock child%}
{% endblock parent %}