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.

Reply via email to