mike watkins dot ca : August 19 2004 Archives

August 19 2004

No need to switch to Ruby from Python

Noted on the web today, a bunch of discussion about Ruby, a framework called Rails and an application written quickly using the framework called BaseCamp. I’d seen BaseCamp in my web travels earlier this year and was very impressed, so it was interesting to learn that a so-called lesser scripting language (by the Java zealots) was used for this project.

Preaching to the choir for me, Python has turned out to be my indispensible Swiss-Army knife of tools and I can’t imagine living without it.

Naturally my curiousity was peaked on reading about the Rails framework. I have to say that ActiveRecord looks familiar to me – very much like SQLObject in use.

I’ve used three different ORM with Python – Object Relational Membrane (thank you Dieter), Cucumber by Titus Brown (you can find this on Sourceforge), and SQLObject by Ian Bicking. Of the three, SQLObject most closely resembles Rails::ActiveRecord in that its auto discovery of schema and easy building of relations makes it possible to super-quickly put something together.

Meeting application layer needs, Quixote fits the bill very nicely indeed.

Sorry Ruby, the demo just didn’t catch my eye… after discovering that I love whitespace enforcement in Python some years ago now, I could never go to a language that makes me put end all over the place. Ugh!

Not to take anything away from BaseCamp (I love 37 Signals’ design work), Ruby or Rails – I think its just great that languages like Python and Ruby are attracting the attention of Java / ASP / .NET developers using less friendly tools.

Noted in my RSS feed stream today, Andrew commented on the friendly community that has developed around Python – this factor is another reason for supporting the language. Coincidentally he pointed out a thread where discussing helping a newbie with Python DBI cursor access – what follows is a quick summary of how to use SQLObject in part spurred on by the talk about Ruby…



from sqlobject import *
__connection__ =  'postgres://testuser@localhost/testdatabase'


class Status(SQLObject):
    _fromDatabase = True
    

class Document(SQLObject):
    _fromDatabase = True
    
    
    status = ForeignKey('Status')
    contents = MultipleJoin('Content')


class Content(SQLObject):
    _fromDatabase = True
    document = ForeignKey('Document')




And that’s it. You now have three related objects, all their attributes, data conversions to and from the target database, all done automatically. Note, no coding and nor any obtuse mucking about with database-level stuff.

Lest the Ruby folks consider _fromDatabase a waste of space, they’d be right in guessing that leaving it out allows you to define the DB in Python, and a simple call to SomeObject.createTable() does the job. This is really handy, allowing schema ‘definitions’ to reside in Python language bits, no re-synching between SQL code and Python needed.

SQLObject supports multiple DB’s from PostgreSQL (my personal favorite), MySql, SQLite and others.

SQLObject is also able to easily adapt to schemas which don’t follow its conventions—all primary keys are unique, “id”; foreign keys are all tablename_id i.e. status_id. These defaults can be overridden.

Here’s the a script to exercise the objects lightly:


print 10*'-'
print "1 - Documents in our db:", len (list(Document.select()))


print 10*'-'
d = Document.get(2476)
print "2 - Document object: ", d


print 10*'-'
print "3- Print status object associated with document: ", d.status
print "status.code", d.status.code


print 10*'-'
print "4- Content object(s) associated with document: ",
print d.contents


print 10*'-'
print "5 - Retrieve a specific content object and get its parent document: ",
c = Content.get(2477)
print c.document


print 10*'-'
print "6 - Show off one of the query mechanisms, num matches: ",
result = list(Content.select(Content.q.title == 'Headlines and Reaction'))
print len(result)




That all results in:

1 – Documents in our db: 1238
—————
2 – Document object: expirationDate=None creationDate= modificationDate=None productID=None creatorID=1220 doctypeID=42>
—————
3 – Print status object associated with document: modificationDate=None>
status.code draft
—————
4 – Content object(s) associated with document: [ modificationDate=None version=None creatorID=86>]
—————
5 – Retrieve a specific content object and get its parent document: expirationDate=None creationDate= modificationDate=None productID=None creatorID=1220 doctypeID=42>
—————
6 – Show off one of the query mechanisms, num matches: 7

Crap, if I am going to start writing for my personal blog again I guess I better fix up the layout and CSS once more. Cobbler’s children and all…