odb.py

ODB is a Python object database mapping tool.

One could consider it an object relational mapper, however, unlike ORM tools such as Hibernate, odb.py is not concerned with creating a mapping between differently structured database tables and objects, but instead seeks to make working with similarly structured tables and objects as easy and as maintainable as possible.

Why do we focus on similarly structured tables and objects? We find that keeping database tables and object fields the same creates a directness and simplicity that makes code smaller, easier to understand, and easier to maintain. If a change to objects or database tables is required, an ORM indirection layer allows you to complete only half of the change, leaving one half of your system in the old state. We don't find this functioanlity, or the resulting confusion and indirection to be useful or helpful.

odb.py contains some helpful utilities to make working with clearsilver templates incredibly efficient. In this way, it could be compared to Ruby on Rails. However, odb seeks to allow you to work with any SQL schema you prefer, because your SQL schema will drive your site performance. There are no rules about how your schema must be laid out in odb.py.

Getting Started

odb.py can be found in the clearsilver kit under examples/python/base. There are currently adaptors for both mysql and sqlite. Writing an adaptor for another database is fairly simple. hdfhelp.py is the connector which makes working with odb.py and clearsilver a templates very easy.

Mapping a table

The first step is mapping your relational table with odb, and listing it in a database class. You simply list each column and it's type. Once a mapping is created, clearsilver can be used to read and write the tables, and can also create them if necessary.
from clearsilver import odb, hdfhelp, odb_mysql

class MyTable(odb.Table):
  def _defineRows(self):
    self.d_addColumn("doc_id", odb.kInteger, None, 
                     primarykey=1, autoincrement=1)
    self.d_addColumn("subject", odb.kVarString)
    self.d_addColumn("body", odb.kVarString)

class MyDB(odb.Database):
  def __init__(self, conn):
    odb.Database.__init__(self,conn)
    self.addTable("mytable","ap_mytable",MyTable)

  # this will setup the hdf helper functions that make odb easy to
  # use with clearsilver

  def defaultRowClass(self):
    return hdfhelp.hdfRow
  def defaultRowListClass(self):
    return hdfhelp.hdfItemList

def openDatabase():
  conn = odb_mysql.Connection(host="host",user="user",passwd="pass",db="dbname")
  db = MyDB(conn)
  return db
Once the mapping is created, we can read and write rows as objects.
db = openDatabase()

row = db.mytable.newRow()
row.subject = "foo subject"
row.body = "foo body"
row.save()

try:
  row = db.mytable.fetchRow( ("subject","foo subject" )
  print row
except odb.eNoMatchingRows:
  print "row could not be found"
hdfhelp.py provides some easy class handlers for pushing database data into our HDF dataset for template rendering.
rows = db.mytable.fetchRows()
rows.hdfExport(hdf)
It is common to build your own row classes to encapsulate functionality related to those rows. You can do this by specifying the rowClass option during table definition. If you also wish to easily export your rows into HDF, you may wish to make your row class a subclass of the hdfhelp classes. Alternatively, you can write your own hdfExport(self,prefix,hdf) function for your rowclass which handles exporting data into HDF in a custom format.
class MyRow(hdfhelp.HdfRow):
  def subclassinit(self):
    pass
  def makesubject(self):
    self.subject = "Subject: " + self.body

# change the table definition to
#    self.addTable("mytable","ap_mytable",MyTable, rowClass=MyRow)