summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/schema.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r--lib/sqlalchemy/schema.py93
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)