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
signature.asc
Description: Digital signature