Thread: [SQLObject] two beginner's questions
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: Bud P. B. <bu...@si...> - 2003-04-28 17:22:12
|
Here are two beginner questions that I hope someone can help me with: 1. is it possible that I have to assign __connection__ before defining subclasses of SQLObject? When I don't do this, I seem to run into problems. 2. is there a way to control redundancy in the following example: class test1 (SQLObject): _columns = [StringCol("lang", lenght=2, default='en'), IntCol("someOtherStuffHere")] class test2 (SQLObject): _columns = [StringCol("lang", lenght=2, default='en'), StringCol("differentStuffThanInTest1")] I would like to decide only once how to represent a language in the DBMS and use this consistently in various class definitions. I unsuccessfully tried to define a StringCol object, langCol, before and use it in the _columns definition. This does not seem to work if I use it in more than one class though. I also tried to define a function that returns an instance of StringCol, but this didn't even work once... I hope someone can point out what I'm doing wrong! Many thanks --b /----------------------------------------------------------------- | Bud P. Bruegger, Ph.D. | Sistema (www.sistema.it) | Via U. Bassi, 54 | 58100 Grosseto, Italy | +39-0564-411682 (voice and fax) \----------------------------------------------------------------- |
From: Nick <ni...@dd...> - 2003-04-28 18:40:05
|
On Mon, 2003-04-28 at 12:21, Bud P.Bruegger wrote: > 1. is it possible that I have to assign __connection__ before defining > subclasses of SQLObject? When I don't do this, I seem to run into > problems. Yes, or define _connection in each subclass. > 2. is there a way to control redundancy in the following example: > > class test1 (SQLObject): > _columns = [StringCol("lang", lenght=2, default='en'), > IntCol("someOtherStuffHere")] > > class test2 (SQLObject): > _columns = [StringCol("lang", lenght=2, default='en'), > StringCol("differentStuffThanInTest1")] I had this same problem; I tried to do the same thing by making supertest a class and test1 and test2 subclasses, but that didn't work. It doesn't look like the architecture allows this. Is that right? Nick |
From: Frank B. <fb...@fo...> - 2003-04-28 21:09:05
|
Hallo, Bud P.Bruegger hat gesagt: // Bud P.Bruegger wrote: > 2. is there a way to control redundancy in the following example: > > class test1 (SQLObject): > _columns = [StringCol("lang", lenght=2, default='en'), > IntCol("someOtherStuffHere")] > > class test2 (SQLObject): > _columns = [StringCol("lang", lenght=2, default='en'), > StringCol("differentStuffThanInTest1")] > > I would like to decide only once how to represent a language in the > DBMS and use this consistently in various class definitions. > > I unsuccessfully tried to define a StringCol object, langCol, before > and use it in the _columns definition. This does not seem to work if > I use it in more than one class though. What about this: class Lang (SQLObject): _columns = [StringCol("lang", length=2, unique=1)] class test1 (SQLObject): _columns = [IntCol("langID", foreignKey="Lang"), IntCol("some")] class test2 (SQLObject): _columns = [IntCol("langID", foreignKey="Lang"), StringCol("different")] en = Lang.new(lang="en") t1 = test1.new(langID=en.id, some=1) t2 = test2.new(langID=en.id, different="foo") print t1.lang print t2.lang ciao -- Frank Barknecht _ ______footils.org__ |
From: Luke O. <lu...@me...> - 2003-04-28 23:19:49
|
> On Mon, 2003-04-28 at 12:21, Bud P.Bruegger wrote: > > 1. is it possible that I have to assign __connection__ before > defining > > subclasses of SQLObject? When I don't do this, I seem to run > into > > problems. > > Yes, or define _connection in each subclass. Or define a superclass for all your sublcasses that defines _connection. > > 2. is there a way to control redundancy in the following example: ... > I had this same problem; I tried to do the same thing by making > supertest a class and test1 and test2 subclasses, but that didn't > work. > It doesn't look like the architecture allows this. Is that right? Correct, the architecture is a single level of abstraction between a relational database and python objects. It is a significantly harder piece of work to map arbitrary inheritance trees to a relational database, with specific tradeoffs on either the relational or inheritance/type side of things. http://www.agiledata.org/essays/mappingObjects.html makes many points about the challenges here, and possible implementations. Alternatively, I tend to subscribe to Chris Date's views on the merits of Relation-driven (relational calculus view of types) data design as opposed to Object-driven data design. (http://www.dbdebunk.com/). As a thin-mapper, I feel that SQLObject supports this viewpoint (but that doesn't everyone on this list does :). Back on track: I would personally recommend that the solution in the Relational world is probably Frank's Lang(SQLObject), with foreignKeys in your other classes. Inheritance for the sake of Implementation is to be particularily wary of for me, and that's what this case is. - Luke |
From: Nick <ni...@dd...> - 2003-04-29 03:01:19
|
On Mon, 2003-04-28 at 17:36, Luke Opperman wrote: > Correct, the architecture is a single level of abstraction between a > relational database and python objects. It is a significantly harder > piece of work to map arbitrary inheritance trees to a relational > database, with specific tradeoffs on either the relational or > inheritance/type side of things. I don't think it's really a limitation of the model as much as the implementation. SQLObject sets up properties and functions in a very new class style, which is cool and flexible. You'll notice in the __new__ function of the metaclass how get and set properties are set up, along with assigning other attributes to lambda functions to set up the addX removeX etc. On the other hand, my implementation used __getattr__ and __setattr__ trapping to manage properties very late, at access time. This gives you the flixibility of being able to use inheritance very well, but it does slow down things a bit to have to resolve every attribute every time you access it. What is the goal behind the architecture currently in use vs. the kind I described? A lot of my experience in metaclassing comes from classic classes, so I've learned a lot from the code, but I'm wondering what particular advantages it has over the late binding I'm describing. On the surface it appears to be more limiting, but I'm ready to be enlightened :) Nick |
From: Luke O. <lu...@me...> - 2003-04-29 03:13:38
|
> What is the goal behind the architecture currently in use vs. the > kind I > described? A lot of my experience in metaclassing comes from > classic > classes, so I've learned a lot from the code, but I'm wondering > what > particular advantages it has over the late binding I'm describing. > On > the surface it appears to be more limiting, but I'm ready to be > enlightened :) Hmm, I rather more deeply knowledgable about SQLObject's implementation than your own, so rather than puzzle it out myself, care to give a quick overview of the additional things made available by late binding? If you're not dynamically altering the class based on sub/super attribs, and you're mapping to a somewhat normalized set of relations (as opposed to meta-tables of class/attributes or similar), I don't see the difference from an inheritance perspective at least. But like I said, you can probably tell me faster than I can figure it out. Were there other benefits to the late-binding scheme? I'd say the one immediate advantage to the metaclass system is that it seems much easier to introspect on than __getattr__/__setattr__ systems I've seen in the past. I suppose of immediate interest to this thread is how a late-binding system would make implementation-inheritance like the original poster was looking for possible. It still needs to map to some set of tables, the easiest but of least interest to me for an ORM being the meta-table system. (the four primary ways of doing so being mentioned in the Ambler article I linked to; SQLObject takes the route of "Table for each concrete class, and all classes are concrete" :) ) - Luke |
From: Nick <ni...@dd...> - 2003-04-29 03:46:14
|
On Mon, 2003-04-28 at 21:59, Luke Opperman wrote: > care to give a quick overview of the additional things made available > by late binding? If you're not dynamically altering the class based > on sub/super attribs, and you're mapping to a somewhat normalized set > of relations (as opposed to meta-tables of class/attributes or > similar), I don't see the difference from an inheritance perspective > at least. The main problem is the complexity you introduce with new style metaclassing using type as the super. I believe it may be possible to handle inheritance correctly, but as it is you can't really subclass a class that inherits from SQLObject. The way you defined my classes were extremely similar-- you provide the class attributes table, key, attributes, collections (_table, _idName, _columns, _joins). attributes was a dictionary rather than a list, with the keys being the attributes and the values being an Attribute object, similar to Col. I found converting code from my classes to SQLObject extremely trivial, and in some ways the resulting class definition was much simpler using SQLObject. However, my registration function only registered each class in a dictionary for reference like SQLObject does, but that's it. When you called db the DB lookup methods (which I called new() for inserts, getUnique() for unique lookups and getAggregate() to get a list of objects matching a condition), the results of the queries were stored in Value objects that track each attribute's value (and controlled type normalization, update tracking, etc.). When you tried to make a property access, __getattr__ resolved the name according to the aforementioned attributes dictionary, handling all the type checking etc. > Were there other benefits to the late-binding scheme? I'd say the one > immediate advantage to the metaclass system is that it seems much > easier to introspect on than __getattr__/__setattr__ systems I've > seen in the past. True; introspection is very limited using __getattr__ and __setattr__, but then again, what kind of introspection are you looking for here, in practical use. Sure, you won't be able to do dir(class), but all that information was available in other ways. Maybe some examples? > I suppose of immediate interest to this thread is how a late-binding > system would make implementation-inheritance like the original poster > was looking for possible. Since all the lookups are done when attributes are accessed, it's actually possible to alter the attributes dictionary (or any other class property) at any time without having to rebind properties or methods. Subclassing becomes a non-issue since we only register the name of the class to make sure it's unique. This has the advantage of being able to have class names that are identical get reside in different modules, by the way. > It still needs to map to some set of > tables, the easiest but of least interest to me for an ORM being the > meta-table system. Indeed; my model was very similar to SQLObject in many, many ways, and worked almost identically from a practical standpoint. Only the internals and method names were different. SQLObject does some things nicer, but I think that's just having better ideas for how things should be accessed than me rather than other limitations :) I'm not sure if I'm really answering your questions though. Nick |
From: Luke O. <lu...@me...> - 2003-04-29 04:57:02
|
Nick - See my most recent reply to the list, triggered by your comment "can't subclass a class that inherits from SQLObject". I do this all the time for setting up common _connection's, so I figured I'd try it with columns, what this whole thread was about... and found that it worked! (caveats: only worked with 0.3 release, not tonight's CVS, only tested with DBMConnection, and you'll still need a real table for every concrete class you instantiate.) So I'm still not seeing what late-binding gets you (since the addX/removeX functions allow late re-definition), and anyways, we all ought to be happy subclassing works. :) Or something. Now, to track down what's wrong in CVS, and get a start on that python-based Transaction plan I started talking about... - Luke |
From: Luke O. <lu...@me...> - 2003-04-29 04:47:38
|
> 2. is there a way to control redundancy in the following example: > > class test1 (SQLObject): > _columns = [StringCol("lang", lenght=2, default='en'), > IntCol("someOtherStuffHere")] > > class test2 (SQLObject): > _columns = [StringCol("lang", lenght=2, default='en'), > StringCol("differentStuffThanInTest1")] > > I would like to decide only once how to represent a language in the > DBMS and use this consistently in various class definitions. > > I unsuccessfully tried to define a StringCol object, langCol, I know we're getting caught up in all sorts of things tangentially related (I'm currently in the midst of figuring out why making an abstract class with columns and then saying _columns = Super._columns + [] doesn't quite work...) But there is a somewhat simple non-SQLObject-inheritance-based way to get what you want, without the foreign table suggested by Frank. Rather than define a StringCol object, define a LangCol *class* which is a subclass of StringCol. Something like this ought to work: class LangCol(StringCol): def __init__(self, **kw): kw['length'] = 2 kw['default'] = 'en' StringCol.__init__(self, 'lang', **kw) Yep, just tested this out. Actually, just tested my example above with Super._columns, and it works too! (Using 3.0. All classes currently have a problem with CVS checked out 10 minutes ago, which was throwing me off.) So. To elaborate. You can either define your common column type as a subclass of Col (or StringCol, etc). Or you can use SQLObject inheritance with a structure like: class AbstractObject(SQLObject): _columns = StringCol('lang') class Z(AbstractObject): _columns = AbstractObject._columns + [StringCol('nother')] class Y(AbstractObject): _columns = AbstractObject._columns + [StringCol('further')] And all of this actually seems to work in SQLObject 0.3, tested using DBMConnection. Wow. What do you say to that, Nick? :) - Luke P.S. I'm still tracking down the problem with CVS, but it initially appears to be related to _SO_plainSetters and addColumn. Just a heads up, Ian. |
From: Nick <ni...@dd...> - 2003-04-29 05:08:38
|
On Mon, 2003-04-28 at 23:33, Luke Opperman wrote: > class AbstractObject(SQLObject): > _columns = StringCol('lang') > > class Z(AbstractObject): > _columns = AbstractObject._columns + [StringCol('nother')] > > class Y(AbstractObject): > _columns = AbstractObject._columns + [StringCol('further')] > > And all of this actually seems to work in SQLObject 0.3, tested using > DBMConnection. Wow. What do you say to that, Nick? :) Okay, well that's cool :) I've been working with classic objects for so long (since '97) that I'm still trying to get a handle on the new style classes. SQLObject is really complex in that area, and I'm still trying to grok it all (I've only been looking at it for about 3 days tho). Hopefully I can get up to speed soon to be able to contribute something useful :) Nick |
From: Ian B. <ia...@co...> - 2003-04-29 08:26:20
|
On Mon, 2003-04-28 at 23:33, Luke Opperman wrote: > class LangCol(StringCol): > def __init__(self, **kw): > kw['length'] = 2 > kw['default'] = 'en' > StringCol.__init__(self, 'lang', **kw) This is exactly what I would have suggested. Note it can be somewhat shorter: class LangCol(StringCol): def __init__(self, **kw): StringCol.__init__(self, 'lang', length=2, default='en', **kw) Ian |
From: Bud P. B. <bu...@si...> - 2003-04-29 08:33:30
|
The good thing about time differences is that you get back to work and the problem is solved and digested... Many thanks for all the interesting answers. I particularly like the one below. I assume that this should work also in upcoming versions... --b On Mon, 28 Apr 2003 23:33:34 -0500 Luke Opperman <lu...@me...> wrote: > > > 2. is there a way to control redundancy in the following example: > > > > class test1 (SQLObject): > > _columns = [StringCol("lang", lenght=2, default='en'), > > IntCol("someOtherStuffHere")] > > > > class test2 (SQLObject): > > _columns = [StringCol("lang", lenght=2, default='en'), > > StringCol("differentStuffThanInTest1")] > > > > I would like to decide only once how to represent a language in the > > DBMS and use this consistently in various class definitions. > > > > I unsuccessfully tried to define a StringCol object, langCol, > > I know we're getting caught up in all sorts of things tangentially > related (I'm currently in the midst of figuring out why making an > abstract class with columns and then saying _columns = Super._columns > + [] doesn't quite work...) > > But there is a somewhat simple non-SQLObject-inheritance-based way to > get what you want, without the foreign table suggested by Frank. > Rather than define a StringCol object, define a LangCol *class* which > is a subclass of StringCol. Something like this ought to work: > > class LangCol(StringCol): > def __init__(self, **kw): > kw['length'] = 2 > kw['default'] = 'en' > StringCol.__init__(self, 'lang', **kw) > > Yep, just tested this out. Actually, just tested my example above with > Super._columns, and it works too! (Using 3.0. All classes currently > have a problem with CVS checked out 10 minutes ago, which was > throwing me off.) > > > So. To elaborate. You can either define your common column type as a > subclass of Col (or StringCol, etc). Or you can use SQLObject > inheritance with a structure like: > > class AbstractObject(SQLObject): > _columns = StringCol('lang') > > class Z(AbstractObject): > _columns = AbstractObject._columns + [StringCol('nother')] > > class Y(AbstractObject): > _columns = AbstractObject._columns + [StringCol('further')] > > And all of this actually seems to work in SQLObject 0.3, tested using > DBMConnection. Wow. What do you say to that, Nick? :) > > - Luke > > P.S. I'm still tracking down the problem with CVS, but it initially > appears to be related to _SO_plainSetters and addColumn. Just a heads > up, Ian. > > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > sqlobject-discuss mailing list > sql...@li... > https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss > /----------------------------------------------------------------- | Bud P. Bruegger, Ph.D. | Sistema (www.sistema.it) | Via U. Bassi, 54 | 58100 Grosseto, Italy | +39-0564-411682 (voice and fax) \----------------------------------------------------------------- |
From: Ian B. <ia...@co...> - 2003-04-29 08:38:56
|
On Mon, 2003-04-28 at 23:33, Luke Opperman wrote: > So. To elaborate. You can either define your common column type as a > subclass of Col (or StringCol, etc). Or you can use SQLObject > inheritance with a structure like: > > class AbstractObject(SQLObject): > _columns = StringCol('lang') > > class Z(AbstractObject): > _columns = AbstractObject._columns + [StringCol('nother')] > > class Y(AbstractObject): > _columns = AbstractObject._columns + [StringCol('further')] > > And all of this actually seems to work in SQLObject 0.3, tested using > DBMConnection. Wow. What do you say to that, Nick? :) > > - Luke > > P.S. I'm still tracking down the problem with CVS, but it initially > appears to be related to _SO_plainSetters and addColumn. Just a heads > up, Ian. Okay, I think I figured out what the problem is, but not the solution. Column objects are bound to the class they are used with. During class initialization, Col.setClass gets called, with the class argument. At that point some fixing up occurs -- new with 0.4, for instance, you can do: class Z(SQLObject): nother = StringCol() After instantiation the StringCol object is given its name, and only then can it set some things like .dbName. Style information also comes into play at that point. So I'm not sure... I guess to fix this the original column definition has to be left alone, and the column object needs to be cloned by MetaSQLObject and then tied to the class. Arr... that's a pain. I do want subclassing to be possible, though (and with the new way of defining columns it should be more pleasant to use). Ian |