Skip to content

Latest commit

 

History

History
executable file
·
200 lines (147 loc) · 6.93 KB

introjinja.rst

File metadata and controls

executable file
·
200 lines (147 loc) · 6.93 KB

-Python Packages- Part 8: Website with jinja2 and tornado

This article was stolen from the famous kennethreitz/python-guide. The introduction to jinja2 and tornado with its code examples was a contribution from me. ... so I stole my own code back to complete a little bit my blog ...

The introductions to template engines and frameworks are from the python-guide and its authors.

Templating (with Jinja2)

Most WSGI applications are responding to HTTP requests to serve content in HTML or other markup languages. Instead of generating directly textual content from Python, the concept of separation of concerns advises us to use templates. A template engine manages a suite of template files, with a system of hierarchy and inclusion to avoid unnecessary repetition, and is in charge of rendering (generating) the actual content, filling the static content of the templates with the dynamic content generated by the application. The result ist mostly a html file send back to the request.

As template files are sometimes written by designers or front-end developers, it can be difficult to handle increasing complexity.

Some general good practices apply to the part of the application passing dynamic content to the template engine, and to the templates themselves.

  • Template files should be passed only the dynamic content that is needed for rendering the template. Avoid to be tempted to pass additional content "just in case": it is easier to add some missing variable when needed than to remove a likely unused variable later.
  • Many template engines allow for complex statements or assignments in the template itself, and many allow some Python code to be evaluated in the templates. This convenience can lead to uncontrolled increase in complexity, and often harder to find bugs.
  • It is often necessary to mix JavaScript templates with HTML templates. A sane approach to this design is to isolate the parts where the HTML template passes some variable content to the JavaScript code.

Jinja2 is a template engine which is similar to the Django template system with some extra features. It is a text-based template language and thus can be used to generate any markup. It allows customization of filters, tags, tests and globals. Unlike the template system implemented in the Django Framework it allows to call functions. The Code is staying under the BSD license.

Framework (tornado)

Broadly speaking, a web framework consist of a set of libraries and a main handler within which you can build custom code to implement a web application (i.e. an interactive web site). Most web frameworks include patterns and utilities to accomplish at least the following:

URL Routing
Matches an incoming HTTP request to a particular piece of Python code to be invoked
Request and Response Objects
Encapsulate the information received from or sent to a user's browser
Template Engine
Allows for separating Python code implementing an application's logic from the HTML (or other) output that it produces
Development Web Server
Runs an HTTP server on development machines to enable rapid development; often automatically reloads server-side code when files are updated

Tornado is a scalable, non-blocking web server and web application framework with a relative simple usage. Tornado is known for its high performance. It was initially developed for friendfeed , a real time chat and blog system.

Example

Here some important html tags in Jinja2:

{# This is a comment #}

{# The next tag is a variable output: #}
{{title}}

{# Tag for a block, can be replaced through inheritance with other html code #}
{% block head %}
<h1>This is the head!</h1>
{% endblock %}

{# Output of an array as an iteration #}
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}

The next listings is an example of a web site in combination with the tornado web server. Tornado is not very complicate to use.

# import Jinja2
from jinja2 import Environment, FileSystemLoader

# import Tornado
import tornado.ioloop
import tornado.web

# Load template file templates/site.html
TEMPLATE_FILE = "site.html"
templateLoader = FileSystemLoader( searchpath="templates" )
templateEnv = Environment( loader=templateLoader )
template = templateEnv.get_template(TEMPLATE_FILE)

# List for famous movie rendering
movie_list = [[1,"The Hitchhiker's Guide to the Galaxy"],[2,"Back to future"],[3,"Matrix"]]

# template.render() returns a string which contains the rendered html
html_output = template.render(list=movie_list,
                        title="Here is my favorite movie list")

# Handler for main page
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # Returns rendered template string to the browser request
        self.write(html_output)

# Assign handler to the server root  (127.0.0.1:PORT/)
application = tornado.web.Application([
    (r"/", MainHandler),
])
PORT=8884
if __name__ == "__main__":
    # Setup the server
    application.listen(PORT)
    tornado.ioloop.IOLoop.instance().start()

The base.html file can be used as base for all site pages which are for example implemented in the content block.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{{title}} - My Webpage</title>
</head>
<body>
<div id="content">
    {# In the next line the content from the site.html template will be added #}
    {% block content %}{% endblock %}
</div>
<div id="footer">
    {% block footer %}
    &copy; Copyright 2013 by <a href="http://domain.invalid/">you</a>.
    {% endblock %}
</div>
</body>

The next listing is our site page (site.html) loaded in the Python app which extends base.html. The content block is automatically set into the corresponding block in the base.html page.

<!{% extends "base.html" %}
{% block content %}
    <p class="important">
    <div id="content">
        <h2>{{title}}</h2>
        <p>{{ list_title }}</p>
        <ul>
             {% for item in list %}
             <li>{{ item[0]}} :  {{ item[1]}}</li>
             {% endfor %}
        </ul>
    </div>
    </p>
{% endblock %}