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.