[workshop] generic sql storage in python

Andy Todd workshop@cornerhost.com
Thu, 09 May 2002 16:09:27 +1000


Michal Wallace wrote:
> (crossposted to innnercircle and workshop lists)
> 
> I'll be covering this in detail in an upcoming 
> webAppWorkshop lesson, but if anyone's interested
> you might want to check out the storage module:
> 
> http://cvs.sabren.com/sixthdev/cvsweb.cgi/storage/Storage.py?rev=1.1.1.1
> http://cvs.sabren.com/sixthdev/cvsweb.cgi/storage/MySQLStorage.py?rev=1.1.1.1
> 
> Give it a database connection in the constructor,
> it'll let you fetch and save individual records as
> python dictionaries. The only requirement is that
> you have a key named "ID"...
> 
> It's a fairly simple piece of code. Storage is the
> generic case, MySQLStorage is for MySQL. 
> 
> There's also a MockStorage which works like an in-memory 
> database (probably only useful for testing purposes):
> 
> http://cvs.sabren.com/sixthdev/cvsweb.cgi/storage/MockStorage.py?rev=1.1.1.1
> 
> 
> Sincerely,
> 
> Michal J Wallace
> Sabren Enterprises, Inc.
> -------------------------------------
> contact: michal@sabren.com
> hosting: http://www.cornerhost.com/
> my site: http://www.sabren.net/
> --------------------------------------
> 

Got it, tried it, loved it.

Just a couple of points though ;-)

1. There is a bug (I think) in MySQLStorage.py. To make it work I had to 
add an extra line to the _update method (at line 48 in the CVS file), 
making it look like;

     def _update(self, table, **row):

         sql = "UPDATE " + table + " SET"
         for col,val in row.iteritems():
             sql += " " + col + "='" + str(val) + "',"
         sql = sql[:-1]
         sql += " WHERE ID = %d" % row["ID"]

         self.cur.execute(sql)
         return self.fetch(table, row["ID"]

Without the "WHERE" clause it always trys to update every row in the table.

2. A trap for young players, when Michal said 'The only requirement is 
that you have a key named "ID"...' I didn't realise the full 
implications of what he said. I just created a column called 'ID'.

This perplexed me for quite a while (which isn't that hard) until I 
realised that this column HAD to be the primary key *and* had to be an 
AUTO_INCREMENT column, e.g.;

CREATE TABLE test_storage ( ID INTEGER AUTO_INCREMENT, ..., PRIMARY KEY 
(ID) );

Where ... is your other column definitions. Still it got me reading the 
manual to find out what on earth cursor._insert_id returned so thats a 
good thing as far as I'm concerned.

It also took me a couple of passes to get my syntax right, when using 
the 'store' method, you need to pass the data in as a series of 
parameters, e.g.;

 >>> db = MySQLdb.connect( db='test' )
 >>> storage = MySQLStorage( db )
 >>> storage.store('test_storage', COL1='COL1 Value', COL2='Col2 Value')

Don't - as I did - try and pass in a dictionary of column name:value 
pairs because that just confuses everyone.

Regards,
Andy
-- 
----------------------------------------------------------------------
 From the desk of Andrew J Todd esq - http://www.halfcooked.com