The question was based on a misconception on my part (in a visual representation of a tree, while dragging a node you drag the whole subtree with it, so you can't drop a node in it's own subtree).
Sorry about that ... PS: Checked that when updating the children (via append) the exception occurs right away (is there a flush happening in the background?), while when updating the parent, the exception happens during the flush afterwards. On Apr 11, 5:41 pm, Michael Bayer <[email protected]> wrote: > On Apr 11, 2012, at 3:34 AM, lars van gemerden wrote: > > > > > > > > > > > Hi all, > > > I am looking for a way to append a child to a tree like structure. I > > am using adjacency to represent the tree. > > > Let's say I have a relationship configured with: > > > children = relationship(TreeNode, > > primaryjoin = "TreeNode.id == > > TreeNode.parent_id", > > backref = backref( "parent", > > remote_side=[TreeNode.id]), > > cascade = "all, delete-orphan", > > use_list = True) > > > and I do: > > > t1 = TreeNode() > > t2 = TreeNode(parent = t1) > > t3 = TreeNode(parent = t2) > > > then i can set: > > > t1.parent = t3, > > > without problem, but: > > > t3.children.append(t1) > > > gives a CircularDependencyError, while i would like this to give the > > same result as t1.parent = t3, perhaps by altering the behaviour of > > Treenode.children.append. > > > Am I missing something? > > Is there some way to arrange for this? > > t1.parent = t3 means you aren't persisting a tree anymore - it's no longer a > hierarchy, since t3 is a descendant of t1 already via t2. It's a cycle. > > The exception on the "children" side is probably because mutating "children" > has the effect of both t3 and t1 being considered in the flush (due to > t3.children as well as t1.parent_id changing), whereas t1.parent = t3 does > not actually consider "t3" to modified. You'd still get a cycle if you > created everything via "x.parent=y" at once (below I just put it into the > adjacency_list.py example - boom): > > node = TreeNode('rootnode') > n1 = TreeNode('node1', parent=node) > n2 = TreeNode('node2', parent=n1) > node.parent = n2 > session.add(node) > session.flush() > > sqlalchemy.exc.CircularDependencyError: Circular dependency detected. Cycles: > ... > > though I wasn't able to reproduce the behavior being different by mutating > children vs. the parent....I'm sure with more digging I could figure that > out. But in any case, you aren't safe from cycles if you're building them, > the usual way to insert rows with cycles to themselves is to use the > post_update feature described > athttp://docs.sqlalchemy.org/en/latest/orm/relationships.html#rows-that.... > You probably need to put it on both sides in this case as the unit of work > code will consider one or both of the "children" or "parent" relationships in > a particular flush depending on where it sees changes. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
