On 11/19/2015 02:38 PM, Bernhard Radermacher wrote: > I am stumped... > > I have the following scenario: Two classes (Project and Package) inherit > from class Container. Project is at the top-level of the hierarchy, and > can contain Packages, Package must be contained in a Project or a > different Package (i.e. a Container) and can contain other packages. The > picture shows the tables and relationships for implementing this as > Joined Table Inheritance. > > <https://lh3.googleusercontent.com/-Y-UfphSM1hg/Vk4hYRwMa5I/AAAAAAAAAOM/546cwcbzI84/s1600/Diagram.png> > > > The tables can be created by SQL without any issues: > > CREATE TABLE `Container` ( > `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, > `name` varchar(64) NOT NULL, > `description` text, > `containerType` varchar(8) NOT NULL > ); > > > CREATE TABLE `Package` ( > `id` int(11) NOT NULL PRIMARY KEY, > `container_id` int(11) NOT NULL, > FOREIGN KEY (`id`) REFERENCES `Container` (`id`), > FOREIGN KEY (`container_id`) REFERENCES `Container` (`id`) > ); > > > CREATE TABLE IF NOT EXISTS `Project` ( > `id` int(11) NOT NULL PRIMARY KEY, > FOREIGN KEY (`id`) REFERENCES `Container` (`id`) > ); > > > I am using the following definitions in Python: > > from sqlalchemy import ( > Column, > ForeignKey, > Integer, > Unicode, > UnicodeText, > ) > > from sqlalchemy.ext.declarative import ( > declarative_base, > ) > > from sqlalchemy.orm import ( > relationship, > scoped_session, > sessionmaker, > ) > > from zope.sqlalchemy import ZopeTransactionExtension > > DBSession = > scoped_session(sessionmaker(extension=ZopeTransactionExtension())) > > Base = declarative_base() > > class Container(Base): > ''' > The are two different kind of containers, projects and packages. > > Projects are the toplevel container, they cannot be at any lower > level (they can contain, but not be contained). > > Packages can be contained in a project, or in a different package. > > The Container itself is abstract. > ''' > id = Column(Integer, primary_key=True, nullable=False) > name = Column(Unicode(64), nullable=False) > description = Column(UnicodeText, nullable=True) > containerType = Column(Unicode(8), nullable=False) > > __mapper_args__ = dict( > polymorphic_on='containerType', > ) > > class Project(Container): > ''' > Projects are the toplevel container, they cannot be at any lower > level (they can contain, but not be contained. > ''' > id = Column(Integer, ForeignKey('Container.id'), primary_key=True, > nullable=False) > __mapper_args__ = dict( > polymorphic_identity='Project', > ) > > > class Package(Container): > ''' > Packages must be contained and can contain. > ''' > id = Column(Integer, ForeignKey('Container.id'), primary_key=True, > nullable=False) > container_id = Column(Integer, ForeignKey('Container.id'), > nullable=False) > ident = relationship('Container', foreign_keys=[id]) > container = relationship('Container', foreign_keys=[container_id], > backref='packages') > > __mapper_args__ = dict( > polymorphic_identity='Package', > ) > > I also tried to replace the two respective lines in Package with: > > ident = relationship('Container', > primaryjoin="Package.id==Container.id") > container = relationship('Container', > primaryjoin="Package.container_id==Container.id", backref='packages') > > Both result in the same error: > > sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between > 'Container' and 'Package'; tables have more than one foreign key > constraint relationship between them. Please specify the 'onclause' of > this join explicitly. > > Where and how can I specify the missing 'onclause'?
this refers to the inheritance condition of Package subclassing Container. You need to use the inherit_condition argument: http://docs.sqlalchemy.org/en/rel_1_0/orm/mapping_api.html?highlight=inherit_condition#sqlalchemy.orm.mapper.params.inherit_condition the docs are slight here but the format is like that of the relationship, just not a string: class Package(Container): # ... id = Column(ForeignKey('container.id')) # ... __mapper_args__ = {'polymorphic_identity': 'Package', 'inherit_condition': Container.id == id} Note the use of "id" as a local variable within the "class" block. > > -- > You received this message because you are subscribed to the Google > Groups "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send > an email to sqlalchemy+unsubscr...@googlegroups.com > <mailto:sqlalchemy+unsubscr...@googlegroups.com>. > To post to this group, send email to sqlalchemy@googlegroups.com > <mailto:sqlalchemy@googlegroups.com>. > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.