summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/mapper.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/mapper.py')
-rw-r--r--lib/sqlalchemy/orm/mapper.py191
1 files changed, 119 insertions, 72 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 5a2ca6ed4..b1a6b1a33 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -151,17 +151,7 @@ class Mapper(object):
self.allow_partial_pks = allow_partial_pks
- if with_polymorphic == '*':
- self.with_polymorphic = ('*', None)
- elif isinstance(with_polymorphic, (tuple, list)):
- if isinstance(with_polymorphic[0], (basestring, tuple, list)):
- self.with_polymorphic = with_polymorphic
- else:
- self.with_polymorphic = (with_polymorphic, None)
- elif with_polymorphic is not None:
- raise sa_exc.ArgumentError("Invalid setting for with_polymorphic")
- else:
- self.with_polymorphic = None
+ self._set_with_polymorphic(with_polymorphic)
if isinstance(self.local_table, expression._SelectBase):
raise sa_exc.InvalidRequestError(
@@ -225,10 +215,10 @@ class Mapper(object):
local_table = None
"""The :class:`.Selectable` which this :class:`.Mapper` manages.
-
+
Typically is an instance of :class:`.Table` or :class:`.Alias`.
May also be ``None``.
-
+
The "local" table is the
selectable that the :class:`.Mapper` is directly responsible for
managing from an attribute access and flush perspective. For
@@ -239,15 +229,15 @@ class Mapper(object):
single-table inheriting mapper, local_table will be ``None``.
See also :attr:`~.Mapper.mapped_table`.
-
+
"""
mapped_table = None
"""The :class:`.Selectable` to which this :class:`.Mapper` is mapped.
-
+
Typically an instance of :class:`.Table`, :class:`.Join`, or
- :class:`.Alias`.
-
+ :class:`.Alias`.
+
The "mapped" table is the selectable that
the mapper selects from during queries. For non-inheriting
mappers, the mapped table is the same as the "local" table.
@@ -255,99 +245,99 @@ class Mapper(object):
full :class:`.Join` representing full rows for this particular
subclass. For single-table inheritance mappers, mapped_table
references the base table.
-
+
See also :attr:`~.Mapper.local_table`.
-
+
"""
inherits = None
"""References the :class:`.Mapper` which this :class:`.Mapper`
inherits from, if any.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
configured = None
"""Represent ``True`` if this :class:`.Mapper` has been configured.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
See also :func:`.configure_mappers`.
-
+
"""
concrete = None
"""Represent ``True`` if this :class:`.Mapper` is a concrete
inheritance mapper.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
tables = None
"""An iterable containing the collection of :class:`.Table` objects
which this :class:`.Mapper` is aware of.
-
+
If the mapper is mapped to a :class:`.Join`, or an :class:`.Alias`
representing a :class:`.Select`, the individual :class:`.Table`
objects that comprise the full construct will be represented here.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
primary_key = None
"""An iterable containing the collection of :class:`.Column` objects
which comprise the 'primary key' of the mapped table, from the
perspective of this :class:`.Mapper`.
-
+
This list is against the selectable in :attr:`~.Mapper.mapped_table`. In the
case of inheriting mappers, some columns may be managed by a superclass
mapper. For example, in the case of a :class:`.Join`, the primary
key is determined by all of the primary key columns across all tables
referenced by the :class:`.Join`.
-
+
The list is also not necessarily the same as the primary key column
collection associated with the underlying tables; the :class:`.Mapper`
features a ``primary_key`` argument that can override what the
:class:`.Mapper` considers as primary key columns.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
class_ = None
"""The Python class which this :class:`.Mapper` maps.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
class_manager = None
"""The :class:`.ClassManager` which maintains event listeners
and class-bound descriptors for this :class:`.Mapper`.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
"""
single = None
"""Represent ``True`` if this :class:`.Mapper` is a single table
- inheritance mapper.
-
+ inheritance mapper.
+
:attr:`~.Mapper.local_table` will be ``None`` if this flag is set.
-
- This is a *read only* attribute determined during mapper construction.
+
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
non_primary = None
@@ -355,35 +345,35 @@ class Mapper(object):
mapper, e.g. a mapper that is used only to selet rows but not for
persistence management.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
polymorphic_on = None
"""The :class:`.Column` specified as the ``polymorphic_on`` column
for this :class:`.Mapper`, within an inheritance scenario.
-
+
This attribute may also be of other types besides :class:`.Column`
in a future SQLAlchemy release.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
polymorphic_map = None
"""A mapping of "polymorphic identity" identifiers mapped to :class:`.Mapper`
instances, within an inheritance scenario.
-
+
The identifiers can be of any type which is comparable to the
type of column represented by :attr:`~.Mapper.polymorphic_on`.
-
+
An inheritance chain of mappers will all reference the same
polymorphic map object. The object is used to correlate incoming
result rows to target mappers.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
"""
@@ -391,32 +381,32 @@ class Mapper(object):
polymorphic_identity = None
"""Represent an identifier which is matched against the :attr:`~.Mapper.polymorphic_on`
column during result row loading.
-
+
Used only with inheritance, this object can be of any type which is
comparable to the type of column represented by :attr:`~.Mapper.polymorphic_on`.
-
- This is a *read only* attribute determined during mapper construction.
+
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
base_mapper = None
"""The base-most :class:`.Mapper` in an inheritance chain.
-
+
In a non-inheriting scenario, this attribute will always be this
:class:`.Mapper`. In an inheritance scenario, it references
the :class:`.Mapper` which is parent to all other :class:`.Mapper`
objects in the inheritance chain.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
columns = None
"""A collection of :class:`.Column` or other scalar expression
objects maintained by this :class:`.Mapper`.
-
+
The collection behaves the same as that of the ``c`` attribute on
any :class:`.Table` object, except that only those columns included in
this mapping are present, and are keyed based on the attribute name
@@ -424,9 +414,9 @@ class Mapper(object):
:class:`.Column` itself. Additionally, scalar expressions mapped
by :func:`.column_property` are also present here.
- This is a *read only* attribute determined during mapper construction.
+ This is a *read only* attribute determined during mapper construction.
Behavior is undefined if directly modified.
-
+
"""
validators = None
@@ -530,16 +520,6 @@ class Mapper(object):
if self.polymorphic_identity is not None:
self.polymorphic_map[self.polymorphic_identity] = self
- if self.polymorphic_on is None:
- for mapper in self.iterate_to_root():
- # try to set up polymorphic on using
- # correesponding_column(); else leave
- # as None
- if mapper.polymorphic_on is not None:
- self.polymorphic_on = \
- self.mapped_table.corresponding_column(
- mapper.polymorphic_on)
- break
else:
self._all_tables = set()
self.base_mapper = self
@@ -553,6 +533,59 @@ class Mapper(object):
"Mapper '%s' does not have a mapped_table specified."
% self)
+ def _set_with_polymorphic(self, with_polymorphic):
+ if with_polymorphic == '*':
+ self.with_polymorphic = ('*', None)
+ elif isinstance(with_polymorphic, (tuple, list)):
+ if isinstance(with_polymorphic[0], (basestring, tuple, list)):
+ self.with_polymorphic = with_polymorphic
+ else:
+ self.with_polymorphic = (with_polymorphic, None)
+ elif with_polymorphic is not None:
+ raise sa_exc.ArgumentError("Invalid setting for with_polymorphic")
+ else:
+ self.with_polymorphic = None
+
+ if isinstance(self.local_table, expression._SelectBase):
+ raise sa_exc.InvalidRequestError(
+ "When mapping against a select() construct, map against "
+ "an alias() of the construct instead."
+ "This because several databases don't allow a "
+ "SELECT from a subquery that does not have an alias."
+ )
+
+ if self.with_polymorphic and \
+ isinstance(self.with_polymorphic[1],
+ expression._SelectBase):
+ self.with_polymorphic = (self.with_polymorphic[0],
+ self.with_polymorphic[1].alias())
+ if self.configured:
+ self._expire_memoizations()
+
+ def _set_concrete_base(self, mapper):
+ """Set the given :class:`.Mapper` as the 'inherits' for this :class:`.Mapper`,
+ assuming this :class:`.Mapper` is concrete and does not already have
+ an inherits."""
+
+ assert self.concrete
+ assert not self.inherits
+ assert isinstance(mapper, Mapper)
+ self.inherits = mapper
+ self.inherits.polymorphic_map.update(self.polymorphic_map)
+ self.polymorphic_map = self.inherits.polymorphic_map
+ for mapper in self.iterate_to_root():
+ if mapper.polymorphic_on is not None:
+ mapper._requires_row_aliasing = True
+ self.batch = self.inherits.batch
+ self.base_mapper = self.inherits.base_mapper
+ self.inherits._inheriting_mappers.add(self)
+ self.passive_updates = self.inherits.passive_updates
+ self._all_tables = self.inherits._all_tables
+
+ def _set_polymorphic_on(self, polymorphic_on):
+ self.polymorphic_on = polymorphic_on
+ self._configure_polymorphic_setter(True)
+
def _configure_legacy_instrument_class(self):
if self.inherits:
@@ -818,7 +851,7 @@ class Mapper(object):
init=False,
setparent=True)
- def _configure_polymorphic_setter(self):
+ def _configure_polymorphic_setter(self, init=False):
"""Configure an attribute on the mapper representing the
'polymorphic_on' column, if applicable, and not
already generated by _configure_properties (which is typical).
@@ -834,6 +867,17 @@ class Mapper(object):
# but we need it for the base mapper
setter = False
+ if self.polymorphic_on is None:
+ for mapper in self.iterate_to_root():
+ # try to set up polymorphic on using
+ # correesponding_column(); else leave
+ # as None
+ if mapper.polymorphic_on is not None:
+ self.polymorphic_on = \
+ self.mapped_table.corresponding_column(
+ mapper.polymorphic_on)
+ break
+
if self.polymorphic_on is not None:
setter = True
@@ -861,7 +905,7 @@ class Mapper(object):
self._configure_property(
col.key,
properties.ColumnProperty(col, _instrument=instrument),
- init=False, setparent=True)
+ init=init, setparent=True)
polymorphic_key = col.key
else:
polymorphic_key = self._columntoproperty[self.polymorphic_on].key
@@ -2714,6 +2758,7 @@ def configure_mappers():
if not _new_mappers:
return
+ _call_configured = None
_COMPILE_MUTEX.acquire()
try:
global _already_compiling
@@ -2744,6 +2789,7 @@ def configure_mappers():
mapper._post_configure_properties()
mapper._expire_memoizations()
mapper.dispatch.mapper_configured(mapper, mapper.class_)
+ _call_configured = mapper
except:
exc = sys.exc_info()[1]
if not hasattr(exc, '_configure_failed'):
@@ -2755,7 +2801,8 @@ def configure_mappers():
_already_compiling = False
finally:
_COMPILE_MUTEX.release()
-
+ if _call_configured is not None:
+ _call_configured.dispatch.after_configured()
def reconstructor(fn):
"""Decorate a method as the 'reconstructor' hook.