Sunday, March 22, 2009

Django templating

One of my contacts, John, wrote me yesterday, asking for some conceptual help with the Django templating system. I broke down template inheritance for him, using the following very simple example.

I told John...


I typically use Django's template inheritance in this way. A base page handles most of the boiler plate stuff and then I specialize in the inherited pages. URLs and the views (python functions) also get involved.

Here's a super simple page. (Imagine that each code snippet lives in its own file.) This one is base.html.


<html>
<body>
Part One
Part Two
</body>
</html>


I need two more things to display a page using the Django system, the URI routing expression in urls.py and a view. (I'm sure you get this, but to be clear I just want to call out all of the parts.)

The URI expression:


(r'^base$', base_function),


base_function is the view function, typically defined in another file. Something like this will display the page without really doing anything fancy with data.



def base_function(request):
return render_to_response("base.html")



From a browser, you go to /base/, and you see...
Part One Part Two

Now you want to either extend or replace a section of the template. First, let's extend. We modify the original template and add markers for the areas we will be extending or replacing.

<html>
<body>
{% block one %} Part One{% endblock %}
{% block two %} Part Two{% endblock %}
</body>
</html>

Suppose you just want to just change the second block. So you create a file called mod2.html.

{% extends "base.html" %}
{% block two %} A different thing to render in Part Two{% endblock %}

You add another URL expression in urls.py. So now it looks like...

(r'^base$', base_function),
(r'^mod2$', mod_alt_two_function),

and you add a second view function...



def mod_alt_two_function(request):
return render_to_response("mod2.html")



From a browser, you go to /mod2/, and you see...
Part One A different thing to render in Part Two

A third view might replace the first and second section....

(r'^base$', base_function),
(r'^mod2$', mod_alt_two_function),
(r'^all$', all_mod_function),




def all_mod_function(request):
return render_to_response("all.html")



{% extends "base.html" %}
{% block one %} Much different than
{% endblock %}
{% block two %} the original{% endblock %}

Producing this when you hit /all/ in the browser:

Much different than
the original

So that's the basics with template inheritance. You can also just include chunks of other templates by including them right in the middle of the page. And you can wrap the includes in logic, so that based upon the data you are passing to the template from the view function, you can make decisions about what to include. Here is a small snippet from one of my pages that includes one of four different HTML template 'chunks' based upon the values of the variables "result.format" and "result.render_hint".




{% ifequal result.format 'pipe' %}
{% ifequal result.render_hint 'email' %}
{% include 'email_result.html' %}
{% endifequal %}
{% ifnotequal result.render_hint 'email' %}
{% include 'table_properties.html' %}
{% endifnotequal %}
{% endifequal %}
{% ifequal result.format 'text' %}
{% include 'text_result.html' %}
{% endifequal %}
{% ifequal result.format 'tag' %}
{% include 'tag.html' %}
{% endifequal %}

1 comment:

hock said...
This comment has been removed by a blog administrator.