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 > r...@kallisti.us > > "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 sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.