"""
+class NoForeignKeysError(ArgumentError):
+ """Raised when no foreign keys can be located between two selectables
+ during a join."""
+
+class AmbiguousForeignKeysError(ArgumentError):
+ """Raised when more than one foreign key matching can be located
+ between two selectables during a join."""
class CircularDependencyError(SQLAlchemyError):
"""Raised by topological sorts when a circular dependency is detected.
self._annotate_fks()
self._annotate_remote()
self._annotate_local()
- self._determine_direction()
self._setup_pairs()
self._check_foreign_cols(self.primaryjoin, True)
if self.secondaryjoin is not None:
self._check_foreign_cols(self.secondaryjoin, False)
+ self._determine_direction()
self._check_remote_side()
self._log_joins()
join_condition(
self.child_selectable,
self.secondary,
- a_subset=self.child_local_selectable)
+ a_subset=self.child_local_selectable,
+ consider_as_foreign_keys=\
+ self.consider_as_foreign_keys or None
+ )
if self.primaryjoin is None:
self.primaryjoin = \
join_condition(
self.parent_selectable,
self.secondary,
- a_subset=self.parent_local_selectable)
+ a_subset=self.parent_local_selectable,
+ consider_as_foreign_keys=\
+ self.consider_as_foreign_keys or None
+ )
else:
if self.primaryjoin is None:
self.primaryjoin = \
join_condition(
self.parent_selectable,
self.child_selectable,
- a_subset=self.parent_local_selectable)
- except sa_exc.ArgumentError, e:
- raise sa_exc.ArgumentError("Could not determine join "
- "condition between parent/child tables on "
- "relationship %s. Specify a 'primaryjoin' "
- "expression. If 'secondary' is present, "
- "'secondaryjoin' is needed as well."
- % self.prop)
+ a_subset=self.parent_local_selectable,
+ consider_as_foreign_keys=\
+ self.consider_as_foreign_keys or None
+ )
+ except sa_exc.NoForeignKeysError, nfke:
+ if self.secondary is not None:
+ raise sa_exc.NoForeignKeysError("Could not determine join "
+ "condition between parent/child tables on "
+ "relationship %s - there are no foreign keys "
+ "linking these tables via secondary table '%s'. "
+ "Ensure that referencing columns are associated with a "\
+ "ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' "\
+ "and 'secondaryjoin' expressions."
+ % (self.prop, self.secondary))
+ else:
+ raise sa_exc.NoForeignKeysError("Could not determine join "
+ "condition between parent/child tables on "
+ "relationship %s - there are no foreign keys "
+ "linking these tables. "
+ "Ensure that referencing columns are associated with a "
+ "ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' "
+ "expression."
+ % self.prop)
+ except sa_exc.AmbiguousForeignKeysError, afke:
+ if self.secondary is not None:
+ raise sa_exc.AmbiguousForeignKeysError("Could not determine join "
+ "condition between parent/child tables on "
+ "relationship %s - there are multiple foreign key "
+ "paths linking the tables via secondary table '%s'. "
+ "Specify the 'foreign_keys' "
+ "argument, providing a list of those columns which "
+ "should be counted as containing a foreign key reference "
+ "from the secondary table to each of the parent and child tables."
+ % (self.prop, self.secondary))
+ else:
+ raise sa_exc.AmbiguousForeignKeysError("Could not determine join "
+ "condition between parent/child tables on "
+ "relationship %s - there are multiple foreign key "
+ "paths linking the tables. Specify the 'foreign_keys' "
+ "argument, providing a list of those columns which "
+ "should be counted as containing a foreign key reference "
+ "to the parent table."
+ % self.prop)
@util.memoized_property
def primaryjoin_reverse_remote(self):
err = "Could not locate any simple equality expressions "\
"involving foreign key columns for %s join condition "\
"'%s' on relationship %s." % (
- primary and 'primaryjoin' or 'secondaryjoin',
+ primary and 'primary' or 'secondary',
join_condition,
self.prop
)
else:
err = "Could not locate any relevant foreign key columns "\
"for %s join condition '%s' on relationship %s." % (
- primary and 'primaryjoin' or 'secondaryjoin',
+ primary and 'primary' or 'secondary',
join_condition,
self.prop
)
- err += "Ensure that referencing columns are associated with a "\
- "a ForeignKey or ForeignKeyConstraint, or are annotated "\
+ err += " Ensure that referencing columns are associated with a "\
+ "ForeignKey or ForeignKeyConstraint, or are annotated "\
"in the join condition with the foreign() annotation."
raise sa_exc.ArgumentError(err)
return visitors.cloned_traverse(crit, {}, {'binary':visit_binary})
+
def join_condition(a, b, ignore_nonexistent_tables=False,
- a_subset=None):
+ a_subset=None,
+ consider_as_foreign_keys=None):
"""create a join condition between two tables or selectables.
e.g.::
for fk in sorted(
b.foreign_keys,
key=lambda fk:fk.parent._creation_order):
+ if consider_as_foreign_keys is not None and \
+ fk.parent not in consider_as_foreign_keys:
+ continue
try:
col = fk.get_referent(left)
except exc.NoReferenceError, nrte:
for fk in sorted(
left.foreign_keys,
key=lambda fk:fk.parent._creation_order):
+ if consider_as_foreign_keys is not None and \
+ fk.parent not in consider_as_foreign_keys:
+ continue
try:
col = fk.get_referent(b)
except exc.NoReferenceError, nrte:
"subquery using alias()?"
else:
hint = ""
- raise exc.ArgumentError(
+ raise exc.NoForeignKeysError(
"Can't find any foreign key relationships "
"between '%s' and '%s'.%s" % (a.description, b.description, hint))
elif len(constraints) > 1:
- raise exc.ArgumentError(
+ raise exc.AmbiguousForeignKeysError(
"Can't determine join between '%s' and '%s'; "
"tables have more than one foreign key "
"constraint relationship between them. "
Column('x', Integer),
Column('y', Integer),
)
+ cls.right_multi_fk = Table('rgt_multi_fk', m,
+ Column('id', Integer, primary_key=True),
+ Column('lid1', Integer, ForeignKey('lft.id')),
+ Column('lid2', Integer, ForeignKey('lft.id')),
+ )
+
cls.selfref = Table('selfref', m,
Column('id', Integer, primary_key=True),
Column('sid', Integer, ForeignKey('selfref.id'))
Column('lid', Integer, ForeignKey('m2mlft.id'), primary_key=True),
Column('rid', Integer, ForeignKey('m2mrgt.id'), primary_key=True),
)
+ cls.m2msecondary_no_fks = Table('m2msecondary_no_fks', m,
+ Column('lid', Integer, primary_key=True),
+ Column('rid', Integer, primary_key=True),
+ )
+ cls.m2msecondary_ambig_fks = Table('m2msecondary_ambig_fks', m,
+ Column('lid1', Integer, ForeignKey('m2mlft.id'), primary_key=True),
+ Column('rid1', Integer, ForeignKey('m2mrgt.id'), primary_key=True),
+ Column('lid2', Integer, ForeignKey('m2mlft.id'), primary_key=True),
+ Column('rid2', Integer, ForeignKey('m2mrgt.id'), primary_key=True),
+ )
cls.base_w_sub_rel = Table('base_w_sub_rel', m,
Column('id', Integer, primary_key=True),
Column('sub_id', Integer, ForeignKey('rel_sub.id'))
fn
)
+ def _assert_raises_no_relevant_fks(self, fn, expr, relname,
+ primary, *arg, **kw):
+ assert_raises_message(
+ exc.ArgumentError,
+ r"Could not locate any relevant foreign key columns "
+ r"for %s join condition '%s' on relationship %s. "
+ r"Ensure that referencing columns are associated with "
+ r"a ForeignKey or ForeignKeyConstraint, or are annotated "
+ r"in the join condition with the foreign\(\) annotation."
+ % (
+ primary, expr, relname
+ ),
+ fn, *arg, **kw
+ )
+
+ def _assert_raises_no_equality(self, fn, expr, relname,
+ primary, *arg, **kw):
+ assert_raises_message(
+ sa.exc.ArgumentError,
+ "Could not locate any simple equality expressions "
+ "involving foreign key columns for %s join "
+ "condition '%s' on relationship %s. "
+ "Ensure that referencing columns are associated with a "
+ "ForeignKey or ForeignKeyConstraint, or are annotated in "
+ r"the join condition with the foreign\(\) annotation. "
+ "To allow comparison operators other than '==', "
+ "the relationship can be marked as viewonly=True." % (
+ primary, expr, relname
+ ),
+ fn, *arg, **kw
+ )
+
+ def _assert_raises_ambig_join(self, fn, relname, secondary_arg,
+ *arg, **kw):
+ if secondary_arg is not None:
+ assert_raises_message(
+ exc.AmbiguousForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are multiple foreign key paths linking the "
+ "tables via secondary table '%s'. "
+ "Specify the 'foreign_keys' argument, providing a list "
+ "of those columns which should be counted as "
+ "containing a foreign key reference from the "
+ "secondary table to each of the parent and child tables."
+ % (relname, secondary_arg),
+ fn, *arg, **kw)
+ else:
+ assert_raises_message(
+ exc.AmbiguousForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are no foreign keys linking these tables. "
+ % (relname,),
+ fn, *arg, **kw)
+
+ def _assert_raises_no_join(self, fn, relname, secondary_arg,
+ *arg, **kw):
+ if secondary_arg is not None:
+ assert_raises_message(
+ exc.NoForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are no foreign keys linking these tables "
+ "via secondary table '%s'. "
+ "Ensure that referencing columns are associated with a ForeignKey "
+ "or ForeignKeyConstraint, or specify 'primaryjoin' and "
+ "'secondaryjoin' expressions"
+ % (relname, secondary_arg),
+ fn, *arg, **kw)
+ else:
+ assert_raises_message(
+ exc.NoForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are no foreign keys linking these tables. "
+ "Ensure that referencing columns are associated with a ForeignKey "
+ "or ForeignKeyConstraint, or specify a 'primaryjoin' "
+ "expression."
+ % (relname,),
+ fn, *arg, **kw)
+
+
class ColumnCollectionsTest(_JoinFixtures, fixtures.TestBase, AssertsCompiledSQL):
def test_determine_local_remote_pairs_o2o_joined_sub_to_base(self):
joincond = self._join_fixture_o2o_joined_sub_to_base()
)
def test_err_local_remote_compound_1(self):
- assert_raises_message(
- exc.ArgumentError,
- "Can't determine relationship direction for "
- "relationship 'None' - foreign key "
- "columns are present in neither the "
- "parent nor the child's mapped tables",
- self._join_fixture_compound_expression_1_non_annotated
+ self._assert_raises_no_relevant_fks(
+ self._join_fixture_compound_expression_1_non_annotated,
+ r'lft.x \+ lft.y = rgt.x \* rgt.y',
+ "None", "primary"
)
def test_determine_remote_columns_compound_2(self):
"lft.id = rgt.lid"
)
+ def test_determine_join_ambiguous_fks_o2m(self):
+ assert_raises_message(
+ exc.AmbiguousForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship None - "
+ "there are multiple foreign key paths linking "
+ "the tables. Specify the 'foreign_keys' argument, "
+ "providing a list of those columns which "
+ "should be counted as containing a foreign "
+ "key reference to the parent table.",
+ relationships.JoinCondition,
+ self.left,
+ self.right_multi_fk,
+ self.left,
+ self.right_multi_fk,
+ )
+
+ def test_determine_join_no_fks_o2m(self):
+ self._assert_raises_no_join(
+ relationships.JoinCondition,
+ "None", None,
+ self.left,
+ self.selfref,
+ self.left,
+ self.selfref,
+ )
+
+
+ def test_determine_join_ambiguous_fks_m2m(self):
+
+ self._assert_raises_ambig_join(
+ relationships.JoinCondition,
+ "None", self.m2msecondary_ambig_fks,
+ self.m2mleft,
+ self.m2mright,
+ self.m2mleft,
+ self.m2mright,
+ secondary=self.m2msecondary_ambig_fks
+ )
+
+ def test_determine_join_no_fks_m2m(self):
+ self._assert_raises_no_join(
+ relationships.JoinCondition,
+ "None", self.m2msecondary_no_fks,
+ self.m2mleft,
+ self.m2mright,
+ self.m2mleft,
+ self.m2mright,
+ secondary=self.m2msecondary_no_fks
+ )
+
+ def _join_fixture_fks_ambig_m2m(self):
+ return relationships.JoinCondition(
+ self.m2mleft,
+ self.m2mright,
+ self.m2mleft,
+ self.m2mright,
+ secondary=self.m2msecondary_ambig_fks,
+ consider_as_foreign_keys=[
+ self.m2msecondary_ambig_fks.c.lid1,
+ self.m2msecondary_ambig_fks.c.rid1]
+ )
+
+ def test_determine_join_w_fks_ambig_m2m(self):
+ joincond = self._join_fixture_fks_ambig_m2m()
+ self.assert_compile(
+ joincond.primaryjoin,
+ "m2mlft.id = m2msecondary_ambig_fks.lid1"
+ )
+ self.assert_compile(
+ joincond.secondaryjoin,
+ "m2mrgt.id = m2msecondary_ambig_fks.rid1"
+ )
+
class AdaptedJoinTest(_JoinFixtures, fixtures.TestBase, AssertsCompiledSQL):
__dialect__ = 'default'
from test.lib.testing import eq_, startswith_, AssertsCompiledSQL, is_
from test.lib import fixtures
from test.orm import _fixtures
-
+from sqlalchemy import exc
class DependencyTwoParentTest(fixtures.MappedTest):
"""Test flush() when a mapper is dependent on multiple relationships"""
subscriber_table = Table('subscriber', metadata,
Column('id', Integer, primary_key=True,
test_needs_autoincrement=True),
- Column('dummy', String(10)) # to appease older sqlite version
)
address_table = Table('address',
"mean to set remote_side on the many-to-one side ?",
configure_mappers)
+class AmbiguousFKResolutionTest(fixtures.MappedTest):
+ @classmethod
+ def define_tables(cls, metadata):
+ Table("a", metadata,
+ Column('id', Integer, primary_key=True)
+ )
+ Table("b", metadata,
+ Column('id', Integer, primary_key=True),
+ Column('aid_1', Integer, ForeignKey('a.id')),
+ Column('aid_2', Integer, ForeignKey('a.id')),
+ )
+ Table("atob", metadata,
+ Column('aid', Integer),
+ Column('bid', Integer),
+ )
+ Table("atob_ambiguous", metadata,
+ Column('aid1', Integer, ForeignKey('a.id')),
+ Column('bid1', Integer, ForeignKey('b.id')),
+ Column('aid2', Integer, ForeignKey('a.id')),
+ Column('bid2', Integer, ForeignKey('b.id')),
+ )
+
+ @classmethod
+ def setup_classes(cls):
+ class A(cls.Basic):
+ pass
+ class B(cls.Basic):
+ pass
+
+ def test_ambiguous_fks_o2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b = self.tables.a, self.tables.b
+ mapper(A, a, properties={
+ 'bs':relationship(B)
+ })
+ mapper(B, b)
+ assert_raises_message(
+ sa.exc.AmbiguousForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship A.bs - "
+ "there are multiple foreign key paths linking "
+ "the tables. Specify the 'foreign_keys' argument, "
+ "providing a list of those columns which "
+ "should be counted as containing a foreign "
+ "key reference to the parent table.",
+ sa.orm.configure_mappers
+ )
+
+ def test_with_fks_o2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b = self.tables.a, self.tables.b
+ mapper(A, a, properties={
+ 'bs':relationship(B, foreign_keys=b.c.aid_1)
+ })
+ mapper(B, b)
+ sa.orm.configure_mappers()
+ assert A.bs.property.primaryjoin.compare(
+ a.c.id==b.c.aid_1
+ )
+ eq_(
+ A.bs.property._calculated_foreign_keys,
+ set([b.c.aid_1])
+ )
+
+ def test_with_pj_o2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b = self.tables.a, self.tables.b
+ mapper(A, a, properties={
+ 'bs':relationship(B, primaryjoin=a.c.id==b.c.aid_1)
+ })
+ mapper(B, b)
+ sa.orm.configure_mappers()
+ assert A.bs.property.primaryjoin.compare(
+ a.c.id==b.c.aid_1
+ )
+ eq_(
+ A.bs.property._calculated_foreign_keys,
+ set([b.c.aid_1])
+ )
+
+ def test_with_annotated_pj_o2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b = self.tables.a, self.tables.b
+ mapper(A, a, properties={
+ 'bs':relationship(B, primaryjoin=a.c.id==foreign(b.c.aid_1))
+ })
+ mapper(B, b)
+ sa.orm.configure_mappers()
+ assert A.bs.property.primaryjoin.compare(
+ a.c.id==b.c.aid_1
+ )
+ eq_(
+ A.bs.property._calculated_foreign_keys,
+ set([b.c.aid_1])
+ )
+
+ def test_no_fks_m2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b, a_to_b = self.tables.a, self.tables.b, self.tables.atob
+ mapper(A, a, properties={
+ 'bs':relationship(B, secondary=a_to_b)
+ })
+ mapper(B, b)
+ assert_raises_message(
+ sa.exc.NoForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship A.bs - "
+ "there are no foreign keys linking these "
+ "tables via secondary table 'atob'. "
+ "Specify 'primaryjoin' and 'secondaryjoin' expressions.",
+ sa.orm.configure_mappers
+ )
+
+ def test_ambiguous_fks_m2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b, a_to_b = self.tables.a, self.tables.b, self.tables.atob_ambiguous
+ mapper(A, a, properties={
+ 'bs':relationship(B, secondary=a_to_b)
+ })
+ mapper(B, b)
+ assert_raises_message(
+ sa.exc.AmbiguousForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship A.bs - "
+ "there are multiple foreign key paths linking "
+ "the tables via secondary table 'atob_ambiguous'. "
+ "Specify the 'foreign_keys' argument, providing a "
+ "list of those columns which should be counted "
+ "as containing a foreign key reference from the "
+ "secondary table to each of the parent and child tables.",
+ sa.orm.configure_mappers
+ )
+
+ def test_with_fks_m2m(self):
+ A, B = self.classes.A, self.classes.B
+ a, b, a_to_b = self.tables.a, self.tables.b, self.tables.atob_ambiguous
+ mapper(A, a, properties={
+ 'bs':relationship(B, secondary=a_to_b,
+ foreign_keys=[a_to_b.c.aid1, a_to_b.c.bid1])
+ })
+ mapper(B, b)
+ sa.orm.configure_mappers()
class InvalidRelationshipEscalationTest(fixtures.MappedTest):
class Bar(cls.Basic):
pass
+ def _assert_raises_no_relevant_fks(self, fn, expr, relname,
+ primary, *arg, **kw):
+ assert_raises_message(
+ sa.exc.ArgumentError,
+ "Could not locate any relevant foreign key columns "
+ "for %s join condition '%s' on relationship %s. "
+ "Ensure that referencing columns are associated with "
+ "a ForeignKey or ForeignKeyConstraint, or are annotated "
+ r"in the join condition with the foreign\(\) annotation."
+ % (
+ primary, expr, relname
+ ),
+ fn, *arg, **kw
+ )
+
+ def _assert_raises_no_equality(self, fn, expr, relname,
+ primary, *arg, **kw):
+ assert_raises_message(
+ sa.exc.ArgumentError,
+ "Could not locate any simple equality expressions "
+ "involving foreign key columns for %s join "
+ "condition '%s' on relationship %s. "
+ "Ensure that referencing columns are associated with a "
+ "ForeignKey or ForeignKeyConstraint, or are annotated in "
+ r"the join condition with the foreign\(\) annotation. "
+ "To allow comparison operators other than '==', "
+ "the relationship can be marked as viewonly=True." % (
+ primary, expr, relname
+ ),
+ fn, *arg, **kw
+ )
+
+ def _assert_raises_ambig_join(self, fn, relname, secondary_arg,
+ *arg, **kw):
+ if secondary_arg is not None:
+ assert_raises_message(
+ exc.ArgumentError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are multiple foreign key paths linking the "
+ "tables via secondary table '%s'. "
+ "Specify the 'foreign_keys' argument, providing a list "
+ "of those columns which should be counted as "
+ "containing a foreign key reference from the "
+ "secondary table to each of the parent and child tables."
+ % (relname, secondary_arg),
+ fn, *arg, **kw)
+ else:
+ assert_raises_message(
+ exc.ArgumentError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are no foreign keys linking these tables. "
+ % (relname,),
+ fn, *arg, **kw)
+
+ def _assert_raises_no_join(self, fn, relname, secondary_arg,
+ *arg, **kw):
+ if secondary_arg is not None:
+ assert_raises_message(
+ exc.NoForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are no foreign keys linking these tables "
+ "via secondary table '%s'. "
+ "Ensure that referencing columns are associated with a ForeignKey "
+ "or ForeignKeyConstraint, or specify 'primaryjoin' and "
+ "'secondaryjoin' expressions"
+ % (relname, secondary_arg),
+ fn, *arg, **kw)
+ else:
+ assert_raises_message(
+ exc.NoForeignKeysError,
+ "Could not determine join condition between "
+ "parent/child tables on relationship %s - "
+ "there are no foreign keys linking these tables. "
+ "Ensure that referencing columns are associated with a ForeignKey "
+ "or ForeignKeyConstraint, or specify a 'primaryjoin' "
+ "expression."
+ % (relname,),
+ fn, *arg, **kw)
+
def test_no_join(self):
bars, Foo, Bar, foos = (self.tables.bars,
self.classes.Foo,
'bars':relationship(Bar)})
mapper(Bar, bars)
- assert_raises_message(
- sa.exc.ArgumentError,
- "Could not determine join condition between parent/child "
- "tables on relationship", sa.orm.configure_mappers)
+ self._assert_raises_ambig_join(sa.orm.configure_mappers,
+ "Foo.bars", None
+ )
def test_no_join_self_ref(self):
bars, Foo, Bar, foos = (self.tables.bars,
sa.orm.configure_mappers)
- def test_no_equated_self_ref(self):
+ def test_no_equated_self_ref_no_fks(self):
bars, Foo, Bar, foos = (self.tables.bars,
self.classes.Foo,
self.classes.Bar,
primaryjoin=foos.c.id>foos.c.fid)})
mapper(Bar, bars)
- assert_raises_message(
- sa.exc.ArgumentError,
- "Could not determine relationship direction for primaryjoin "
- "condition",
- configure_mappers)
+ self._assert_raises_no_relevant_fks(configure_mappers,
+ "foos.id > foos.fid", "Foo.foos", "primary"
+ )
- def test_no_equated_self_ref(self):
+
+ def test_no_equated_self_ref_no_equality(self):
bars, Foo, Bar, foos = (self.tables.bars,
self.classes.Foo,
self.classes.Bar,
foreign_keys=[foos.c.fid])})
mapper(Bar, bars)
- assert_raises_message(
- sa.exc.ArgumentError,
- "Could not locate any foreign-key-equated, "
- "locally mapped column pairs for primaryjoin "
- "condition 'foos.id > foos.fid' on relationship "
- "Foo.foos. For more relaxed rules on join "
- "conditions, the relationship may be marked as viewonly=True.",
- sa.orm.configure_mappers)
+ self._assert_raises_no_equality(configure_mappers,
+ "foos.id > foos.fid", "Foo.foos", "primary"
+ )
def test_no_equated_viewonly(self):
bars, Bar, bars_with_fks, foos_with_fks, Foo, foos = (self.tables.bars,