Template Inheritance in Django - django

I'm using Django 1.1, and I have this template, a base template, that all the other pages inherit from. It defines a bunch of things that are constant throughout pretty much all of the website, like this navbar:
<div id="navbar">
{% block navbar %}
Link 1
Link 2
Link 3
Link 4
Admin
{% endblock %}
</div>
But Django's default behavior within child templates is to have the child completely override blocks in the parent template. I've got this page here that doesn't necessarily have to override the navbar block, just add a few more entries to it that'll be specific to that page, but right now the only way I can see that happening is if I were to copy the navbar block from the parent and then include it in the template + my additions. Is there any other way that can be done?

Use {{ block.super }} in the child template to include the content from the parent block.

As Alasdair noted, {{ block.super }} allows you to use the value from the parent.
However, if you're finding you always need to do this, you should consider whether your blocks are granular enough. You should be able to lay them out in such a way that each block only defines the content it needs.

You can define nested blocks, so you could also do something like this:
<div id="navbar">
{% block navbar %}
Link 1
Link 2
Link 3
Link 4
Admin
{% block navbar-extra %}{% endblock %}
{% endblock %}
</div>
Templates that need to override the entire navbar could do so, while other templates could just override the "navbar-extra" block. IMO this is a little cleaner than using {{ block.super }} in situations where you know in advance where you'll need the extensibility; YMMV.

You don't have to define all blocks, so if you don't define navbar block in child page, it will use block content from parent.

Related

Django custom template tags imitating {% block %} behavior

I was studying Django custom template tags and got a question about the possibilities of custom tags.
Assume I have a construction like
{% extends "base.html" %}
{% block leftmenu %}
{% spaceless %}
<div id="#leftmenu">
...
</div>
{% endspaceless %}
{% endblock %}
and I want to shorten it like
{% extends "base.html" %}
{% load myawesometags %}
{% myblock leftmenu %}
...
{% endmyblock %}
I can't just create custom tag adding <div> and removing spaces cause without {% block ... %} the content won't take it's place in the base template. So, the question is: is it possible to emulate standard Django blocks in custom template tags?
It is possible to write a block tag, however you should know that block tag and extends tag work together. If you look at the code for BlockNode and ExtendsNode you will see how they render the template contents together.
ExtendNode captures all the block nodes from current template and the parent template. These blocks are stored in render_context with key BLOCK_CONTEXT_KEY and with value as instance of BlockContext. All the blocks are added to BlockContext using method add_blocks which uses FIFO (first-in-first-out) queue. Once all the block nodes are stored ExtendNode then renders the parent template. This causes the BlockNode instances to be rendered in the parent template. BlockNode then picks the BlockContext from render_context to get the block data. And because of FIFO, when BlockNode pops the block object from BlockContext it picks the last block, i.e. the one it encounters last in the inheritance. That's what I understood when reading the code. If I missed something please correct me.
You may be able to inherit BlockNode to customize it to a certain degree.
It is possible, though I think this kind of template tag is not expected to be customized.
The easiest way is probably to inherit the BlockNode class to do what you want and (somewhat) copy the do_block() function https://github.com/django/django/blob/master/django/template/loader_tags.py#L172 to use your BlockNode.

Django template inclusion

