Tag Archives: mako

A Funny Thing Happened on the Way to the Webserver

Some years ago, I was looking for forum software, preferably written in Python, so I found Pocoo’s original bulletin board project. Since then, I’ve kept an eye on the Pocoo team, experimenting early on with Werkzeug, and using Pygments (indirectly) and Sphinx (for the documentation of the Pyrseas project). I also heard about Jinja but, I guess because I was already invested in Mako Templates, wasn’t much interested in a Django Templates lookalike.

Fast forward to the present and this database user interfaces tutorial and project. My next step was going to replace my dinky WSGI “server” and associated routing code by a robust and substantial alternative. I was almost set on using CherryPy, but had some doubts.

CherryPy is a solid WSGI server framework. I chose it on previous projects, over others such as Zope, Django, TurboGears and Pylons, primarily because it’s relatively lightweight and, as they say, “agnostic.” CP doesn’t include nor even suggest its own template language, ORM or database layer, or JavaScript library. The one thing that may take some getting used is its URI mapping scheme.

In spite of the above, I thought that CherryPy was perhaps too heavy a dependency to add to the project and particularly to this tutorial. So I kept my eyes and ears open to alternatives.

About a month ago, I briefly encountered Flask and dismissed it, thinking, “Hmm, just Werkzeug and Jinja put together.” I’m not quite sure what prompted me to look further this past week. Maybe it was the recent comments by Armin and P.J. Eby’s responses introducing WSGI Lite.

The funny thing is I delved into Flask and liked what I saw. The URL routing decorator is quite attractive, and useful. I was largely convinced by the argument for having one template engine. The question then became: should I replace Mako by Jinja2? And, can Jinja2 do something similar to those Mako <%def%> tags I talked about earlier?

I was pleasantly surprised. In fact, Jinja’s equivalent for those tags are called macros and its documentation uses an HTML <input> for its example of a macro.

The bottom line is I very easily replaced Mako by Jinja2 (code in GitHub tagged as v0.2.3). I’m still exploring Flask and considering it as an alternative to CherryPy as the underlying framework.

Templating for Web Database Interfaces

If you count the number of lines in the HTML files of the (corrected) v0.2 of the minimalist WSGI database interface I presented earlier, you’ll find 228 non-blank lines. However, there are only 91 unique lines. In other words, there is 60% repetition. Not a good example of the Don’t Repeat Yourself (DRY) principle.

In addition, film.py has seven lines with embedded HTML tags. It would be best if the HTML formatting code (i.e., the View code in MVC terms) resided all within the templates.

Therefore, it is time to replace the bare-bones templating scheme with something more full-featured.

Over the past few years, I have used or experimented with Cheetah, Django templates, Genshi, Kid, Mako, Mighty,  Zope’s TAL and perhaps others that don’t readily come to mind. I’ve settled on Mako primarily for the features I’ll explain below.

When creating database interfaces, particularly of the CRUD or administrative type, much of the repetition comes from defining input elements for each database attribute, e.g., <input>, <select> and <textarea> HTML elements. Moreover, the HTML form to input a new record may be almost identical —but not quite— to the form to update or display an existing record.

My solution to this DRY dilemma has been to use Mako’s <%def> tags, in conjunction with Mako namespaces, to create a library of HTML form “functions” that simplify the specification of input elements.

The following excerpt from templates/forms.html illustrates these concepts:

% if errors and name in errors:
  <div class="errmsg">${errors[name]}</div>
% endif
</%def>\
...
<%def name="text(name, label, size, value=None, readonly=False)">
<div>
${error(name)}\
  <label for="${name}">${label}: </label>
  <input type="text" id="${name}" name="${name}" size="${size}"\
${value and (' value="%s"' % unicode(value).replace('"', '&quot;')) or ''}\
${readonly and ' readonly="readonly"' or ''} />
</div>\
</%def>

The following is templates/film/fields.html which is used by both the new.html and edit.html templates to define the same three input fields:

<%namespace name="form" file="/forms.html"/>
<%page args="edit=False"/>
<fieldset>
  <%form:text name="id" label="Id" size="10" value="${id}"
              readonly="${edit}"/>
  <%form:text name="title" label="Title" size="64" value="${title}"/>
  <%form:text name="release_year" label="Release Year" size="10"
              value="${release_year}"/>
</fieldset>

The templates/film/new.html file incorporates the above as follows:

<%namespace file="fields.html" name="fields"/>
...
    ${fields.body()}

If you run the application and press the Save button on the New Film page without entering anything, the three files above combine to generate the following HTML for the Id field:

