Tornado Templates

In the last article I wrote about Tornado a very powerful web server that can scale to tens of thousands of simultaneous connections.

In this next article we will dig into using Tornado Templates.

Here is what we will be covering:

  • Creating Templates
  • Rendering Templates
  • Layout Templates

We will start with the basic test app that we created in the Storm Chasing Tornado article.

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("""<h2>Storm Chasing Tornado...</h2>
                      <pre>                       
                         ***********
                          *********
                           *******
                            *****
                             ***
                              **
                               *
                              
                       </pre>
                
                  """)                    

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Since we will be working with multiple files let’s create an new directory for our application and copy our handler file into that directory.


carlos@webserver:~$ mkdir tornado_alley
carlos@webserver:~$ mv chasing_tornado.py ./tornado_alley/
carlos@webserver:~$ cd ./tornado_alley/
carlos@webserver:~/tornado_alley$

Next let’s create a directory to hold our templates.

carlos@webserver:~/tornado_alley$ mkdir templates
carlos@webserver:~/tornado_alley$ cd ./templates/
carlos@webserver:~/tornado_alley/templates$ 

Now we are going to create our template files, Tornado templates are just simple .html files embedded with Python code for processing.

carlos@webserver:~/tornado_alley/templates$ touch base.html home.html
carlos@webserver:~/tornado_alley/templates$ ls
base.html  home.html

The base.html file will provide our layout for all templates in our site, let’s add the basic structure.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB">
<head>
  <title>Storm Chasing Tornado</title>
</head>
<body>

<div id="header">
  {% block header %}{% end %}
</div>

<div id="content">
  {% block content %}{% end %}
</div>

<div id="footer">
  {% block footer %}{% end %}
</div>

</body>
</html>

Next let’s add the markup for our home.html

{% extends "base.html" %}

{% block header %}
  <h1>Storm Chasing Tornado</h1>
{% end %}

{% block content %}
  
<ul>
 {% for storm_chaser in storm_chasers %}
     <li>{{ storm_chaser }}</li>
 {% end %}
</ul>
{% end %}

{% block footer %}
  <p>2012 Storm Chaser
  <ul>
    <li><a href="http://carlosgabaldon.com">Home</a></li>
    <li><a href="about">About</a></li>
    <li><a href="terms.html">Terms of Service</a></li>
    <li><a href="privacy.html">Privacy</a></li>
  </ul>
  </p>
{% end %}

Tornado template expressions are very similar to Django templates syntax which are surrounded by double curly braces: {{ … }}. The contents may be any python expression, which will be escaped according to the current autoescape setting and inserted into the output. Other template directives use {% %}. These tags may be escaped as {{! and {%! if you need to include a literal {{ or {% in the output. To comment out a section so that it is omitted from the output, surround it with {# … #}.
To inherit from another template as home.html is inheriting from base.html we use {% extends *filename* %}

Templates that use extends should contain one or more block tags to replace content from the parent template. Anything in the child template not contained in a block tag will be ignored, for detailed examples read the official Tornado documentation.

Next we need to modify our handler file to use the templates.


import os.path
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        storm_chasers = ["TIV 1", "TIV 2"]
       
        self.render("home.html", 
                    storm_chasers=storm_chasers)                   


handlers = [
    (r"/", MainHandler),
]

settings = dict(
        template_path=os.path.join(os.path.dirname(__file__), "templates"),
)               

application = tornado.web.Application(handlers, **settings)


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()


Let’s walk through the above modifications. The tornado.web.Application class accepts additional keyword arguments passed to the constructor which are used for configuring a Tornado web application instance. We will create a settings dictionary to set the template path.


settings = dict(
        template_path=os.path.join(os.path.dirname(__file__), "templates"),
)               

application = tornado.web.Application(handlers, **settings)

Now that the template path is configured we will switch from writing out the HTML with the write() method to using the render() method of our base tornado.web.RequestHandler. The render() method takes the template name and multiple keyword arguments that are passed directly to the template for use in rendering.

self.render("home.html", 
            storm_chasers=storm_chasers)     

In this case it is just a list of top storm chaser vehicles which we will iterate in our home.html template.

{% for storm_chaser in storm_chasers %}
     <li>{{ storm_chaser }}</li>
 {% end %}

Lastly to make things cleaner we moved out the URL to handler mappings out of the constructor call to a handlers variable.

handlers = [
    (r"/", MainHandler),
]

We can now start up our application again to see our new cool templates.

carlos@webserver:~/tornado_alley$ python chasing_tornado.py

Using the IP address of our VM, we just need to open a browser window

http://192.168.0.15:8888/

Happy Hacking!

8 thoughts on “Tornado Templates

Leave a reply to Kris Bennett Cancel reply