I had a problem and I figured a workaround, but I would like someone to t=
ry to explain to me what
I did wrong originally.
Problem: I want the Spam.get() method of my Spam table class to do some e=
xtra initialization stuff
(row.moreSpam()) after a row is returned (in my real case, I need to pars=
e some XML into a DOM
object from one of the strings that is returned in the table, but that de=
tail is relatively
inconsequential to the problem - I built a simple example here which just=
adds an extra attribute
to the class and the failure is identical).
When I started out, I created the following SQLObject subclass:
eric =3D StringCol(length=3D32)
self.idle =3D 'marvelous Spam' # this is where all the 'extra stuff=
' would go
Pretty simple. I put in an appropriate connection and did the following:
row =3D Spam.get(1)
print row.eric -> displays 'wonderful Spam'
print row.idle -> displays 'marvelous Spam'
(Of course, the "idle" attribute is not actually connected to the table, =
only the "eric" attribute
is, but in my case, that's fine. I would add some helper methods to make=
sure that if the "idle"
attribute is modified, it does the appropriate thing. In my case, it wou=
ld reencode the XML and
update the table's actual string attribute with the reencoded XML string)=
This works fine, but it is prone to failure since if other uses of get() =
occur, then I (or others)
might not remember to call the moreSpam() method after the row is returne=
d (in my real world case,
this is critical since the decoded XML data is necessary for the rest of =
the app to work).
In any case, the purpose of inheritance/encapsulation is exactly to hide =
this kind of stuff so it
happens automagically. What I really wanted is the get() method to add t=
he extra initialization
behavior after it gets back the row object.
From past experiences with other languages (Objective-C) using a database=
kit similar to
SQLObject, I figured I would just override the get() method in my Spam cl=
ass, call the "super"
get() method from SQLObject (which will get me back the row) and then add=
the necessary call to
So I tried adding this to the bottom of the Spam class:
obj =3D SQLObject.get(cls,id) # get the row object for 'id', your 'n=
ormal' get() call
obj.moreSpam() # this should add the idle attribute to =
the row object
return obj # return the row object as get() normall=
get =3D classmethod(get) # silliness needed to make class metho=
Now, if you do:
row =3D Spam.get(2)
it fails with the following:
Traceback (most recent call last):
File "<pyshell#48>", line 1, in -toplevel-
File "C:\xampp\xampp\htdocs\cats\test.py", line 23, in get
obj =3D SQLObject.get(self,id)
File "C:\Python24\lib\site-packages\sqlobject\main.py", line 890, in ge=
id =3D cls.sqlmeta.idType(id)
TypeError: int() argument must be a string or a number
I tried different approaches to change the the overridden method and noth=
ing improved matters.=20
So, on a hunch, I tried doing a real hack. I removed the stuff I had add=
ed to the Spam class and
then subclassed the Spam class and put the new get() method there as foll=
obj =3D Spam.get(id)
get =3D classmethod(get)
Now, when I did row =3D SubSpam.get(2), everything worked peachy, and the=
extra row.idle attribute
appeared perfectly with no problem.
So this hack works, but I contend it is a hack. I see no reason why I sh=
ould have to add another
level of class inheritance to this problem. Spam is already a subclass a=
nd everything I have done
shouldn't cause this problem.
The only thing I can see that is different is that I am calling Spam.get(=
) in my sub-subclass
whereas originally I was calling SQLObject.get() because that was its sup=
erclass. I assume there
is some problem with way the metadata connections work in the original de=
rived class (Spam) and
the SQLObject class when it is called directly). However, it still seems=
really fishy to me and
I'd love to understand it.
Anyone have any ideas?