Re: [sqlalchemy] declarative one to many relationship with composite primary key

2010-11-17 Thread Adrien Saladin
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).

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

Re: [sqlalchemy] declarative one to many relationship with composite primary key

2010-11-17 Thread Michael Bayer

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 

Re: [sqlalchemy] declarative one to many relationship with composite primary key

2010-11-17 Thread Adrien Saladin
On Wed, Nov 17, 2010 at 4:58 PM, Michael Bayer mike...@zzzcomputing.com wrote:
 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.


Thanks for the quick reply, the patch and the syntax correction of my code.

Regards,

-- 
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.



[sqlalchemy] declarative one to many relationship with composite primary key

2010-11-16 Thread Adrien
Hi list,

Sorry if this is trivial, I'm relatively new to sqlalchemy.
I'm trying to set a one to many relationship between class Foo and
class Bar (ie Foo should have a list of Bars). Foo has a composite
primary key.

#
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
id = Column(Integer, primary_key=True)
one_id = Column(Integer, nullable=False)
two_id = Column(Integer, nullable=False)

ForeignKeyConstraint([one_id, two_id], [foo.one, foo.two])
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()
#

I get the following message:

sqlalchemy.exc.ArgumentError: Could not determine join condition
between parent/child tables on relationship Bar.foo.  Specify a
'primaryjoin' expression.


I tried to change the relationship line to:
foo = relationship(Foo, backref = bars, primaryjoin=and_(one_id ==
Foo.one, two_id==Foo.two ) )

but then I get this message:

sqlalchemy.exc.ArgumentError: Could not determine relationship
direction for primaryjoin condition 'bar.one_id = foo.one AND
bar.two_id = foo.two', on relationship Bar.foo. Ensure that the
referencing Column objects have a ForeignKey present, or are otherwise
part of a ForeignKeyConstraint on their parent Table.

Thank you for your help!

-- 
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.



Re: [sqlalchemy] declarative one to many relationship with composite primary key

2010-11-16 Thread Michael Bayer
ForeignKeyConstraint needs to go into __table_args__ when using declarative.

http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#table-configuration


On Nov 16, 2010, at 6:28 PM, Adrien wrote:

 Hi list,
 
 Sorry if this is trivial, I'm relatively new to sqlalchemy.
 I'm trying to set a one to many relationship between class Foo and
 class Bar (ie Foo should have a list of Bars). Foo has a composite
 primary key.
 
 #
 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
id = Column(Integer, primary_key=True)
one_id = Column(Integer, nullable=False)
two_id = Column(Integer, nullable=False)
 
ForeignKeyConstraint([one_id, two_id], [foo.one, foo.two])
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()
 #
 
 I get the following message:
 
 sqlalchemy.exc.ArgumentError: Could not determine join condition
 between parent/child tables on relationship Bar.foo.  Specify a
 'primaryjoin' expression.
 
 
 I tried to change the relationship line to:
 foo = relationship(Foo, backref = bars, primaryjoin=and_(one_id ==
 Foo.one, two_id==Foo.two ) )
 
 but then I get this message:
 
 sqlalchemy.exc.ArgumentError: Could not determine relationship
 direction for primaryjoin condition 'bar.one_id = foo.one AND
 bar.two_id = foo.two', on relationship Bar.foo. Ensure that the
 referencing Column objects have a ForeignKey present, or are otherwise
 part of a ForeignKeyConstraint on their parent Table.
 
 Thank you for your help!
 
 -- 
 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.