diff options
Diffstat (limited to 'lib/sqlalchemy/orm/properties.py')
-rw-r--r-- | lib/sqlalchemy/orm/properties.py | 77 |
1 files changed, 43 insertions, 34 deletions
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 4cf501e3f..02f0752a5 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -264,6 +264,7 @@ class ColumnProperty(StrategizedProperty): def do_init(self): super(ColumnProperty, self).do_init() + if len(self.columns) > 1 and set(self.parent.primary_key).issuperset( self.columns ): @@ -339,28 +340,51 @@ class ColumnProperty(StrategizedProperty): __slots__ = "__clause_element__", "info", "expressions" + def _orm_annotate_column(self, column): + """annotate and possibly adapt a column to be returned + as the mapped-attribute exposed version of the column. + + The column in this context needs to act as much like the + column in an ORM mapped context as possible, so includes + annotations to give hints to various ORM functions as to + the source entity of this column. It also adapts it + to the mapper's with_polymorphic selectable if one is + present. + + """ + + pe = self._parententity + annotations = { + "entity_namespace": pe, + "parententity": pe, + "parentmapper": pe, + "orm_key": self.prop.key, + } + + col = column + + # for a mapper with polymorphic_on and an adapter, return + # the column against the polymorphic selectable. + # see also orm.util._orm_downgrade_polymorphic_columns + # for the reverse operation. + if self._parentmapper._polymorphic_adapter: + mapper_local_col = col + col = self._parentmapper._polymorphic_adapter.traverse(col) + + # this is a clue to the ORM Query etc. that this column + # was adapted to the mapper's polymorphic_adapter. the + # ORM uses this hint to know which column its adapting. + annotations["adapt_column"] = mapper_local_col + + return col._annotate(annotations)._set_propagate_attrs( + {"compile_state_plugin": "orm", "plugin_subject": pe} + ) + def _memoized_method___clause_element__(self): if self.adapter: return self.adapter(self.prop.columns[0], self.prop.key) else: - pe = self._parententity - # no adapter, so we aren't aliased - # assert self._parententity is self._parentmapper - return ( - self.prop.columns[0] - ._annotate( - { - "entity_namespace": pe, - "parententity": pe, - "parentmapper": pe, - "orm_key": self.prop.key, - "compile_state_plugin": "orm", - } - ) - ._set_propagate_attrs( - {"compile_state_plugin": "orm", "plugin_subject": pe} - ) - ) + return self._orm_annotate_column(self.prop.columns[0]) def _memoized_attr_info(self): """The .info dictionary for this attribute.""" @@ -384,23 +408,8 @@ class ColumnProperty(StrategizedProperty): for col in self.prop.columns ] else: - # no adapter, so we aren't aliased - # assert self._parententity is self._parentmapper return [ - col._annotate( - { - "parententity": self._parententity, - "parentmapper": self._parententity, - "orm_key": self.prop.key, - "compile_state_plugin": "orm", - } - )._set_propagate_attrs( - { - "compile_state_plugin": "orm", - "plugin_subject": self._parententity, - } - ) - for col in self.prop.columns + self._orm_annotate_column(col) for col in self.prop.columns ] def _fallback_getattr(self, key): |