Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested django templates

This seems like a pretty basic thing to do but although I've been using Django for around a year, I've never run into this scenario yet.

In a lot of templating/web frameworks, template inheritance works a bit differently, in that usually it behaves more like wrappers, so if you have childtemplate.html, parenttemplate.html, and grandparenttemplate.html, then the finally rendering usually looks something like:

grandparent header
    parent header
        child header
        child content
    parent content
    parent footer
grandparent content
grandparent footer

That's not exactly how it works in Django but I'm wondering how to implement it.

Specifically I have my "child" template, let's just say it's foo.html. foo.html optional gets a variable parent_template or defaults to "base.html"

{% extends parent_template|default:"base.html" %}

{% block content %}
I am a foo and my title is {{ foo.title }}
{% endblock content %}

So, this is where I run into a snag. If parent_template is a template, that template should wrap the contents of foo.html and then place the result into base.html:

{% extends "base.html" %}

{% something_magical_here %}
<div>parent header</div>
# content of foo.html
<div>parent footer</div>
{% end_something_magical_here %}

And then in base.html:

<html>
... snip ...
<div id="content">
{% something_else_magical %}
# content of parent_template rendering, or just foo.html if no parent_template given
{% end_something_else_magical %}

Which should render as

<html>
... snip ...
<div id="content">
<div>parent header</div> 
I am a foo and my title is Bar
<div>parent footer</div>

if parent_template is set and

<html>
... snip ...
<div id="content">
I am a foo and my title is Bar

if it is not.

I hope my problem is clear: I need to (optionally) wrap a template in a parent template, and then send the results of that to the base.html template.

Normally, something like this might work:

#foo.html
{% extends "parent.html" %}
{% block child_content %}
I am a foo and my title is {{ foo.title }}
{% endblock child_content %}

#parent.html
{% extends "base.html" %}

{% block content %}
parent header
{% block child_content %}{% endblock child_content %}
parent content
parent footer

#base.html
base header
{% block content %}{% endblock content %}
base content
base footer

However, since the parent_template could be blank, then sometimes base.html will be getting just the child_content block, not the content block.

Also, I'd like to be able to do this without having to create a bunch of sub-blocks (what if I decide that the foo application should have its own /foo/base.html that then calls /base.html)?

Any ideas?

like image 967
Jordan Reiter Avatar asked May 06 '11 19:05

Jordan Reiter


1 Answers

the extends template tag can take a variable argument.

so:

base.html
    {% block content %}
        <p>BASE</p>
    {% endblock %}

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

    {% block content %}
        {{ block.super }}
        <p>PARENT</p>
    {% endblock %}

foo.html
    {% extends ext_templ %}

    {% block content %}
        {{ block.super }}
        <p>FOO</p>
    {% endblock %}

using base:

return render_to_response('foo.html', {'ext_templ':'base.html'})

gives you:

<p>BASE</p>
<p>FOO</p>

using parent:

return render_to_response('foo.html', {'ext_templ':'parent.html'})

gives you:

<p>BASE</p>
<p>PARENT</p>
<p>FOO</p>

edit:

one way around this problem to get nested blocks is:

base.html
    {% block content %}
        {% block top %}
            <p>BASE START</p>
        {% endblock %}

        {% block bot %}
            <p>BASE END</p>
        {% endblock %}
    {% endblock %}


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

    {% block top %}
        {{ block.super }}
        <p>PARENT</p>
    {% endblock %}

    {% block bot %}
        <p>PARENT</p>
        {{ block.super }}
    {% endblock %}

foo.html
    {% extends ext_templ %}

    {% block top %}
        {{ block.super }}
        <p>FOO</p>
    {% endblock %}

    {% block bot %}
        <p>FOO END</p>
        {{ block.super }}
    {% endblock %}

The other method that i can think of is to wrap the blocks with an {% if ext_templ == 'parent.html' %} tag but that doesn't seem very dry. I'm curious to see other peoples response to nested blocks as well.

like image 66
dting Avatar answered Nov 05 '22 12:11

dting