- orm
- Fixed cascades on a += assignment to a list-based relation.
-
+
+ - synonyms can now be created against props that don't exist yet,
+ which are later added via add_property(). This commonly includes
+ backrefs. (i.e. you can make synonyms for backrefs without
+ worrying about the order of operations) [ticket:919]
+
- ext
- '+', '*', '+=' and '*=' support for association proxied lists.
def __init__(self, key, user_prop, comparator=None):
self.user_prop = user_prop
- self.comparator = comparator
+ self._comparator = comparator
self.key = key
self.impl = ProxiedAttribute.ProxyImpl(key)
-
+
+ def comparator(self):
+ if callable(self._comparator):
+ self._comparator = self._comparator()
+ return self._comparator
+ comparator = property(comparator)
+
def __get__(self, instance, owner):
if instance is None:
self.user_prop.__get__(instance, owner)
def do_init(self):
class_ = self.parent.class_
- aliased_property = self.parent._get_property(self.key, resolve_synonyms=True)
+ def comparator():
+ return self.parent._get_property(self.key, resolve_synonyms=True).comparator
self.logger.info("register managed attribute %s on class %s" % (self.key, class_.__name__))
if self.instrument is None:
class SynonymProp(object):
return getattr(obj, self.name)
self.instrument = SynonymProp()
- sessionlib.register_attribute(class_, self.key, uselist=False, proxy_property=self.instrument, useobject=False, comparator=aliased_property.comparator)
+ sessionlib.register_attribute(class_, self.key, uselist=False, proxy_property=self.instrument, useobject=False, comparator=comparator)
def merge(self, session, source, dest, _recursive):
pass
assert u.user_name == 'jack'
u.user_name = 'jacko'
assert m._columntoproperty[users.c.user_name] is m.get_property('_user_name')
+
+ def test_synonym_replaces_backref(self):
+ assert_calls = []
+ class Address(object):
+ def _get_user(self):
+ assert_calls.append("get")
+ return self._user
+ def _set_user(self, user):
+ assert_calls.append("set")
+ self._user = user
+ user = property(_get_user, _set_user)
+
+ # synonym is created against nonexistent prop
+ mapper(Address, addresses, properties={
+ 'user':synonym('_user')
+ })
+ compile_mappers()
+
+ # later, backref sets up the prop
+ mapper(User, users, properties={
+ 'addresses':relation(Address, backref='_user')
+ })
+
+ sess = create_session()
+ u1 = sess.query(User).get(7)
+ u2 = sess.query(User).get(8)
+ # comparaison ops need to work
+ a1 = sess.query(Address).filter(Address.user==u1).one()
+ assert a1.address_id == 1
+ a1.user = u2
+ assert a1.user is u2
+ self.assertEquals(assert_calls, ["set", "get"])
+
+ def test_self_ref_syn(self):
+ t = Table('nodes', MetaData(),
+ Column('id', Integer, primary_key=True),
+ Column('parent_id', Integer, ForeignKey('nodes.id')))
+
+ class Node(object):
+ pass
+
+ mapper(Node, t, properties={
+ '_children':relation(Node, backref=backref('_parent', remote_side=t.c.id)),
+ 'children':synonym('_children'),
+ 'parent':synonym('_parent')
+ })
+
+ n1 = Node()
+ n2 = Node()
+ n1.children.append(n2)
+ assert n2.parent is n2._parent is n1
+ assert n1.children[0] is n1._children[0] is n2
+ self.assertEquals(str(Node.parent == n2), ":param_1 = nodes.parent_id")
def test_illegal_non_primary(self):
mapper(User, users)