deferred with_polymorphic(), declarative support for concrete bases
support with_polymorphic as a callable. the patch below illustrates that all tests continue to pass. This would obviate the need for the awkward UsageRecipes/DeclarativeAbstractConcreteBase , and will also allow us to rewrite the "inheritance" documentation using declarative.
diff -r 086ae95614b4848c486eeb7acf2bc1b03b2a6a37 lib/sqlalchemy/orm/mapper.py
--- a/lib/sqlalchemy/orm/mapper.py Thu Jul 28 11:53:18 2011 -0400
+++ b/lib/sqlalchemy/orm/mapper.py Fri Jul 29 11:11:17 2011 -0400
@@ -150,31 +150,8 @@
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](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](1),
- expression._SelectBase):
- self.with_polymorphic = (self.with_polymorphic[0](0),
- self.with_polymorphic[1](1).alias())
+ self.with_polymorphic = lambda: with_polymorphic
+
# our 'polymorphic identity', a string name that when located in a
# result set row indicates this Mapper should be used to construct
@@ -831,13 +808,13 @@
setter = False
instrument = False
col = self.polymorphic_on
- if self.with_polymorphic is None \
- or self.with_polymorphic[1](1).corresponding_column(col) \
- is None:
- raise sa_exc.InvalidRequestError("Could not map polymorphic_on column "
- "'%s' to the mapped table - polymorphic "
- "loads will not function properly"
- % col.description)
+ #if self.with_polymorphic is None \
+ # or self.with_polymorphic[1](1).corresponding_column(col) \
+ # is None:
+ # raise sa_exc.InvalidRequestError("Could not map polymorphic_on column "
+ # "'%s' to the mapped table - polymorphic "
+ # "loads will not function properly"
+ # % col.description)
else:
instrument = True
@@ -864,6 +841,33 @@
else:
self._set_polymorphic_identity = None
+ def _init_with_polymorphic(self):
+ self.with_polymorphic = with_polymorphic = self.with_polymorphic()
+ if with_polymorphic == '*':
+ self.with_polymorphic = ('*', None)
+ elif isinstance(with_polymorphic, (tuple, list)):
+ if isinstance(with_polymorphic[0](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](1),
+ expression._SelectBase):
+ self.with_polymorphic = (self.with_polymorphic[0](0),
+ self.with_polymorphic[1](1).alias())
def _adapt_inherited_property(self, key, prop, init):
@@ -1029,6 +1033,9 @@
"""
self._log("_post_configure_properties() started")
+
+ self._init_with_polymorphic()
+
l = [prop) for key, prop in self._props.iteritems()]((key,)
for key, prop in l:
self._log("initialize prop %s", key)
Comments (5)
-
reporter -
reporter - changed title to deferred with_polymorphic(), declarative support for concrete bases
the attached patch moves several mapping settings to be settable after the fact. Test illustrates new extensions for declarative for abstract and concrete use cases. Would be nice however if _set_with_polymorphic() and _set_polymorphic_on() worked for joined inh and/or multi-level inh as well, doesn't seem to pass in test_abc_inheritance if these are moved to the "configure" step.
-
reporter polymorphic_on set later is not that big a deal, just needs to be in order of descent:
def _post_configure_properties(self): if self is self.base_mapper: for m in self.self_and_descendants: m._configure_polymorphic_setter(init=m.configured)
-
reporter - changed status to resolved
seems to work, we'll see how it goes.
-
reporter - removed milestone
Removing milestone: 0.7.3 (automated comment)
- Log in to comment
abstract base is more difficult than this - the mapping still needs to be deferred. the concrete base can be added after the fact per the patch below, but the declarative case is not working yet.