On Nov 17, 2010, at 9:07 AM, Adrien Saladin wrote: > On Wed, Nov 17, 2010 at 1:16 AM, Michael Bayer <mike...@zzzcomputing.com> > wrote: >> ForeignKeyConstraint needs to go into __table_args__ when using declarative. >> >> http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#table-configuration > > Thanks for the note. I have updated my test script to use > __table_args__ but the error remains the same (see script and ouput > below).
OK its actually a huge SQLA bug that an error isn't raised for that, which is surprising to me, so I created and resolved #1972 in r67d8f4e2fcb9. __table_args__ is expected to be a tuple or dict, so now an error is raised if it's not. (x) isn't a tuple. here's the correct form: class Bar(Base): __tablename__ = "bar" __table_args__ = ( ForeignKeyConstraint(['one_id', 'two_id'], ['foo.one', 'foo.two']),{} ) id = Column(Integer, primary_key=True) one_id = Column(Integer, nullable=False) two_id = Column(Integer, nullable=False) foo = relationship("Foo", backref = "bars") > > I then tried with the hybrid approach > (http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#using-a-hybrid-approach-with-table) > which works well. > Am I again doing something wrong with declarative ? > > Thanks, > > > ################################# > from sqlalchemy import * > from sqlalchemy.orm import * > from sqlalchemy.ext.declarative import declarative_base > > > Base = declarative_base() > > class Foo(Base): > __tablename__ = "foo" > one = Column(Integer, primary_key=True) > two = Column(Integer, primary_key=True) > > class Bar(Base): > __tablename__ = "bar" > __table_args__ = ( ForeignKeyConstraint(['one_id', 'two_id'], > ['foo.one', 'foo.two']) ) > id = Column(Integer, primary_key=True) > one_id = Column(Integer, nullable=False) > two_id = Column(Integer, nullable=False) > > foo = relationship("Foo", backref = "bars") > > > > metadata = Base.metadata > > engine = create_engine('sqlite:///:memory:', echo=True) > metadata.create_all(engine) > > from sqlalchemy.orm import sessionmaker > > # create a configured "Session" class > Session = sessionmaker(bind=engine) > > # create a Session > session = Session() > > foo = Foo() > foo.one = 1 > foo.two = 2 > session.add(foo) > session.commit() > > ############################# > > > > 2010-11-17 14:56:01,309 INFO sqlalchemy.engine.base.Engine.0x...9690 > PRAGMA table_info("foo") > 2010-11-17 14:56:01,309 INFO sqlalchemy.engine.base.Engine.0x...9690 () > 2010-11-17 14:56:01,310 INFO sqlalchemy.engine.base.Engine.0x...9690 > PRAGMA table_info("bar") > 2010-11-17 14:56:01,310 INFO sqlalchemy.engine.base.Engine.0x...9690 () > 2010-11-17 14:56:01,310 INFO sqlalchemy.engine.base.Engine.0x...9690 > CREATE TABLE foo ( > one INTEGER NOT NULL, > two INTEGER NOT NULL, > PRIMARY KEY (one, two) > ) > > > 2010-11-17 14:56:01,310 INFO sqlalchemy.engine.base.Engine.0x...9690 () > 2010-11-17 14:56:01,310 INFO sqlalchemy.engine.base.Engine.0x...9690 COMMIT > 2010-11-17 14:56:01,311 INFO sqlalchemy.engine.base.Engine.0x...9690 > CREATE TABLE bar ( > id INTEGER NOT NULL, > one_id INTEGER NOT NULL, > two_id INTEGER NOT NULL, > PRIMARY KEY (id) > ) > > > 2010-11-17 14:56:01,311 INFO sqlalchemy.engine.base.Engine.0x...9690 () > 2010-11-17 14:56:01,311 INFO sqlalchemy.engine.base.Engine.0x...9690 COMMIT > Traceback (most recent call last): > File "compositePrimaryKey_decl.py", line 39, in <module> > foo = Foo() > File "<string>", line 4, in __init__ > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/state.py", > line 93, in initialize_instance > fn(self, instance, args, kwargs) > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/mapper.py", > line 2357, in _event_on_init > instrumenting_mapper.compile() > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/mapper.py", > line 805, in compile > mapper._post_configure_properties() > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/mapper.py", > line 834, in _post_configure_properties > prop.init() > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/interfaces.py", > line 493, in init > self.do_init() > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/properties.py", > line 840, in do_init > self._determine_joins() > File > "/home/virtualenvs/sqlalchemy/lib/python2.6/site-packages/sqlalchemy/orm/properties.py", > line 969, in _determine_joins > % self) > sqlalchemy.exc.ArgumentError: Could not determine join condition > between parent/child tables on relationship Bar.foo. Specify a > 'primaryjoin' expression. If this is a many-to-many relationship, > 'secondaryjoin' is needed as well. > > > The script below works with the hybrid declarative approach: > > ################################# > from sqlalchemy import * > from sqlalchemy.orm import * > from sqlalchemy.ext.declarative import declarative_base > > > Base = declarative_base() > > class Foo(Base): > __tablename__ = "foo" > one = Column(Integer, primary_key=True) > two = Column(Integer, primary_key=True) > > > > bartable = Table("bar", Base.metadata, > Column("id", Integer, primary_key=True), > Column("one_id", Integer, nullable=False), > Column("two_id", Integer, nullable=False), > ForeignKeyConstraint(['one_id', 'two_id'], ['foo.one', 'foo.two']), > ) > > > > > class Bar(Base): > __table__ = bartable > foo = relationship("Foo", backref = "bars") > > > metadata = Base.metadata > > engine = create_engine('sqlite:///:memory:', echo=True) > metadata.create_all(engine) > > from sqlalchemy.orm import sessionmaker > > # create a configured "Session" class > Session = sessionmaker(bind=engine) > > # create a Session > session = Session() > > foo = Foo() > foo.one = 1 > foo.two = 2 > session.add(foo) > session.commit() > > > bar = Bar() > bar.foo = foo > session.add(bar) > > > session.commit() > > > ############################# > > -- > 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. > -- 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.