The template inheritance page on the django site doesn't really solve my problem (Django 1.2).
My base page looks like:
...
<div class="grid_12" id="content">
{% block content %}{% endblock %}
</div>
...
{% block javascript %}{% endblock %}
I have another template that defines content for these:
{% block content %}
animated sidebar
{% endblock %}
...
{% block javascript %}
alert('hello');
{% endblock %}
This is something like an animated sidebar, so I don't want to extend the base template since it's auxiliary to the main content of the page. If I just use "include", the entire thing is put where the "include" tag is placed - as a result the javascript doesn't run because it's included before one of its dependencies.
What's the best way to solve this?
EDIT
Sorry, I didn't make myself clear.
I have my content pages which render a template that extends "base.html". In "base.html" I want to include a sidebar template that needs to append blocks in "base.html". So I've tried just putting include "sidebar.html" into "base.html", but it just inserts the whole thing where the "include" tag is. What I want it to do is append the blocks in "base.html", which may themselves have been populated by "page.html".
Maybe it's important to say that "sidebar.html" is entirely static - i.e. there's no callable associated with it. So perhaps this question should really be "How can I include a static template into base.html so it will append to blocks in base.html regardless of the output of the actual view that processes the request?"
I think you mean you want to append to a block? You can put {{ block.super }} where you want the inherited content to go. e.g.:
{% block javascript %}
{{ block.super }}
alert('hello');
{% endblock %}
You should only use {% block foo %} tags to extend blocks in a base template, so I'm not clear what you mean when you say you don't want to extend it.
The code, as you've entered it, should render to
...
<div class="grid_12" id="content">
animated sidebar
</div>
...
alert(hello)
Unless you want to append the content (as in Matt's answer) it's not clear what you want to happen.
You shoud be using something like jQuery to trigger execution only after the page is fully loaded. Include jQuery library in the document header and then somewhere:
$(document).ready(function() {
//your code goes here
});

Django: Extends or Include?

My friend and I are having a small argument. In my current Django Project, I have created a file called menu.html which will contain a bunch of links configured and formatted into a list. Instead of manually hard-coding the menu into each page, I am currently including the menu using the following Django/Python code:
{% include 'menu.html' %}
However, my friend is suggesting that this is the incorrect way to do it. He said I need to use extends instead of include and then define content, something like this:
{% extend 'menu.html' %}
{% block content %}
The rest of my content here.
{% endblock %}
That's a bit of extra code. Does it really matter which I use? I would prefer to use the former.
Yes, it matters. First of all extends can only occur as the very first line of the file. Secondly, include pushes and pops a context object on the resolve stack, which means that value created in the context while in the include will go out of scope when it returns.
My rule is: create base.html template files that define the overall structure of your site and use liberal amounts of {% block foo %} around critical areas. Then all of your other templates extends the base (or something that itself extends the base) and you replace those blocks as needed.
include, on the other hand, is good for encapsulating things you may need to use in more than one place, maybe even on the same page.
Update:
I have been using my own library of template_tags for so long that I forget that Django's template language still has major gaps in functionality. The tag in question here is from an early django snippet called expr which I have heavily edited and extended. You can say, for example, {% expr 'Fred' as name %} (or any valid Python expression), and it will store the result in the 'name' slot in the current Context. If this occurs in an included template, name's value will be popped on exit from the template file.
You can sort of achieve this with the {% with %} tag, but expr gives me much greater flexibility, including doing arbitrarily complex calls. This originally came up when having to create complex cached objects that required expensive DBMS interactions that couldn't be done up in the view, they had to be invoked in the template itself.
Email me (in my profile) if you need to get deeper into this.
( his friend )
What I actually meant was defining a base.html so you can inherit a base template consistent of several generic sections, this one includes the doctype, html element defines 3 blocks for content and nav and optional area to override/insert script/link elements in the head.
<!doctype>
<html>
<head>
{%block extrahead %} {%endblock %}
</head>
{%block nav %}
<nav>
<ul>
<li>home</li>
</ul>
</nav>
<div id="content">
{% endblock %}
{%block content %}
{% endblock %}
</div>
</html>
Then you can define homepage.html:
{% extends "base.html" %}
{% block content %}
homepage content
{% endblock %}
homepage.html would then have the navigation because it extends base.html.
In this case placing the menu in base.html and extending from this seems to be more senseful.
including is great for splitting complex template and reusing those chunks.
let's say, you use the same list-style in different places of the site, but you send other queryset to it. as long, as you call the querysets the same, you only need to write the template code once.
Here I use differnt templates for normal- and ajax-requests. But using include let me re-use most parts in both templates

Can we append to a {% block %} rather than overwrite?

In my core.html I have a block labeled javascript. It would be great if I can append more lines to this block without overwriting everything in it.
{% block javascript %}
{{ block.super }}
... more content ...
{% endblock %}
See: Django documentation - Template inheritance
Using block.super works fine when extending a template but not as well when including one, ie:
{% extends "base.html" %} vs. {% include "partial.html" %}
Say you want to include a template in the middle of your page and you'd also like it to add some javascript in a block at the end of the page: calling block.super in the included template will crash.
Cf. Django issues #7324, #12008, #13399 and the related update to the documentation. Cf. include tag note:
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.
Blocks are evaluated before they are included. This means that a template that includes blocks from another will contain blocks that have already been evaluated and rendered - not blocks that can be overridden by, for example, an extending template.
In that case I'd recommend using django-sekizai, wich allow you to do things like:
{% load sekizai_tags %}
⎧ <p>Some content</p>
<p>Some content</p> | {% addtoblock "js" %}
| <script type="text/javascript">
{% include "partial.html" %} -> ⎨ alert("Hello django-sekizai");
| </script>
<p>Some more content</p> ⎩ {% endaddtoblock %}
{% render_block "js" %}
From django-sekizai README:
The main reason I started this project was the lack of a good media (css/js) framework in django and the django-cms. Yes there is the Media class used in forms in django, but really that doesn't work that well. Usually the frontend guys want to decide on css and javascript files to be included and they don't want to have to edit Python files to change that neither did I want them to change my Python files. Therefor there was a need to allow you to edit contents of templates which are before or after the point where you are now. Also I wanted duplicates to be removed. As a result I wrote django-sekizai, which does exactly that. It's similar to blocks, just instead of inheriting them, you extend them.

How to test for use of a django template block?

I would like to do the following:
{% if appnav %}
<hr />
<div id="appnav">
<ul class="tabs">
{% block appnav %}{% endblock %}
</ul>
</div>
{% endif %}
...however, testing for the present use of a block by templates further down the inheritance chain does not seem to work.
Is there some other conditional that might do this?
The template language doesn't provide exactly what you're looking for. Child templates can call the parent block with {{ block.super }}, but parent templates can't reference child templates.
Your best bet will probably be to write a custom template tag. There are two sections in the template manual to review.
First, Parsing until another block tag. This will give you the basics of how to parse.
Second, Parsing until another block tag and saving contents. By placing a block tag inside the custom tag, you could detect content and wrap it as appropriate. This should work, because I believe the inner block tag will be parsed first. If that doesn't work, subclass the existing block template tag provided by django to implement your special magic.
If you you are looking for an easy solution. You can hide the element as the default html.
<div id="appnav">
<ul class="tabs">
{% block appnav %}
<script>document.getElementById("appnav").style.display = "none"</script>
{% endblock %}
</ul>
</div>