diff options
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r-- | lib/sqlalchemy/schema.py | 83 |
1 files changed, 47 insertions, 36 deletions
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 5fa84063f..32ea2b5ee 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -769,13 +769,15 @@ class ForeignKey(SchemaItem): __visit_name__ = 'foreign_key' - def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None, deferrable=None, initially=None): + def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None, deferrable=None, initially=None, link_to_name=False): """ Construct a column-level FOREIGN KEY. :param column: A single target column for the key relationship. A :class:`Column` - object or a column name as a string: ``tablename.columnname`` or - ``schema.tablename.columnname``. + object or a column name as a string: ``tablename.columnkey`` or + ``schema.tablename.columnkey``. ``columnkey`` is the ``key`` which has been assigned + to the column (defaults to the column name itself), unless ``link_to_name`` is ``True`` + in which case the rendered name of the column is used. :param constraint: Optional. A parent :class:`ForeignKeyConstraint` object. If not supplied, a :class:`ForeignKeyConstraint` will be automatically created @@ -797,7 +799,10 @@ class ForeignKey(SchemaItem): :param initially: Optional string. If set, emit INITIALLY <value> when issuing DDL for this constraint. - + + :param link_to_name: if True, the string name given in ``column`` is the rendered + name of the referenced column, not its locally assigned ``key``. + :param use_alter: If True, do not emit this key as part of the CREATE TABLE definition. Instead, use ALTER TABLE after table creation to add the key. Useful for circular dependencies. @@ -812,6 +817,7 @@ class ForeignKey(SchemaItem): self.ondelete = ondelete self.deferrable = deferrable self.initially = initially + self.link_to_name = link_to_name def __repr__(self): return "ForeignKey(%r)" % self._get_colspec() @@ -877,21 +883,29 @@ class ForeignKey(SchemaItem): "foreign key" % tname) table = Table(tname, parenttable.metadata, mustexist=True, schema=schema) - try: - if colname is None: - # colname is None in the case that ForeignKey argument - # was specified as table name only, in which case we - # match the column name to the same column on the - # parent. - key = self.parent - _column = table.c[self.parent.key] - else: - _column = table.c[colname] - except KeyError, e: + + _column = None + if colname is None: + # colname is None in the case that ForeignKey argument + # was specified as table name only, in which case we + # match the column name to the same column on the + # parent. + key = self.parent + _column = table.c.get(self.parent.key, None) + elif self.link_to_name: + key = colname + for c in table.c: + if c.name == colname: + _column = c + else: + key = colname + _column = table.c.get(colname, None) + + if not _column: raise exc.NoReferencedColumnError( "Could not create ForeignKey '%s' on table '%s': " "table '%s' has no column named '%s'" % ( - self._colspec, parenttable.name, table.name, str(e))) + self._colspec, parenttable.name, table.name, key)) elif hasattr(self._colspec, '__clause_element__'): _column = self._colspec.__clause_element__() @@ -1191,50 +1205,47 @@ class ForeignKeyConstraint(Constraint): """ __visit_name__ = 'foreign_key_constraint' - def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, use_alter=False, deferrable=None, initially=None): + def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, use_alter=False, deferrable=None, initially=None, link_to_name=False): """Construct a composite-capable FOREIGN KEY. - columns - A sequence of local column names. The named columns must be defined - and present in the parent Table. + :param columns: A sequence of local column names. The named columns must be defined + and present in the parent Table. The names should match the ``key`` given + to each column (defaults to the name) unless ``link_to_name`` is True. - refcolumns - A sequence of foreign column names or Column objects. The columns + :param refcolumns: A sequence of foreign column names or Column objects. The columns must all be located within the same Table. - name - Optional, the in-database name of the key. + :param name: Optional, the in-database name of the key. - onupdate - Optional string. If set, emit ON UPDATE <value> when issuing DDL + :param onupdate: Optional string. If set, emit ON UPDATE <value> when issuing DDL for this constraint. Typical values include CASCADE, DELETE and RESTRICT. - ondelete - Optional string. If set, emit ON DELETE <value> when issuing DDL + :param ondelete: Optional string. If set, emit ON DELETE <value> when issuing DDL for this constraint. Typical values include CASCADE, DELETE and RESTRICT. - deferrable - Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when + :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when issuing DDL for this constraint. - initially - Optional string. If set, emit INITIALLY <value> when issuing DDL + :param initially: Optional string. If set, emit INITIALLY <value> when issuing DDL for this constraint. - use_alter - If True, do not emit this key as part of the CREATE TABLE + :param link_to_name: if True, the string name given in ``column`` is the rendered + name of the referenced column, not its locally assigned ``key``. + + :param use_alter: If True, do not emit this key as part of the CREATE TABLE definition. Instead, use ALTER TABLE after table creation to add the key. Useful for circular dependencies. + """ - super(ForeignKeyConstraint, self).__init__(name, deferrable, initially) self.__colnames = columns self.__refcolnames = refcolumns self.elements = util.OrderedSet() self.onupdate = onupdate self.ondelete = ondelete + self.link_to_name = link_to_name if self.name is None and use_alter: raise exc.ArgumentError("Alterable ForeignKey/ForeignKeyConstraint requires a name") self.use_alter = use_alter @@ -1247,7 +1258,7 @@ class ForeignKeyConstraint(Constraint): self.append_element(c, r) def append_element(self, col, refcol): - fk = ForeignKey(refcol, constraint=self, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete, use_alter=self.use_alter) + fk = ForeignKey(refcol, constraint=self, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete, use_alter=self.use_alter, link_to_name=self.link_to_name) fk._set_parent(self.table.c[col]) self._append_fk(fk) |