the fix? was to add a check for self referential foreign keys in non-
self-referential relations, and do not add those as part of the
relation's foreign key collection,
is this anywhere near the correct thing to do?
# ignore self referential keys
if not (self.secondaryjoin or
self._is_self_referential() or binary.left.table !=
binary.right.table):
return
def _determine_fks(self):
if len(self._legacy_foreignkey) and not
self._is_self_referential():
self.foreign_keys = self._legacy_foreignkey
def col_is_part_of_mappings(col):
if self.secondary is None:
return
self.parent.mapped_table.corresponding_column(col, raiseerr=False) is
not None or \
self.target.corresponding_column(col,
raiseerr=False) is not None
else:
return
self.parent.mapped_table.corresponding_column(col, raiseerr=False) is
not None or \
self.target.corresponding_column(col,
raiseerr=False) is not None or \
self.secondary.corresponding_column(col,
raiseerr=False) is not None
if len(self.foreign_keys):
self._opposite_side = util.Set()
def visit_binary(binary):
if binary.operator != '=' or not
isinstance(binary.left, schema.Column) or not isinstance(binary.right,
schema.Column):
return
if binary.left in self.foreign_keys:
self._opposite_side.add(binary.right)
if binary.right in self.foreign_keys:
self._opposite_side.add(binary.left)
mapperutil.BinaryVisitor(visit_binary).traverse(self.primaryjoin)
if self.secondaryjoin is not None:
mapperutil.BinaryVisitor(visit_binary).traverse(self.secondaryjoin)
else:
self.foreign_keys = util.Set()
self._opposite_side = util.Set()
def visit_binary(binary):
if binary.operator != '=' or not
isinstance(binary.left, schema.Column) or not isinstance(binary.right,
schema.Column):
return
# this check is for when the user put the "view_only"
flag on and has tables that have nothing
# to do with the relationship's parent/child mappings
in the join conditions. we dont want cols
# or clauses related to those external tables dealt
with. see orm.relationships.ViewOnlyTest
if not col_is_part_of_mappings(binary.left) or not
col_is_part_of_mappings(binary.right):
return
# ignore self referential keys
if not (self.secondaryjoin or
self._is_self_referential() or binary.left.table !=
binary.right.table):
return
for f in binary.left.foreign_keys:
if f.references(binary.right.table):
self.foreign_keys.add(binary.left)
self._opposite_side.add(binary.right)
for f in binary.right.foreign_keys:
if f.references(binary.left.table):
self.foreign_keys.add(binary.right)
self._opposite_side.add(binary.left)
mapperutil.BinaryVisitor(visit_binary).traverse(self.primaryjoin)
if len(self.foreign_keys) == 0:
raise exceptions.ArgumentError(
"Can't locate any foreign key columns in primary
join "
"condition '%s' for relationship '%s'. Specify "
"'foreign_keys' argument to indicate which columns
in "
"the join condition are foreign." %
(str(self.primaryjoin), str(self)))
if self.secondaryjoin is not None:
mapperutil.BinaryVisitor(visit_binary).traverse(self.secondaryjoin)
On Nov 6, 9:11 pm, Esceo <[EMAIL PROTECTED]> wrote:
> Just wondering if this is a bug in _determine_fks
>
> i.e. 'child.id' probably should not be part of the foreign key
> pointing to parent
>
> On Nov 6, 7:42 pm, Esceo <[EMAIL PROTECTED]> wrote:
>
>
>
> > Hi, all
>
> > the followings are the code snippet
>
> > from sqlalchemy import *
> > meta = MetaData('sqlite://')
>
> > parent = Table('parent', meta,
> > Column('id', Integer, primary_key=True),
> > Column('name', Integer)
> > )
>
> > child = Table('child', meta,
> > Column('id', Integer, primary_key=True),
> > Column('current_id', Integer),
> > Column('parent_id', Integer),
> > ForeignKeyConstraint(['parent_id'],['parent.id'],
> > ondelete="CASCADE"),
> > ForeignKeyConstraint(['current_id'],['child.id']), )
>
> > class Parent(object):
> > pass
>
> > class Child(object):
> > pass
>
> > mapper(Parent, parent);
>
> > mapper(Child, child,
> > properties = { 'parent' : relation(Parent,
> > primaryjoin =
> > (child.c.parent_id == parent.c.id) &
> > (child.c.current_id ==
> > child.c.id),
> > backref = "child"),
> > 'current' : relation(Child,
> > primaryjoin = child.c.current_id ==
> > child.c.id)
>
> > })
>
> > meta.create_all()
>
> > s = create_session()
> > c = Child()
> > c.parent = Parent()
> > s.save(c)
> > s.flush()
> > s.clear()
>
> > running that resulted in
>
> > Traceback (most recent call last):
> > File "C:\powerforce\test_fk_relation.py", line 39, in <module>
> > s.flush()
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\session.py", line 320, in flush
> > self.uow.flush(self, objects)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 210, in flush
> > flush_context.execute()
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 400, in execute
> > UOWExecutor().execute(self, head)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1018, in execute
> > self.execute_save_steps(trans, task)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1035, in
> > execute_save_steps
> > self.execute_dependencies(trans, task, False)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1048, in
> > execute_dependencies
> > self.execute_dependency(trans, dep, False)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1029, in
> > execute_dependency
> > dep.execute(trans, isdelete)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\unitofwork.py", line 984, in execute
> > self.processor.process_dependencies(self.targettask, [elem.obj for
> > elem in self.targettask.polymorphic_tosave_elements if elem.obj is not
> > None], trans, delete=False)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\dependency.py", line 275, in
> > process_dependencies
> > self._synchronize(obj, child, None, False, uowcommit)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\dependency.py", line 310, in _synchronize
> > self.syncrules.execute(source, dest, obj, child, clearkeys)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\sync.py", line 92, in execute
> > rule.execute(source, dest, obj, child, clearkeys)
> > File "C:\Python25\lib\site-packages\sqlalchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\sync.py", line 135, in execute
> > value = self.source_mapper.get_attr_by_column(source,
> > self.source_column)
> > File "C:\Python25\lib\site-packages\SQLAlchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\mapper.py", line 1017, in get_attr_by_column
> > prop = self._getpropbycolumn(column, raiseerror)
> > File "C:\Python25\lib\site-packages\SQLAlchemy-0.3.11dev_r3181-
> > py2.5.egg\sqlalchemy\orm\mapper.py", line 1007, in _getpropbycolumn
> > raise exceptions.InvalidRequestError("Column '%s.%s' is not
> > available, due to conflicting property '%s':%s" % (column.table.name,
> > column.name, column.key, repr(prop)))
> > sqlalchemy.exceptions.InvalidRequestError: Column 'child.id' is not
> > available, d
> > ue to conflicting property
> > 'id':<sqlalchemy.orm.properties.ColumnProperty object at 0x016FB730>
>
> > If I had renamed the id column on child to '_id', I ended up with a
> > different error no child.id column configured on the maper Parent|
> > parent|
>
> > any clues?
>
> > Thanks in advance
>
> > Lei- Hide quoted text -
>
> - Show quoted text -
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---