<div class="form-row">
  <div class="errmsg">Id must be a positive integer</div>
  <label for="id">Id: </label>
  <input type="text" id="id" name="id" size="10" />
</div>

The errmsg <div> comes courtesy of the application passing a form ‘errors’ argument to the render() function and the opening %if in forms.html. You can also see that the text %def creates the form-row <div> as well as both the <label> and <input> elements. In edit.html, fields.body() is called with edit=True and as a result, the input element also gets a readonly attribute.

The forms.html “library” includes support for text, checkbox, select and textarea elements (the latter three are not currently used by this application). Counting unique vs. overall lines in the templates we now find only 25% repetition which is a good improvement over the original.

The complete code is available at GitHub, tagged as v0.2.1.

I’d like to take this opportunity to thank Mike Bayer for creating Mako templates and to encourage others to give them a try.

A Minimalist WSGI Database User Interface

In a previous post, I presented a minimalist command line database user interface. Subsequently, I separated the business logic into its own module and presented an outline design for a web interface. Today I’ll go over a minimalist WSGI database interface. To try it out, do the following:

$ git clone git://github.com/jmafc/database-ui-tutorial.git dbui
$ cd dbui
$ createdb moviesdev
$ yamltodb moviesdev film.yaml | psql moviesdev
$ cd wsgi
$ python dbapp.py moviesdev

The pre-requisites (Git, PostgreSQL, Python, Psycopg2 and Pyrseas) have not changed. If you previously experimented with the command line interface, you’ll want to do a git pull and then the last two steps above. To browse the code, visit GitHub.

Caveat: I used Python’s standard library wsgiref package to develop the barest functionality that I needed for this tutorial. It’s not an attempt to create YAPWF (Yet Another Python Web Framework). With that said, since we’re dealing with a film database, let’s review the various protagonists and crew members.

Supporting Cast

server.py

This is about the most basic WSGI server you can write. For a real appplication, you’ll want to use CherryPy (perhaps fronted by nginx or Apache), Apache with mod_wsgiFlask or any number of other WSGI frameworks.

static/*.css

Two Cascading Style Sheets are provided: base.css and app.css. They implement a theme similar to Django’s admin application.

URL routing

Routing of requests occurs in the dispatch methods of classes DatabaseApp (in dbapp.py) and FilmHandler (in film.py), see Main Characters below. Everything is hard-coded with if/elif/else logic. In real life, you’d want to use something like CherryPy’s exposed objects, Routes or the routing features of your framework.

templating.py

You can’t get much more austere than this templating “engine.” It expects to find template files at a fixed location (see below) and a dictionary for string formatting. For a non-tutorial application, take a look at Mako, Jinja or the templating features of your web framework.

templates/*.html

The home.html template presents a trivial menu. The error/404.html file is used for Not Found responses. The templates/film subdirectory has four files: list.html displays all movies in an HTML table, new.html is used to accept input for a new record, edit.html to display an existing record and allow changes or deletion, and delete.html requests confirmation prior to executing a DELETE.

dblib.py

This simple database interface library is making a repeat appearance, but it has been revamped into a DbConnection class so that it can be easily shared by the main players.

bl.py

The business logic module is essentially unchanged, only adapted to use the DbConnection class.

errors.py

This just declares two Exception classes for use by the two main modules.

Main Characters and Crew

dbapp.py

Continuing with movie analogies, dbapp.py runs the show, like a film director. It defines two simple Request and Response classes and the main DatabaseApp class. The latter’s main attraction it its __call__ method, the heart of a WSGI interface. In as few lines as possible, it implements:

  • serving the normal HTML responses
  • serving the CSS files
  • serving HTTP 404 Not Found responses
  • simple redirects to its own URLs

film.py

This is the leading performer and accordingly it has the most lines. It first defines a FilmForm class which encapsulates the HTML form or HTTP query string data. Its validate method incorporates the field validation originally present in the edit function of cmdline/dbapp.py.

The FilmHandler class implements the methods to respond to each HTTP request. Consider what happens when the user selects the /film/new link from the menu or film listing pages. The dispatch methods then cause the FilmHandler new method to execute which renders the new.html form.

After the user enters the data and clicks Save, the dispatch methods invoke the create method. This uses FilmForm to extract and validate the data. If a validation error is present, the form is redisplayed with a simplified error mechanism. Otherwise, the business logic insert function is called. If a database error occurs, the form is redisplayed with the error from psycopg2 and PostgreSQL. If everything is OK, the transaction is committed and the application redirects to the film listing page.

For now, the application does not use any Javascript, so it’s overall interaction is not the most user friendly. However, if you’re new to WSGI, I hope you’ll take some time to review the application and that you’ll find it instructive.