diff options
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r-- | lib/sqlalchemy/schema.py | 93 |
1 files changed, 38 insertions, 55 deletions
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 5ddca718a..a7f24a211 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -86,11 +86,8 @@ class _TableSingleton(expression._FigureVisitName): def __call__(self, name, metadata, *args, **kwargs): schema = kwargs.get('schema', None) - autoload = kwargs.pop('autoload', False) - autoload_with = kwargs.pop('autoload_with', False) - mustexist = kwargs.pop('mustexist', False) useexisting = kwargs.pop('useexisting', False) - include_columns = kwargs.pop('include_columns', None) + mustexist = kwargs.pop('mustexist', False) key = _get_table_key(name, schema) try: table = metadata.tables[key] @@ -101,57 +98,23 @@ class _TableSingleton(expression._FigureVisitName): except KeyError: if mustexist: raise exceptions.ArgumentError("Table '%s' not defined" % (key)) - table = type.__call__(self, name, metadata, **kwargs) - table._set_parent(metadata) - # load column definitions from the database if 'autoload' is defined - # we do it after the table is in the singleton dictionary to support - # circular foreign keys - if autoload: - try: - if autoload_with: - autoload_with.reflecttable(table, include_columns=include_columns) - else: - metadata._get_bind(raiseerr=True).reflecttable(table, include_columns=include_columns) - except exceptions.NoSuchTableError: + try: + return type.__call__(self, name, metadata, *args, **kwargs) + except: + if key in metadata.tables: del metadata.tables[key] - raise - # initialize all the column, etc. objects. done after - # reflection to allow user-overrides - table._init_items(*args) - return table + raise class Table(SchemaItem, expression.TableClause): - """Represent a relational database table. - - This subclasses ``expression.TableClause`` to provide a table that is - associated with an instance of ``MetaData``, which in turn - may be associated with an instance of ``Engine``. - - Whereas ``TableClause`` represents a table as its used in an SQL - expression, ``Table`` represents a table as it exists in a - database schema. - - If this ``Table`` is ultimately associated with an engine, - the ``Table`` gains the ability to access the database directly - without the need for dealing with an explicit ``Connection`` object; - this is known as "implicit execution". - - Implicit operation allows the ``Table`` to access the database to - reflect its own properties (via the autoload=True flag), it allows - the create() and drop() methods to be called without passing - a connectable, and it also propigates the underlying engine to - constructed SQL objects so that they too can be executed via their - execute() method without the need for a ``Connection``. - """ + """Represent a relational database table.""" __metaclass__ = _TableSingleton - def __init__(self, name, metadata, **kwargs): + def __init__(self, name, metadata, *args, **kwargs): """Construct a Table. - Table objects can be constructed directly. The init method is - actually called via the TableSingleton metaclass. Arguments + Table objects can be constructed directly. Arguments are: name @@ -168,8 +131,8 @@ class Table(SchemaItem, expression.TableClause): Should contain a listing of the Column objects for this table. \**kwargs - Options include: - + kwargs include: + schema The *schema name* for this table, which is required if the table resides in a schema other than the @@ -185,14 +148,14 @@ class Table(SchemaItem, expression.TableClause): if autoload==True, this is an optional Engine or Connection instance to be used for the table reflection. If ``None``, the underlying MetaData's bound connectable will be used. - + include_columns A list of strings indicating a subset of columns to be loaded via the ``autoload`` operation; table columns who aren't present in this list will not be represented on the resulting ``Table`` object. Defaults to ``None`` which indicates all columns should be reflected. - + mustexist Defaults to False: indicates that this Table must already have been defined elsewhere in the application, else an @@ -236,18 +199,35 @@ class Table(SchemaItem, expression.TableClause): else: self.fullname = self.name self.owner = kwargs.pop('owner', None) + + autoload = kwargs.pop('autoload', False) + autoload_with = kwargs.pop('autoload_with', None) + include_columns = kwargs.pop('include_columns', None) + # validate remaining kwargs that they all specify DB prefixes if len([k for k in kwargs if not re.match(r'^(?:%s)_' % '|'.join(databases.__all__), k)]): raise TypeError("Invalid argument(s) for Table: %s" % repr(kwargs.keys())) - # store extra kwargs, which should only contain db-specific options self.kwargs = kwargs + + self._set_parent(metadata) + # load column definitions from the database if 'autoload' is defined + # we do it after the table is in the singleton dictionary to support + # circular foreign keys + if autoload: + if autoload_with: + autoload_with.reflecttable(self, include_columns=include_columns) + else: + metadata._get_bind(raiseerr=True).reflecttable(self, include_columns=include_columns) + + # initialize all the column, etc. objects. done after + # reflection to allow user-overrides + self._init_items(*args) key = property(lambda self:_get_table_key(self.name, self.schema)) def _export_columns(self, columns=None): - # override FromClause's collection initialization logic; TableClause and Table - # implement it differently + # override FromClause's collection initialization logic; Table implements it differently pass def _set_primary_key(self, pk): @@ -510,6 +490,7 @@ class Column(SchemaItem, expression._ColumnClause): table._columns.add(self) else: self._pre_existing_column = None + if self.primary_key: table.primary_key.add(self) elif self.key in table.primary_key: @@ -632,8 +613,10 @@ class ForeignKey(SchemaItem): # locate the parent table this foreign key is attached to. # we use the "original" column which our parent column represents # (its a list of columns/other ColumnElements if the parent table is a UNION) - if isinstance(self.parent.base_column, Column): - parenttable = self.parent.base_column.table + for c in self.parent.base_columns: + if isinstance(c, Column): + parenttable = c.table + break else: raise exceptions.ArgumentError("Parent column '%s' does not descend from a table-attached Column" % str(self.parent)) m = re.match(r"^(.+?)(?:\.(.+?))?(?:\.(.+?))?$", self._colspec, re.UNICODE) |