If you have a simple model, SQLObject may be enough. If you want more flexibility, check out SQLAlchemy.
SQLObject was so far enough for me, but I stumbled upon a weird issue when doing updates. Once in a while my selects returned old data that had been overwritten by a previous update.
SteveA had the same problem and showed me a workaround for this, but it sounded like too much work, and it was scary that this could happen.
I decided to try out SQLAlchemy. After some hair pulling I got it working (you can see the reason for the pulling at the end of the post).
You can get the latest version by typing
easy_install sqlalchemy
Make sure you have the latest 0.9x version of TurboGears.
The model
Using the model is almost as simple as before. The model definition is more complicated, but that’s something you won’t change very often.
model.py (compare to SQLObject version. Note that I’ve added some columns not shown in the previous model):
from sqlalchemy import *
import cherrypy
db = create_engine(cherrypy.config.get('sqlalchemy.dburi'),
echo=cherrypy.config.get('sqlalchemy.echo',0))
session = create_session(bind_to=db)
meta = BoundMetaData(db)
projects = Table('project', meta,
Column('id', Integer, primary_key=True),
Column('title', String(1000), nullable = False),
)
contexts = Table('context', meta,
Column('id', Integer, primary_key=True),
Column('title', String(1000), nullable = False),
)
actions = Table('action', meta,
Column('id', Integer, primary_key=True),
Column('title', String(1000), nullable = False),
Column('project_id', Integer, ForeignKey('project.id')),
Column('context_id', Integer, ForeignKey('context.id')),
Column('notes', String(1000)),
Column('priority', Integer, default=0),
Column('closed', Boolean, default=0),
)
tags = Table('tag', meta,
Column('id', Integer, primary_key=True),
Column('title', String(1000), nullable = False),
)
tagaction = Table('tag_action', meta,
Column('action_id', Integer, ForeignKey('action.id')),
Column('tag_id', Integer, ForeignKey('tag.id'))
)
class Project(object):
def __init__(self, title, notes):
self.title = title
self.notes = notes
def __repr__(self):
return self.title
class Action(object):
def __init__(self, title, notes, project, context,
priority, closed):
self.title = title
self.notes = notes
self.context = context
self.project = project
self.priority = priority
self.closed = closed
def __repr__(self):
return self.title
class Tag(object):
def __init__(self, title):
self.title = title
def __repr__(self):
return self.title
class Context(object):
def __init__(self, title):
self.title = title
def __repr__(self):
return self.title
mapper(Tag, tags)
actionmapper = mapper(Action, actions, properties = {
'tags' : relation(Tag, secondary=tagaction)
})
projectmapper = mapper(Project, projects, properties={
'actions' : relation(Action, backref='project'),
})
contextmapper = mapper(Context, contexts, properties={
'actions' : relation(Action, backref='context'),
})
Read the rest of this entry »