diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-01-14 18:53:58 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-01-14 21:26:35 -0500 |
| commit | 836178d42620869c3cab4b7f41d24560f0098c87 (patch) | |
| tree | 362fe080e1a41295f5f12561e77e46b009e77de3 /lib/sqlalchemy | |
| parent | 5f697cb6729761cc0422597339f7b5e41382b803 (diff) | |
| download | sqlalchemy-836178d42620869c3cab4b7f41d24560f0098c87.tar.gz | |
Relax "ambiguous" association proxy restrictions, support Proxy
Fixed issue in association proxy due to :ticket:`3423` which caused the use
of custom :class:`.PropComparator` objects with hybrid attribites, such as
the one demonstrated in the ``dictlike-polymorphic`` example to not
function within an association proxy. The strictness that was added in
:ticket:`3423` has been relaxed, and additional logic to accomodate for
an association proxy that links to a custom hybrid have been added.
Fixes: #4446
Change-Id: I8addc80f51094769915ac2dce1a301bd72ee7433
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/ext/associationproxy.py | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 59ed1aa99..5b05d2b3d 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -380,7 +380,12 @@ class AssociationProxyInstance(object): parent, owning_class, target_class, value_attr ) - is_object = getattr(target_class, value_attr).impl.uses_objects + attr = getattr(target_class, value_attr) + if attr._is_internal_proxy and not hasattr(attr, "impl"): + return AmbiguousAssociationProxyInstance( + parent, owning_class, target_class, value_attr + ) + is_object = attr.impl.uses_objects if is_object: return ObjectAssociationProxyInstance( parent, owning_class, target_class, value_attr @@ -739,13 +744,10 @@ class AmbiguousAssociationProxyInstance(AssociationProxyInstance): ) def get(self, obj): - self._ambiguous() - - def set(self, obj, values): - self._ambiguous() - - def delete(self, obj): - self._ambiguous() + if obj is None: + self._ambiguous() + else: + return super(AmbiguousAssociationProxyInstance, self).get(obj) def any(self, criterion=None, **kwargs): self._ambiguous() @@ -764,25 +766,31 @@ class AmbiguousAssociationProxyInstance(AssociationProxyInstance): if parent_instance is not None: actual_obj = getattr(parent_instance, self.target_collection) if actual_obj is not None: - instance_class = type(actual_obj) - if instance_class not in self._lookup_cache: - self._populate_cache(instance_class) - try: - return self._lookup_cache[instance_class] - except KeyError: + insp = inspect(actual_obj) + except exc.NoInspectionAvailable: pass + else: + mapper = insp.mapper + instance_class = mapper.class_ + if instance_class not in self._lookup_cache: + self._populate_cache(instance_class, mapper) + + try: + return self._lookup_cache[instance_class] + except KeyError: + pass # no object or ambiguous object given, so return "self", which - # is a no-op proxy. + # is a proxy with generally only instance-level functionality return self - def _populate_cache(self, instance_class): + def _populate_cache(self, instance_class, mapper): prop = orm.class_mapper(self.owning_class).get_property( self.target_collection ) - if inspect(instance_class).mapper.isa(prop.mapper): + if mapper.isa(prop.mapper): target_class = instance_class try: target_assoc = self._cls_unwrap_target_assoc_proxy( |
