]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Default to using current mapped class as owner if none found
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 20 Feb 2018 17:15:57 +0000 (12:15 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 20 Feb 2018 21:41:48 +0000 (16:41 -0500)
Repaired regression caused in 1.2.3 and 1.1.16 regarding association proxy
objects, revising the approach to :ticket:`4185` when calculating the
"owning class" of an association proxy to default to choosing the current
class if the proxy object is not directly associated with a mapped class,
such as a mixin.

Change-Id: I87d0ac09f695dc285bd4bbe0a547f1d5ce23e068
Fixes: #4185
doc/build/changelog/unreleased_11/4185.rst [new file with mode: 0644]
lib/sqlalchemy/ext/associationproxy.py
test/ext/test_associationproxy.py

diff --git a/doc/build/changelog/unreleased_11/4185.rst b/doc/build/changelog/unreleased_11/4185.rst
new file mode 100644 (file)
index 0000000..a6b6bfb
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+    :tags: bug, ext
+    :tickets: 4185
+    :versions: 1.2.4
+
+    Repaired regression caused in 1.2.3 and 1.1.16 regarding association proxy
+    objects, revising the approach to :ticket:`4185` when calculating the
+    "owning class" of an association proxy to default to choosing the current
+    class if the proxy object is not directly associated with a mapped class,
+    such as a mixin.
index 72200c5e21922b09fcb8236705d77c923e70a817..1ebc7b420450a7b0e196a7bda905ef552bc65a44 100644 (file)
@@ -271,7 +271,12 @@ class AssociationProxy(interfaces.InspectionAttrInfo):
 
         # note we can get our real .key here too
         owner = insp.mapper.class_manager._locate_owning_manager(self)
-        self.owning_class = owner.class_
+        if owner is not None:
+            self.owning_class = owner.class_
+        else:
+            # the proxy is attached to a class that is not mapped
+            # (like a mixin), we are mapped, so, it's us.
+            self.owning_class = target_cls
 
     def __get__(self, obj, class_):
         if self.owning_class is None:
index 111ba91a8f1b706749ac6596115934c90b7d4b5c..34eeb1527166304418d65459182b3e7086dfe16e 100644 (file)
@@ -2044,6 +2044,33 @@ class AttributeAccessTest(fixtures.TestBase):
         sp.children = 'c'
         is_(SubParent.children.owning_class, Parent)
 
+    def test_resolved_to_correct_class_five(self):
+        Base = declarative_base()
+
+        class Mixin(object):
+            children = association_proxy('_children', 'value')
+
+        class Parent(Mixin, Base):
+            __tablename__ = 'parent'
+            id = Column(Integer, primary_key=True)
+            _children = relationship("Child")
+
+        class Child(Base):
+            __tablename__ = 'child'
+            parent_id = Column(
+                Integer, ForeignKey(Parent.id), primary_key=True)
+            value = Column(String)
+
+        # this triggers the owning routine, doesn't fail
+        Mixin.children
+
+        p1 = Parent()
+
+        c1 = Child(value='c1')
+        p1._children.append(c1)
+        is_(Parent.children.owning_class, Parent)
+        eq_(p1.children, ["c1"])
+
     def test_never_assign_nonetype(self):
         foo = association_proxy('x', 'y')
         foo._calc_owner(None, None)