Hey everyone,

I *think* this is a limitation of having classes that are
polymorphic_on a join (instead of mapping a join), but I'm going to
ask anyway to make sure I understand.

I have a hierarchy of mappers to represent various network interfaces
on various devices.  This is polymorphic_on a join to the
discriminator of the assocated device records:

-----
iftype_join = select([device_t.c.model], 
from_obj=[interface_t.join(device_t)]).alias()
interface_m = orm.mapper(InterfaceBase, interface_t,
                         polymorphic_on=iftype_join.c.model,
                         polymorphic_identity=0,
                         properties={"device": orm.relation(Device),
                                     "binding": orm.relation(Binding)})
switchport_m = orm.mapper(SwitchPort, inherits=interface_m, 
polymorphic_identity=1)
ciscoswitchport_m = orm.mapper(CiscoSwitchPort, inherits=switchport_m, 
polymorphic_identity=2)
juniperswitchport_m = orm.mapper(JuniperSwitchPort, inherits=switchport_m, 
polymorphic_identity=3)
routerport_m = orm.mapper(RouterPort, inherits=interface_m, 
polymorphic_identity=4)
ciscorouterport_m = orm.mapper(CiscoRouterPort, inherits=routerport_m, 
polymorphic_identity=5)
juniperrouterport_m = orm.mapper(JuniperRouterPort, inherits=routerport_m, 
polymorphic_identity=6)
-----


Next, a binding ties together groups of router and switch ports:

-----
binding_m = orm.mapper(Binding, binding_t,
                       properties={'routerports': orm.relation(RouterPort),
                                   'switchports': orm.relation(SwitchPort)})
-----

But, when I access these members, the collections aren't restricted to
the appropriate subclasses RouterPort/SwitchPort.  They include all
interface types:

>>> print [type(x) for x in b1.routerports]
[<class '__main__.CiscoRouterPort'>, <class '__main__.CiscoSwitchPort'>]

Here's the generated SQL:

2010-08-11 10:29:42,560 INFO sqlalchemy.engine.base.Engine.0x...60ec BEGIN
2010-08-11 10:29:42,561 INFO sqlalchemy.engine.base.Engine.0x...60ec SELECT 
binding.id AS binding_id 
FROM binding 
WHERE binding.id = ?
2010-08-11 10:29:42,561 INFO sqlalchemy.engine.base.Engine.0x...60ec [1]
2010-08-11 10:29:42,561 INFO sqlalchemy.engine.base.Engine.0x...60ec SELECT 
interface.id AS interface_id, interface.deviceid AS interface_deviceid, 
interface.bindingid AS interface_bindingid 
FROM interface 
WHERE ? = interface.bindingid
2010-08-11 10:29:42,561 INFO sqlalchemy.engine.base.Engine.0x...60ec [1]

Is this a limitation of being polymorphic_on a join instead of mapping
the join?

Thanks,
Ross


from sqlalchemy import *
import sqlalchemy.orm as orm

class Device(object):
    pass
class Switch(Device):
    pass
class CiscoSwitch(Switch):
    pass
class JuniperSwitch(Switch):
    pass
class Router(Device):
    pass
class CiscoRouter(Router):
    pass
class JuniperRouter(Router):
    pass

class InterfaceBase(object):
    pass
class SwitchPort(InterfaceBase):
    pass
class CiscoSwitchPort(SwitchPort):
    pass
class JuniperSwitchPort(SwitchPort):
    pass
class RouterPort(InterfaceBase):
    pass
class CiscoRouterPort(RouterPort):
    pass
class JuniperRouterPort(RouterPort):
    pass

class Binding(object):
    pass

engine = create_engine('sqlite:///:memory:')
metadata = MetaData()
device_t = Table('device', metadata, 
                 Column('id', Integer, primary_key=True),
                 Column('model', Integer))
interface_t = Table('interface', metadata,
                    Column('id', Integer, primary_key=True),
                    Column('deviceid', Integer,
ForeignKey('device.id')),
                    Column('bindingid', Integer,
ForeignKey('binding.id')))
binding_t = Table('binding', metadata,
                  Column('id', Integer, primary_key=True))


metadata.create_all(engine)

device_m = orm.mapper(Device, device_t,
                      polymorphic_on=device_t.c.model,
                      polymorphic_identity=0)
switch_m = orm.mapper(Switch, inherits=device_m,
                      polymorphic_identity=1)
ciscoswitch_m = orm.mapper(CiscoSwitch, inherits=switch_m,
                           polymorphic_identity=2)
juniperswitch_m = orm.mapper(JuniperSwitch, inherits=switch_m,
                             polymorphic_identity=3)
router_m = orm.mapper(Router, inherits=device_m,
                      polymorphic_identity=4)
ciscorouter_m = orm.mapper(CiscoRouter, inherits=router_m,
                           polymorphic_identity=5)
juniperrouter_m = orm.mapper(JuniperRouter, inherits=router_m,
                             polymorphic_identity=6)

iftype_join = select([device_t.c.model],
from_obj=[interface_t.join(device_t)]).alias()
interface_m = orm.mapper(InterfaceBase, interface_t,
                         polymorphic_on=iftype_join.c.model,
                         polymorphic_identity=0,
                         properties={"device": orm.relation(Device),
                                     "binding":
orm.relation(Binding)})
switchport_m = orm.mapper(SwitchPort, inherits=interface_m,
                          polymorphic_identity=1)
ciscoswitchport_m = orm.mapper(CiscoSwitchPort, inherits=switchport_m,
                               polymorphic_identity=2)
juniperswitchport_m = orm.mapper(JuniperSwitchPort,
inherits=switchport_m,
                                 polymorphic_identity=3)
routerport_m = orm.mapper(RouterPort, inherits=interface_m,
                          polymorphic_identity=4)
ciscorouterport_m = orm.mapper(CiscoRouterPort, inherits=routerport_m,
                               polymorphic_identity=5)
juniperrouterport_m = orm.mapper(JuniperRouterPort,
inherits=routerport_m,
                                 polymorphic_identity=6)

binding_m = orm.mapper(Binding, binding_t,
                       properties={'routerports':
orm.relation(RouterPort),
                                   'switchports':
orm.relation(SwitchPort)})

Session = orm.sessionmaker(bind=engine)
session = Session()

b1 = Binding()
b2 = Binding()

r1 = CiscoRouter()
rp1 = CiscoRouterPort()
rp1.device = r1
rp1.binding = b1

r2 = JuniperRouter()
rp2 = JuniperRouterPort()
rp2.device = r2
rp2.binding = b2

s1 = CiscoSwitch()
sp1 = CiscoSwitchPort()
sp1.device = s1
sp1.binding = b1

s2 = JuniperSwitch()
sp2 = JuniperSwitchPort()
sp2.device = s2
sp2.binding = b2

session.add_all([r1, rp1, r2, rp2, s1, sp1, s2, sp2, b1, b2])
session.flush()
session.commit()


engine.echo = True
print [type(x) for x in b1.routerports]
print [type(x) for x in b1.switchports]
print [type(x) for x in b2.routerports]
print [type(x) for x in b2.switchports]


-- 
Ross Vandegrift
r...@kallisti.us

"If the fight gets hot, the songs get hotter.  If the going gets tough,
the songs get tougher."
        --Woody Guthrie

Attachment: signature.asc
Description: Digital signature

Reply via email to