Hi, I'm struggling trying to merge two patterns which separately are no- brainers in sqa: joined tabled inheritance and (an arbitrary number of) graph relationships, here represented as connections and dependencies. I've run into quite a few different errors from the following code using version 0.5.3:
(most recently) sqlalchemy.orm.exc.UnmappedColumnError: Can't execute sync rule for source column 'dep_dependency.parent_id'; mapper 'Mapper|Component| dep_group_components' does not map this column. Try using an explicit `foreign_keys` collection which does not include destination column 'dep_group_components.group_id' (or use a viewonly=True relation). (and when the foreign_keys is blank) sqlalchemy.exc.ArgumentError: Could not determine relation direction for secondaryjoin condition 'dep_groups INNER JOIN dep_group_components ON dep_groups.group_id = dep_group_components.group_id INNER JOIN dep_dependency ON dep_group_components.group_id = dep_dependency.child_id', on relation Component.dependents. Specify the foreign_keys argument to indicate which columns on the relation are foreign. Any thoughts on what to do here? I'm fully stumped at this point. I should note that I've tried using a polymorphic_union (for locating the value of the polymorphic_on and for primary and secondaryjoin in relations). That only yields sql code with multiple definitions of 'type'. Many thanks, -thomas --- from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.orm import sessionmaker, scoped_session, create_session from sqlalchemy import Table, Column, Integer, String, Date, DateTime, Time, \ MetaData, ForeignKey, Boolean, ForeignKeyConstraint from sqlalchemy.schema import UniqueConstraint, CheckConstraint from sqlalchemy.orm import backref, mapper, relation, reconstructor, polymorphic_union from sqlalchemy import and_, or_ ENGINE_URL = 'mysql://' TYPE_GROUP = 'group' TYPE_COMPONENT = 'comp' Base = declarative_base() metadata = MetaData() Base.metadata = metadata engine = create_engine( ENGINE_URL, echo=False) class Group(object): def __repr__(self): return "<Group( %s )>" % self.name def __init__(self, name=None, expired=False): """ Note that self.type is automatically populated when polymorphic_on is configued in Group's mapper. """ self.name = name self.expired = expired class DependencyHolderGroup(Group): def __init__(self, name=None, version=None, expired=False): self.name = name self.version = version self.expired = expired class Component(DependencyHolderGroup): pass dep_groups = Table('dep_groups', metadata, Column('group_id', Integer, primary_key=True), Column('type', String(8)), Column('name', String(100), unique=True), Column('expired', Boolean), UniqueConstraint('name', 'type', name='name_type_x'), mysql_engine = 'InnoDb' ) connections_table = Table('dep_connections', metadata, Column('parent_id', Integer, ForeignKey('dep_groups.group_id')), Column('child_id', Integer, ForeignKey('dep_groups.group_id')), mysql_engine='InnoDb' ) dependencies_table = Table('dep_dependency', metadata, Column('parent_id', Integer, ForeignKey('dep_groups.group_id')), Column('child_id', Integer, ForeignKey('dep_groups.group_id')), mysql_engine='InnoDb' ) dep_group_components = Table('dep_group_components', metadata, Column('group_id', Integer, ForeignKey('dep_groups.group_id'), primary_key=True), Column('group_name', String(100)), Column('version', String(50)), # ForeignKeyConstraint(['group_name'], ['dep_groups.name']), # UniqueConstraint('group_name', 'version', name='name_version_x'), # CheckConstraint('type == %s' % TYPE_COMPONENT, name='type_comp_x'), CheckConstraint('dependents.type != "set"', name='no_set_child_x'), mysql_engine = 'InnoDb' ) groups_mapper = mapper(Group, dep_groups, order_by=['name'], polymorphic_on=dep_groups.c.type, polymorphic_identity=TYPE_GROUP, properties={ 'children':relation(Group, lazy=False, primaryjoin=dep_groups.c.group_id==connections_table.c.parent_id, secondaryjoin=dep_groups.c.group_id==connections_table.c.child_id, secondary=connections_table, backref='parents', cascade='all'), }) primary = dep_groups.join(dep_group_components, dep_groups.c.group_id==dep_group_components.c.group_id).join (dependencies_table, dep_group_components.c.group_id==dependencies_table.c.parent_id) secondary = dep_groups.join(dep_group_components, dep_groups.c.group_id==dep_group_components.c.group_id).join (dependencies_table, dep_group_components.c.group_id==dependencies_table.c.child_id) components_mapper = mapper(Component, dep_group_components, inherits=Group, order_by=['name','version'], polymorphic_identity=TYPE_COMPONENT, properties={ 'dependents': relation(Group, foreign_keys=[ dep_group_components.c.group_id, dependencies_table.c.parent_id, dependencies_table.c.child_id ], primaryjoin=primary.onclause, secondaryjoin=secondary.onclause, secondary=dependencies_table) # backref='dep_parents', cascade='all'), }) if __name__ == '__main__': metadata.bind = engine metadata.create_all() s = scoped_session(sessionmaker(bind=engine, autoflush=True))() #s = create_session(bind=engine, autoflush=True, autocommit=True) # for sqlite g1 = Group(name='g1') g2 = Group(name='g2') g1.children.append(g2) s.add(g1) s.add(g2) c = Component(name='c1', version='1') c.dependents.append(g1) s.add(c) s.commit() --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@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 -~----------~----~----~----~------~----~------~--~---