mike watkins dot ca : Python Web Application Diary, Part Three

Python Web Application Diary, Part Three

In part two of this series we created a location and file system hierarchy for application library objects, UI and other components, and did the same for an actual application by using a script mkqpapp.py that automates those tasks.

Today lets start writing code -- we'll begin by defining basic objects for managing weblog or journal entries, and then we'll move on to showing how QP and Durus make defining and publishing your Python objects as easy as, well, py.

Basic Data Elements

As discussed in part one, this tutorial / web application project will result in a basic weblog or on-line journal application. Lets break down a weblog into its most basic data elements:

  1. A weblog is a collection of writing, generally presented in chronological fashion. A weblog could be considered a diary or journal, so lets use the term Journal to describe its function.
  2. A journal usually, but not always, represents the thoughts and opinions of a single author.
  3. Each item in a journal can be considered an article or a post - lets use a more generic term and call each item in the journal an Entry. Entries are typically short bits of text so lets enter and store them as such. Each entry may have a title, and may include other information including dates relating to when the Entry was created, made available to readers, or changed -- but the principal information is the entry itself.

Our first classes

Turning to Python then, we could easily represent Entry as:

class Entry(object):
    title = None
    text = None
    created = None

We could then use the class:

e = Entry()
e.title = 'Python Web Application Diary, Part Three'
e.text = 'Hello, Bruce, my name is Bruce.'
created = datetime.datetime.now()

That was pretty simple, no? Simplicity can be both a boon and a pain in the butt, and experienced developers will recognize at least two significant problems with our still too-simple Entry object:

  1. There is no way of easily persisting this data (saving it so that its available later when we need it)
  2. The current design doesn't warn or otherwise prevent someone from intentionally or accidentally storing data we don't expect, such as:
e = Entry()
e.title = datetime.datetime.now()
e.created = 'Python Web Application Humour'

Kicking Entry Up a Notch - Persistence

Lets first look at the issue of persistence. Keeping our journal entries around for future display (or edits) could be done by:

  • Saving the data into individual files
  • Saving the data in a relational (SQL) database such as Postgres, Oracle, MySQL or MS SQL Server

To SQL or not to SQL, that is the question

Most often these days by default a developer will turn to a SQL database to store and manage persistent data. While there is nothing wrong with this, introducing SQL into the mix does complicate matters some what. SQL types are not exactly analogous to Python data types, and accessing and updating data held in a SQL repository can often require lots of tedious SQL code, in addition to your Python code and objects.

To ease the friction or so-called impedance mismatch between Python and SQL, various Object Relational Mappers (ORMs) have appeared on the Python scene. While ORMs like SQLObject and SQL Alchemy do make using SQL-based data within a Python application somewhat more convenient, its equally true that not all applications need the added complexity and there are other alternatives which can be useful to Python programmers regardless of complexity.

QP doesn't enforce a particular data persistence approach upon a developer, but it does make a choice for you which you can then consciously choose to ignore.

Durus, a Python Object Database

Rather than deal with the impedance mismatch between Python and SQL, QP by default uses Durus, a Python object database, to persist application data.

The truly neat thing about Durus, for Python users, is that you almost know how to use it now, sight unseen.

Lets take our dirt-simple Entry object and make it database aware. You'll recall the basic object looked like this:

class Entry(object):
    title = None
    text = None
    created = None

An Entry object able to participate in the Durus object database looks like this:

class Entry(PersistentObject):
    title = None
    text = None
    created = None

As you can see, other than subclassing a special Durus type, PersistentObject, there are no outward differences. We can therefore make a straightforward claim: Durus is the database you already know.

We'll revisit Durus and object persistence in a future installment. In Part Four of this series we shall take our too-simple, but persistent, object and show how specifications can add useful constraints. We'll also take our first look at Sancho, a unit testing framework.