summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/databases/sqlite.py20
-rw-r--r--lib/sqlalchemy/orm/mapper.py4
-rw-r--r--lib/sqlalchemy/orm/properties.py20
-rw-r--r--lib/sqlalchemy/sql.py5
4 files changed, 37 insertions, 12 deletions
diff --git a/lib/sqlalchemy/databases/sqlite.py b/lib/sqlalchemy/databases/sqlite.py
index b68bf99a7..529486f46 100644
--- a/lib/sqlalchemy/databases/sqlite.py
+++ b/lib/sqlalchemy/databases/sqlite.py
@@ -200,16 +200,30 @@ class SQLiteDialect(ansisql.ANSIDialect):
raise exceptions.NoSuchTableError(table.name)
c = connection.execute("PRAGMA foreign_key_list(" + table.name + ")", {})
+ fks = {}
while True:
row = c.fetchone()
if row is None:
break
- (tablename, localcol, remotecol) = (row[2], row[3], row[4])
- #print "row! " + repr(row)
+ (constraint_name, tablename, localcol, remotecol) = (row[0], row[2], row[3], row[4])
+ try:
+ fk = fks[constraint_name]
+ except KeyError:
+ fk = ([],[])
+ fks[constraint_name] = fk
+
+ print "row! " + repr([key for key in row.keys()]), repr(row)
# look up the table based on the given table's engine, not 'self',
# since it could be a ProxyEngine
remotetable = schema.Table(tablename, table.metadata, autoload=True, autoload_with=connection)
- table.c[localcol].append_item(schema.ForeignKey(remotetable.c[remotecol]))
+ constrained_column = table.c[localcol].name
+ refspec = ".".join([tablename, remotecol])
+ if constrained_column not in fk[0]:
+ fk[0].append(constrained_column)
+ if refspec not in fk[1]:
+ fk[1].append(refspec)
+ for name, value in fks.iteritems():
+ table.append_item(schema.ForeignKeyConstraint(value[0], value[1]))
# check for UNIQUE indexes
c = connection.execute("PRAGMA index_list(" + table.name + ")", {})
unique_indexes = []
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index c9c342dc9..4db2b40f2 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -474,6 +474,10 @@ class Mapper(object):
else:
return self
+ def common_parent(self, other):
+ """return true if the given mapper shares a common inherited parent as this mapper"""
+ return self.base_mapper() is other.base_mapper()
+
def isa(self, other):
"""return True if the given mapper inherits from this mapper"""
m = other
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 2d2bf5fec..f03feaa1c 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -219,15 +219,17 @@ class PropertyLoader(mapper.MapperProperty):
if self.secondaryjoin is not None and self.secondary is None:
raise exceptions.ArgumentError("Property '" + self.key + "' specified with secondary join condition but no secondary argument")
# if join conditions were not specified, figure them out based on foreign keys
- if self.secondary is not None:
- if self.secondaryjoin is None:
- self.secondaryjoin = sql.join(self.mapper.unjoined_table, self.secondary).onclause
- if self.primaryjoin is None:
- self.primaryjoin = sql.join(self.parent.unjoined_table, self.secondary).onclause
- else:
- if self.primaryjoin is None:
- self.primaryjoin = sql.join(self.parent.unjoined_table, self.target).onclause
-
+ try:
+ if self.secondary is not None:
+ if self.secondaryjoin is None:
+ self.secondaryjoin = sql.join(self.mapper.unjoined_table, self.secondary).onclause
+ if self.primaryjoin is None:
+ self.primaryjoin = sql.join(self.parent.unjoined_table, self.secondary).onclause
+ else:
+ if self.primaryjoin is None:
+ self.primaryjoin = sql.join(self.parent.unjoined_table, self.target).onclause
+ except exceptions.ArgumentError, e:
+ raise exceptions.ArgumentError("Error determining primary and/or secondary join for relationship '%s' between mappers '%s' and '%s'. You should specify the 'primaryjoin' (and 'secondaryjoin', if there is an association table present) keyword arguments to the relation() function (or for backrefs, by specifying the backref using the backref() function with keyword arguments) to explicitly specify the join conditions. Nested error is \"%s\"" % (self.key, self.localparent, self.mapper, str(e)))
# if the foreign key wasnt specified and theres no assocaition table, try to figure
# out who is dependent on who. we dont need all the foreign keys represented in the join,
# just one of them.
diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py
index 3650dd8b8..8ad3ced45 100644
--- a/lib/sqlalchemy/sql.py
+++ b/lib/sqlalchemy/sql.py
@@ -1070,17 +1070,22 @@ class Join(FromClause):
return column
def _match_primaries(self, primary, secondary):
crit = []
+ constraints = util.Set()
for fk in secondary.foreign_keys:
if fk.references(primary):
crit.append(primary.corresponding_column(fk.column) == fk.parent)
+ constraints.add(fk.constraint)
self.foreignkey = fk.parent
if primary is not secondary:
for fk in primary.foreign_keys:
if fk.references(secondary):
crit.append(secondary.corresponding_column(fk.column) == fk.parent)
+ constraints.add(fk.constraint)
self.foreignkey = fk.parent
if len(crit) == 0:
raise exceptions.ArgumentError("Cant find any foreign key relationships between '%s' and '%s'" % (primary.name, secondary.name))
+# elif len(constraints) > 1:
+# raise exceptions.ArgumentError("Cant determine join between '%s' and '%s'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly. %s" % (primary.name, secondary.name, constraints))
elif len(crit) == 1:
return (crit[0])
else: