On Aug 11, 2010, at 10:51 AM, Ross Vandegrift wrote:
> 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)
that polymorphic_on above is not valid. polymorpic_on needs to be a column
that's in the mapped table, in this case interface_t, or in the
with_polymorphic selectable if any. Its a SQLA bug that this condition is
silently accepted - a warning is emitted as of rf9c64cf0cbb9. We'll push
this to an exception in the next major version.
> -----
>
>
> 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
> [email protected]
>
> "If the fight gets hot, the songs get hotter. If the going gets tough,
> the songs get tougher."
> --Woody Guthrie
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.