diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-08-01 12:01:59 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-08-01 18:06:48 -0400 |
| commit | 19cd4d4bc01d6176a23c72d37634c8ee4acbac40 (patch) | |
| tree | 2b799e9a421e18590101e1d2961f35d8c1f63137 /lib/sqlalchemy/ext/associationproxy.py | |
| parent | 1c32206120b1a6555f8bb7a20a0c4c53ea2f52a8 (diff) | |
| download | sqlalchemy-19cd4d4bc01d6176a23c72d37634c8ee4acbac40.tar.gz | |
Handle association proxy delete and provide for scalar delete cascade
Fixed multiple issues regarding de-association of scalar objects with the
association proxy. ``del`` now works, and additionally a new flag
:paramref:`.AssociationProxy.cascade_scalar_deletes` is added, which when
set to True indicates that setting a scalar attribute to ``None`` or
deleting via ``del`` will also set the source association to ``None``.
Change-Id: I1580d761571d63eb03a7e8df078cef97d265b85c
Fixes: #4308
Diffstat (limited to 'lib/sqlalchemy/ext/associationproxy.py')
| -rw-r--r-- | lib/sqlalchemy/ext/associationproxy.py | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index a0945fa6c..3c27cb59f 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -94,7 +94,8 @@ class AssociationProxy(interfaces.InspectionAttrInfo): def __init__(self, target_collection, attr, creator=None, getset_factory=None, proxy_factory=None, - proxy_bulk_set=None, info=None): + proxy_bulk_set=None, info=None, + cascade_scalar_deletes=False): """Construct a new :class:`.AssociationProxy`. The :func:`.association_proxy` function is provided as the usual @@ -119,6 +120,15 @@ class AssociationProxy(interfaces.InspectionAttrInfo): If you want to construct instances differently, supply a 'creator' function that takes arguments as above and returns instances. + :param cascade_scalar_deletes: when True, indicates that setting + the proxied value to ``None``, or deleting it via ``del``, should + also remove the source object. Only applies to scalar attributes. + Normally, removing the proxied target will not remove the proxy + source, as this object may have other state that is still to be + kept. + + .. versionadded:: 1.3 + :param getset_factory: Optional. Proxied attribute access is automatically handled by routines that get and set values based on the `attr` argument for this proxy. @@ -150,6 +160,7 @@ class AssociationProxy(interfaces.InspectionAttrInfo): self.getset_factory = getset_factory self.proxy_factory = proxy_factory self.proxy_bulk_set = proxy_bulk_set + self.cascade_scalar_deletes = cascade_scalar_deletes self.owning_class = None self.key = '_%s_%s_%s' % ( @@ -308,9 +319,13 @@ class AssociationProxy(interfaces.InspectionAttrInfo): creator = self.creator and self.creator or self.target_class target = getattr(obj, self.target_collection) if target is None: + if values is None: + return setattr(obj, self.target_collection, creator(values)) else: self._scalar_set(target, values) + if values is None and self.cascade_scalar_deletes: + setattr(obj, self.target_collection, None) else: proxy = self.__get__(obj, None) if proxy is not values: @@ -321,7 +336,11 @@ class AssociationProxy(interfaces.InspectionAttrInfo): if self.owning_class is None: self._calc_owner(obj, None) - delattr(obj, self.key) + if self.scalar: + target = getattr(obj, self.target_collection) + if target is not None: + delattr(target, self.value_attr) + delattr(obj, self.target_collection) def _initialize_scalar_accessors(self): if self.getset_factory: |
