relationship with join to primary key column results in error
if the following is defined:
parent table:
members = sqlalchemy.Table(
'members',z3c.zalchemy.metadata,
sqlalchemy.Column('userName', sqlalchemy.String,primary_key = True),
sqlalchemy.Column('firstName', sqlalchemy.Unicode),
sqlalchemy.Column('lastName', sqlalchemy.Unicode),
sqlalchemy.Column('contactEmail', sqlalchemy.Unicode),
sqlalchemy.Column('photo', sqlalchemy.Binary,
sqlalchemy.PassiveDefault("")),
redefine=True
)
parent class mapper:
sqlalchemy.mapper(Member,members,properties={
'_personalAddress':sqlalchemy.relation(AddressInfo,
uselist=False,
backref='__parent__',
cascade="all, delete-orphan",
primaryjoin=sqlalchemy.and_(
members.c.userName==addresses.c.userName,
addresses.c.addressType==1
)),})
joined table:
addresses = sqlalchemy.Table(
'addresses',z3c.zalchemy.metadata,
sqlalchemy.Column('userName', sqlalchemy.Unicode,
sqlalchemy.ForeignKey('members.userName'),
primary_key=True,
nullable=False),
sqlalchemy.Column('addressType', sqlalchemy.Integer,
nullable=False,
primary_key=True),
sqlalchemy.Column('organisation', sqlalchemy.Unicode),
sqlalchemy.Column('address', sqlalchemy.Unicode),
sqlalchemy.Column('zipCode', sqlalchemy.Unicode),
sqlalchemy.Column('city', sqlalchemy.Unicode),
sqlalchemy.Column('state', sqlalchemy.Unicode, default=u'AT'),
sqlalchemy.Column('email', sqlalchemy.Unicode),
sqlalchemy.Column('phone', sqlalchemy.Unicode),
sqlalchemy.Column('homePage', sqlalchemy.Unicode),
sqlalchemy.Column('isContact', sqlalchemy.Boolean),
)
it results in the following error
Traceback (most recent call last):
File "/Users/bd/zopes/fhvao/lib/python/fhvao/tests.py", line 5, in ?
from fhvao.member import members,Member
File "/Users/bd/zopes/fhvao/lib/python/fhvao/member.py", line 185, in ?
addresses.c.addressType==1
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/__init__.py", line 50, in mapper
return Mapper(class_, table, *args, **params)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/mapper.py", line 253, in __init__
prop.init(key, self)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/mapper.py", line 866, in init
self.do_init(key, parent)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/properties.py", line 215, in do_init
self._find_dependent()
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/properties.py", line 291, in _find_dependent
self.primaryjoin.accept_visitor(visitor)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/sql.py", line 858, in accept_visitor
c.accept_visitor(visitor)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/sql.py", line 947, in accept_visitor
visitor.visit_binary(self)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/properties.py", line 752, in visit_binary
self.func(binary)
File "/Users/bd/zopes/fhvao/lib/python/sqlalchemy/orm/properties.py", line 282, in foo
raise exceptions.ArgumentError("bidirectional dependency not supported...specify foreignkey")
ArgumentError: bidirectional dependency not supported...specify foreignkey
this only happens if the column in the join is a primary_key in the child table, if you change the code above to:
sqlalchemy.Column('addressType', sqlalchemy.Integer,
nullable=False,
primary_key=False),
it works.
a forther question:
shouldn't the addressType be set to 1 automatically if i assign an address object to obj._personalAddress which has no addressType specified?
Regards, Bernd
Comments (4)
-
Account Deleted -
repo owner - changed status to duplicate
this is a duplicate of
#151. if you look at the test case there, you will see the workaround for the problem which is to specify the "foreignkey" property to the relation.the error message itself here should be clarified to say something along the lines of "Could not determine the parent/child relationship between tables "a" and "b", based on join condition "c". please specify the "foreignkey" keyword parameter to the relation() function indicating a column on the "many" side of the relationship".
to answer the second question: maybe. the "primaryjoin" is just a SQL expression which the mapper doesn't look inside of very deeply. the sync.py module could be enhanced to detect the condition of "column = <scalar value>", but that might be tricky; what if it were:
table.c.column == func.foo(3,5)
or
table.c.column == table2.select(table2.c.col7==5)
? then its not just a scalar value, its a function or query that has to be run on the database each time. so that gets more complicated, and also it might not be the most efficient way to do this; the "primaryjoin" condition needs to be able to select values, but once loaded, the application itself might more efficiently set up that related value. by having this functionality just not be there at all, it forces the developer to implement the attributes value his or herself, which eliminates the possibility of unnecessary overhead occuring without the developer's knowledge.
but since a literal value doesnt incur any overhead, i suppose the feature would have to search for exactly:
column == literal value
-
repo owner - changed status to open
- removed status
ok, i implemented the better error message, and actually this case is slightly different from the one in
#151and has been repaired in changeset:1456 -
repo owner - changed status to resolved
- Log in to comment
ups, forgot the version 0.2