mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-15 05:07:16 -04:00
insure that "parent" pointers are set up on objects that were lazily loaded
This commit is contained in:
@@ -167,6 +167,7 @@ relationships to an inheriting mapper (which is also self-referential)
|
||||
- added 'checkfirst' argument to table.create()/table.drop(), as
|
||||
well as table.exists() [ticket:234]
|
||||
- some other ongoing fixes to inheritance [ticket:245]
|
||||
- attribute/backref/orphan/history-tracking tweaks as usual...
|
||||
|
||||
0.2.5
|
||||
- fixed endless loop bug in select_by(), if the traversal hit
|
||||
|
||||
@@ -134,7 +134,10 @@ class InstrumentedAttribute(object):
|
||||
if callable_ is not None:
|
||||
if passive:
|
||||
return InstrumentedAttribute.PASSIVE_NORESULT
|
||||
l = InstrumentedList(self, obj, self._adapt_list(callable_()), init=False)
|
||||
values = callable_()
|
||||
l = InstrumentedList(self, obj, self._adapt_list(values), init=False)
|
||||
if self.trackparent and values is not None:
|
||||
[self.sethasparent(v, True) for v in values if v is not None]
|
||||
# if a callable was executed, then its part of the "committed state"
|
||||
# if any, so commit the newly loaded data
|
||||
orig = state.get('original', None)
|
||||
@@ -152,7 +155,10 @@ class InstrumentedAttribute(object):
|
||||
if callable_ is not None:
|
||||
if passive:
|
||||
return InstrumentedAttribute.PASSIVE_NORESULT
|
||||
obj.__dict__[self.key] = callable_()
|
||||
value = callable_()
|
||||
obj.__dict__[self.key] = value
|
||||
if self.trackparent and value is not None:
|
||||
self.sethasparent(value, True)
|
||||
# if a callable was executed, then its part of the "committed state"
|
||||
# if any, so commit the newly loaded data
|
||||
orig = state.get('original', None)
|
||||
|
||||
+28
-2
@@ -131,8 +131,8 @@ class AttributesTest(PersistTest):
|
||||
class Post(object):pass
|
||||
class Blog(object):pass
|
||||
|
||||
manager.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'))
|
||||
manager.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'))
|
||||
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)
|
||||
@@ -165,6 +165,32 @@ class AttributesTest(PersistTest):
|
||||
j.port = None
|
||||
self.assert_(p.jack is None)
|
||||
|
||||
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)
|
||||
|
||||
# assert connections
|
||||
assert p1.blog is b
|
||||
assert p1 in b.posts
|
||||
|
||||
# no orphans
|
||||
assert getattr(Blog, 'posts').hasparent(p1)
|
||||
assert getattr(Post, 'blog').hasparent(b)
|
||||
|
||||
|
||||
def testinheritance(self):
|
||||
"""tests that attributes are polymorphic"""
|
||||
class Foo(object):pass
|
||||
|
||||
Reference in New Issue
Block a user