Re: [SQLObject] Using SQLObjects as Abstract Classes
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
|
From: Ian B. <ia...@co...> - 2003-07-25 18:18:41
|
On Fri, 2003-07-25 at 12:27, Brad Bollenbach wrote:
> > If you have that class layout, you are supposing that there will be
> > other subclasses of Monitor. However, each of these subclasses must be
> > a separate table, or great confusion will ensue.
>
> There will only be a single monitor table. Monitors store a common set
> of properties. The only thing that's different is how they behave when
> you say "do your monitor check".
Then make that into a multiple-class object, Checker. Like:
class Checker(object):
def __init__(self, monitor):
self.monitor = monitor
def check(self):
assert 0, "Subclass responsibility"
class HTTPChecker(Checker):
def check(self): ...
class MD5HTTPChecker(HTTPChecker):
def check(self): ...
checkers = {'http': HTTPChecker, 'md5': MD5HTTPChecker}
class Monitor(SQLObject):
monitorType = StringCol(length=10)
def _get_checker(self):
return checkers[self.monitorType](self)
Voila! Composition beats inheritance!
> > Python inheritance simply doesn't map to RDBMS tables. There are things
> > that can be called inheritance among RDBMS tables, but they aren't the
> > same thing. So SQLObject just takes a one-class-one-table approach.
> > You can still use inheritance, and a class can be abstract so long as
> > you don't use it, but it's still one-class-one-table. It's improper to
> > use _table = 'monitor' in each class, because that breaks that rule. If
> > you have one table you shouldn't have more than one class that you use
> > with that table.
>
> Hrmph.
>
> I can see where you're coming from, but perhaps some thought could be
> spent on figuring out how to make that "one class" (per table) be an
> abstract class (so, I kind of really only do have class per table,
> because StatusMonitor, KeywordMonitor, etc are just there to specify
> differences in behaviour, not in attributes. That "one class" is my
> abstract base.)
It just wouldn't work. What are you going to do, fetch a generic
Monitor instance, check its type, then refetch a specific instance? Or
do a direct query to find the type, then instantiate the object with the
correct class? It just doesn't make sense. It also is going to cause
all sorts of weird structural problems when you do need more tables.
With the above technique you can add tables fairly easily. Say you want
to create a md5_checker table (to store the MD5 hash).
class MD5Checker(HTTPChecker, SQLObject):
def setMonitor(self, monitor):
HTTPChecker.__init__(self, monitor)
md5 = StringCol(length=128)
function md5CheckerGetter(self, monitor):
inst = MD5Checker.selectBy(monitor=monitor)[0]
inst.setMonitor(monitor)
return inst
checkers['md5'] = md5CheckerGetter
You don't have to create tables for every checker, just the one that
needs it. You don't have to fiddle with inheritance of the Monitor
class.
Someon, who I can't remember, and who's link I've lost, gave a link to a
good article on inheritance and how to map them. The stuff I've written
above follows one of them (one table for each class, including abstract
classes), while standard inheritance in SQLObject is one table per
concrete class. Implementing the former directly in SQLObject is, IMHO,
a lot of work for nothing, since multiple classes is superior in Python
just like multiple tables are superior in the database (IMNSHO). It may
not seem easier to implement (though I don't think it's any harder), but
I think it will be much easier to maintain, and result in more readable
code.
Ian
|