def test_collection_with_backref(self): for base in (object, MyBaseClass, MyClass): class Post(base):pass class Blog(base):pass attributes.register_class(Post) attributes.register_class(Blog) attributes.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True, useobject=True) attributes.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True, useobject=True) b = Blog() (p1, p2, p3) = (Post(), Post(), Post()) b.posts.append(p1) b.posts.append(p2) b.posts.append(p3) self.assert_(b.posts == [p1, p2, p3]) self.assert_(p2.blog is b) p3.blog = None self.assert_(b.posts == [p1, p2]) p4 = Post() p4.blog = b self.assert_(b.posts == [p1, p2, p4]) p4.blog = b p4.blog = b self.assert_(b.posts == [p1, p2, p4]) # assert no failure removing None p5 = Post() p5.blog = None del p5.blog
def _post_init(self): if self._should_log_info: self.logger.info(str(self) + " setup primary join %s" % self.primaryjoin) self.logger.info(str(self) + " setup secondary join %s" % self.secondaryjoin) self.logger.info(str(self) + " synchronize pairs [%s]" % ",".join("(%s => %s)" % (l, r) for l, r in self.synchronize_pairs)) self.logger.info(str(self) + " secondary synchronize pairs [%s]" % ",".join(("(%s => %s)" % (l, r) for l, r in self.secondary_synchronize_pairs or []))) self.logger.info(str(self) + " local/remote pairs [%s]" % ",".join("(%s / %s)" % (l, r) for l, r in self.local_remote_pairs)) self.logger.info(str(self) + " relation direction %s" % self.direction) if self.uselist is None and self.direction is MANYTOONE: self.uselist = False if self.uselist is None: self.uselist = True if not self.viewonly: self._dependency_processor = dependency.create_dependency_processor(self) # primary property handler, set up class attributes if self.is_primary(): if self.back_populates: self.extension = util.to_list(self.extension) or [] self.extension.append(attributes.GenericBackrefExtension(self.back_populates)) self._add_reverse_property(self.back_populates) if self.backref is not None: self.backref.compile(self) elif not mapper.class_mapper(self.parent.class_, compile=False)._get_property(self.key, raiseerr=False): raise sa_exc.ArgumentError("Attempting to assign a new relation '%s' to " "a non-primary mapper on class '%s'. New relations can only be " "added to the primary mapper, i.e. the very first " "mapper created for class '%s' " % (self.key, self.parent.class_.__name__, self.parent.class_.__name__)) super(RelationProperty, self).do_init()
def testlazytrackparent(self): """test that the "hasparent" flag works properly when lazy loaders and backrefs are used""" manager = attributes.AttributeManager() class Post(object): pass class Blog(object): pass # set up instrumented attributes with backrefs manager.register_attribute( Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True) manager.register_attribute( Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True) # create objects as if they'd been freshly loaded from the database (without history) b = Blog() p1 = Post() Blog.posts.set_callable(b, lambda: [p1]) Post.blog.set_callable(p1, lambda: b) manager.commit(p1, b) # no orphans (called before the lazy loaders fire off) assert getattr(Blog, 'posts').hasparent(p1, optimistic=True) assert getattr(Post, 'blog').hasparent(b, optimistic=True) # assert connections assert p1.blog is b assert p1 in b.posts # manual connections b2 = Blog() p2 = Post() b2.posts.append(p2) assert getattr(Blog, 'posts').hasparent(p2) assert getattr(Post, 'blog').hasparent(b2)
def get_extension(self): """Return an attribute extension to use with this backreference.""" return attributes.GenericBackrefExtension(self.key)
def __init__(self, key, _prop=None, **kwargs): self.key = key self.kwargs = kwargs self.prop = _prop self.extension = attributes.GenericBackrefExtension(self.key)
def testbackref(self): class Student(object): pass class Course(object): pass manager = attributes.AttributeManager() manager.register_attribute( Student, 'courses', uselist=True, extension=attributes.GenericBackrefExtension('students')) manager.register_attribute( Course, 'students', uselist=True, extension=attributes.GenericBackrefExtension('courses')) s = Student() c = Course() s.courses.append(c) print c.students print[s] self.assert_(c.students == [s]) s.courses.remove(c) self.assert_(c.students == []) (s1, s2, s3) = (Student(), Student(), Student()) c.students = [s1, s2, s3] self.assert_(s2.courses == [c]) self.assert_(s1.courses == [c]) print "--------------------------------" print s1 print s1.courses print c print c.students s1.courses.remove(c) self.assert_(c.students == [s2, s3]) class Post(object): pass class Blog(object): pass manager.register_attribute( Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True) manager.register_attribute( Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True) b = Blog() (p1, p2, p3) = (Post(), Post(), Post()) b.posts.append(p1) b.posts.append(p2) b.posts.append(p3) self.assert_(b.posts == [p1, p2, p3]) self.assert_(p2.blog is b) p3.blog = None self.assert_(b.posts == [p1, p2]) p4 = Post() p4.blog = b self.assert_(b.posts == [p1, p2, p4]) p4.blog = b p4.blog = b self.assert_(b.posts == [p1, p2, p4]) class Port(object): pass class Jack(object): pass manager.register_attribute( Port, 'jack', uselist=False, extension=attributes.GenericBackrefExtension('port')) manager.register_attribute( Jack, 'port', uselist=False, extension=attributes.GenericBackrefExtension('jack')) p = Port() j = Jack() p.jack = j self.assert_(j.port is p) self.assert_(p.jack is not None) j.port = None self.assert_(p.jack is None)