summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-11-30 20:25:22 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2010-11-30 20:25:22 -0500
commit3c9d2d7b2f76fc18c0f1141a813a7045ac8cb853 (patch)
treedb44f0c0edec5bfcea4009e5d0a457f6e1d04933 /lib
parent79fc3cdc1b0be99e138580905290823463766944 (diff)
downloadsqlalchemy-3c9d2d7b2f76fc18c0f1141a813a7045ac8cb853.tar.gz
- replace GenericBackrefExtension with straight events
- add "backref" argument to register_attribute_impl
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/attributes.py48
-rw-r--r--lib/sqlalchemy/orm/properties.py4
-rw-r--r--lib/sqlalchemy/orm/strategies.py4
3 files changed, 26 insertions, 30 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 9ae885bf9..d80a7fe5a 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -791,21 +791,10 @@ class CollectionAttributeImpl(AttributeImpl):
return getattr(user_data, '_sa_adapter')
-class GenericBackrefExtension(interfaces.AttributeExtension):
- """An extension which synchronizes a two-way relationship.
+def backref_listeners(attribute, key, uselist):
+ """Apply listeners to synchronize a two-way relationship."""
- A typical two-way relationship is a parent object containing a list of
- child objects, where each child object references the parent. The other
- are two objects which contain scalar references to each other.
-
- """
-
- active_history = False
-
- def __init__(self, key):
- self.key = key
-
- def set(self, state, child, oldchild, initiator):
+ def set_(state, child, oldchild, initiator):
if oldchild is child:
return child
@@ -814,7 +803,7 @@ class GenericBackrefExtension(interfaces.AttributeExtension):
# present when updating via a backref.
old_state, old_dict = instance_state(oldchild),\
instance_dict(oldchild)
- impl = old_state.get_impl(self.key)
+ impl = old_state.get_impl(key)
try:
impl.remove(old_state,
old_dict,
@@ -826,7 +815,7 @@ class GenericBackrefExtension(interfaces.AttributeExtension):
if child is not None:
child_state, child_dict = instance_state(child),\
instance_dict(child)
- child_state.get_impl(self.key).append(
+ child_state.get_impl(key).append(
child_state,
child_dict,
state.obj(),
@@ -834,10 +823,10 @@ class GenericBackrefExtension(interfaces.AttributeExtension):
passive=PASSIVE_NO_FETCH)
return child
- def append(self, state, child, initiator):
+ def append(state, child, initiator):
child_state, child_dict = instance_state(child), \
instance_dict(child)
- child_state.get_impl(self.key).append(
+ child_state.get_impl(key).append(
child_state,
child_dict,
state.obj(),
@@ -845,18 +834,24 @@ class GenericBackrefExtension(interfaces.AttributeExtension):
passive=PASSIVE_NO_FETCH)
return child
- def remove(self, state, child, initiator):
+ def remove(state, child, initiator):
if child is not None:
child_state, child_dict = instance_state(child),\
instance_dict(child)
- child_state.get_impl(self.key).remove(
+ child_state.get_impl(key).remove(
child_state,
child_dict,
state.obj(),
initiator,
passive=PASSIVE_NO_FETCH)
-
-
+
+ if uselist:
+ event.listen(append, "on_append", attribute, retval=False, raw=True)
+ else:
+ event.listen(set_, "on_set", attribute, retval=False, raw=True)
+ # TODO: need coverage in test/orm/ of remove event
+ event.listen(remove, "on_remove", attribute, retval=False, raw=True)
+
class History(tuple):
"""A 3-tuple of added, unchanged and deleted values,
representing the changes which have occured on an instrumented
@@ -1010,14 +1005,15 @@ def register_attribute(class_, key, **kw):
comparator = kw.pop('comparator', None)
parententity = kw.pop('parententity', None)
doc = kw.pop('doc', None)
- register_descriptor(class_, key,
+ desc = register_descriptor(class_, key,
comparator, parententity, doc=doc)
register_attribute_impl(class_, key, **kw)
+ return desc
def register_attribute_impl(class_, key,
uselist=False, callable_=None,
useobject=False, mutable_scalars=False,
- impl_class=None, **kw):
+ impl_class=None, backref=None, **kw):
manager = manager_of_class(class_)
if uselist:
@@ -1044,6 +1040,9 @@ def register_attribute_impl(class_, key,
impl = ScalarAttributeImpl(class_, key, callable_, dispatch, **kw)
manager[key].impl = impl
+
+ if backref:
+ backref_listeners(manager[key], backref, uselist)
manager.post_configure_attribute(key)
@@ -1058,6 +1057,7 @@ def register_descriptor(class_, key, comparator=None,
descriptor.__doc__ = doc
manager.instrument_attribute(key, descriptor)
+ return descriptor
def unregister_attribute(class_, key):
manager_of_class(class_).uninstrument_attribute(key)
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index b68290dbd..81ac9262c 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -1347,10 +1347,6 @@ class RelationshipProperty(StrategizedProperty):
)
mapper._configure_property(backref_key, relationship)
if self.back_populates:
- self.extension = list(util.to_list(self.extension,
- default=[]))
- self.extension.append(
- attributes.GenericBackrefExtension(self.back_populates))
self._add_reverse_property(self.back_populates)
def _post_init(self):
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index d8d4afc37..f23145da5 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -47,7 +47,6 @@ def _register_attribute(strategy, mapper, useobject,
if useobject:
attribute_ext.append(sessionlib.UOWEventHandler(prop.key))
-
for m in mapper.self_and_descendants:
if prop is m._props.get(prop.key):
@@ -60,7 +59,7 @@ def _register_attribute(strategy, mapper, useobject,
uselist=uselist,
copy_function=copy_function,
compare_function=compare_function,
- useobject=useobject,
+ useobject=useobject,
extension=attribute_ext,
trackparent=useobject,
typecallable=typecallable,
@@ -398,6 +397,7 @@ class LazyLoader(AbstractRelationshipLoader):
useobject=True,
callable_=self._class_level_loader,
uselist = self.parent_property.uselist,
+ backref = self.parent_property.back_populates,
typecallable = self.parent_property.collection_class,
active_history = \
self.parent_property.active_history or \