I am having some trouble getting the code below to work... running the code below will give this error message when trying to create a Session object (last line):
sqlalchemy.exc.ArgumentError: Could not determine relationship direction for primaryjoin condition 'ChildArea.session_id==ParentArea.session_id AND ChildArea.parent_area_id==ParentArea.id', on relationship ChildArea.parent_area. Ensure that the referencing Column objects have a ForeignKey present, or are otherwise part of a ForeignKeyConstraint on their parent Table, or specify the foreign_keys parameter to this relationship. In other words, no error messages after the create_all statement. Bit of background, the database is an existing database, hence the explicit naming of database columns used every now and then. I am using SQLA 0.7.3 on a Oracle XE 11.2 database (using the most recent version of cx_Oracle). Data is divided in sessions, each session (date) contains a topology which consists of parent areas which themselves consist of child areas. The set of parent areas differs over the sessions. The primary key for a parent area consists of both the session id and the parent area id column. Hence the foreignkey relation from child to parent id consists of these two columns. This is what is giving me issues at the moment, and a few questions. First of course is how to make the code below work, but I am also wondering what the best practice is with regards to using column names and/or object and property names when defining foreign keys and relationships. As the two namings are not in line for my example. The ForeignKeyConstraint requires column names, but the primaryjoin seems to be able to handle various options. Have been skimming through the documentation to find a declarative example with a compound foreignkey but have not been able to find one. What would be a best practice for the primaryjoin? Of course any other comments/recommendations with regards to the code below is appreciated :) Thijs from sqlalchemy import Column from sqlalchemy import ForeignKey from sqlalchemy import ForeignKeyConstraint from sqlalchemy import and_ from sqlalchemy import Integer from sqlalchemy import Date from sqlalchemy import String from sqlalchemy.orm import relationship from sqlalchemy.engine import create_engine from sqlalchemy.ext.declarative import declarative_base from datetime import date # Initiate connection to Oracle database engine=create_engine('oracle://scott:tiger@localhost:1521/XE', echo=True) Base = declarative_base(engine) class Session(Base): __tablename__ = 'sessions' id = Column(Integer, primary_key=True) date = Column(Date, nullable=False) def __init__(self, id, date): self.id = id self.date = date def __repr__(self): return '<Session(date="{1:%Y-%m-%d}")>'.format(self.id, self.date) class ParentArea(Base): __tablename__ = 'session_parentareas' session_id = Column(Integer, ForeignKey('sessions.id'), primary_key=True) session = relationship( "Session", primaryjoin="ParentArea.session_id==Session.id", backref="parent_areas" ) id = Column(Integer, primary_key=True) name = Column(String(50)) def __init__(self, session, id, name): self.session = session self.id = id self.name = name def __repr__(self): return '<ParentArea(date="{0:%Y-%m-%d}", name="{1}")>'.format( self.session.delivery_date, self.name ) class ChildArea(Base): __tablename__ = 'session_childareas' __table_args__ = ( ForeignKeyConstraint( ['session_id', 'parentarea_id'], ['session_parentareas.session_id', 'session_parentareas.id'] ), ) session_id = Column(Integer, ForeignKey('sessions.id'), primary_key=True) session = relationship( "Session", primaryjoin="ChildArea.session_id==Session.id" ) id = Column(Integer, primary_key=True) parent_area_id = Column('parentarea_id', Integer, nullable=False) parent_area = relationship( "ParentArea", primaryjoin=and_( "ChildArea.session_id==ParentArea.session_id", "ChildArea.parent_area_id==ParentArea.id" ), backref="child_areas" ) name = Column(String(50)) def __init__(self, session, id, parent_area, name): self.session = session self.id = id self.parent_area = parent_area self.name = name def __repr__(self): return '<ChildArea(date="{0:%Y-%m-%d}", name="{1}")>'.format( self.session.delivery_date, self.name ) Base.metadata.drop_all() Base.metadata.create_all() # Add a session c = Session(1, date.today()) For completeness sake the full traceback: Traceback (most recent call last): File "example.py", line 107, in <module> c = Session(1, date.today()) File "<string>", line 2, in __init__ File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\instrumentation.py", line 309, in _new_state_if_none state = self._state_constructor(instance, self) File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\util\langhelpers.py", line 484, in __get__ obj.__dict__[self.__name__] = result = self.fget(obj) File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\instrumentation.py", line 157, in _state_constructor self.dispatch.first_init(self, self.class_) File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\event.py", line 274, in __call__ fn(*args, **kw) File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\mapper.py", line 2865, in _event_on_first_init configure_mappers() File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\mapper.py", line 2790, in configure_mappers mapper._post_configure_properties() File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\mapper.py", line 1095, in _post_configure_properties prop.init() File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\interfaces.py", line 128, in init self.do_init() File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\properties.py", line 910, in do_init self._determine_synchronize_pairs() File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\properties.py", line 1197, in _determine_synchronize_pairs True) File "C:\Python27\lib\site-packages\sqlalchemy-0.7.3-py2.7-win32.egg\sqlalchemy\orm\properties.py", line 1175, in _sync_pairs_from_join self sqlalchemy.exc.ArgumentError: Could not determine relationship direction for primaryjoin condition 'ChildArea.session_id==ParentArea.session_id AND ChildArea.parent_area_id==ParentArea.id', on relationship ChildArea.parent_area. Ensure that the referencing Column objects have a ForeignKey present, or are otherwise part of a ForeignKeyConstraint on their parent Table, or specify the foreign_keys parameter to this relationship. -- 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.