I should note that the relationship you are actually trying to set up  
includes a circular relationship between two individual rows.   by  
default this is impossible to accomplish with only INSERT statements  
and not violate foreign key constraints.  to break this circular  
relation you have to also add a special flag "post_update=True" to  
one side of the circle, which will add an extra UPDATE statement to  
the commit.

n_mapper = mapper(Node, node_table, properties={
     'parent': relation(
         Node,
         lazy=True,
         primaryjoin=node_table.c.parent_id==node_table.c.id,
         foreignkey=node_table.c.id,
         uselist=False
     ),
     'children': relation(
         Node,
         primaryjoin=node_table.c.id==node_table.c.parent_id,
         lazy=True,
         cascade="all"
     ),
     'previous_sibling': relation(
         Node,
         primaryjoin=node_table.c.prev_sibling_id==node_table.c.id,
         foreignkey=node_table.c.id,
         lazy=True,
         uselist=False
     ),
     'next_sibling': relation(
         Node,
         primaryjoin=node_table.c.next_sibling_id==node_table.c.id,
         foreignkey=node_table.c.id,
         lazy=True,
         uselist=False,
         post_update=True,
     )
})


produces the statements:

[2006-09-05 14:11:47,504] [engine]: BEGIN
[2006-09-05 14:11:47,510] [engine]: INSERT INTO node (path,  
parent_id, prev_sibling_id, next_sibling_id) VALUES (?, ?, ?, ?)
[2006-09-05 14:11:47,511] [engine]: ['root', None, None, None]
[2006-09-05 14:11:47,516] [engine]: INSERT INTO node (path,  
parent_id, prev_sibling_id, next_sibling_id) VALUES (?, ?, ?, ?)
[2006-09-05 14:11:47,516] [engine]: ['first', 1, None, None]
[2006-09-05 14:11:47,521] [engine]: INSERT INTO node (path,  
parent_id, prev_sibling_id, next_sibling_id) VALUES (?, ?, ?, ?)
[2006-09-05 14:11:47,522] [engine]: ['second', 1, 2, None]
[2006-09-05 14:11:47,527] [engine]: UPDATE node SET path=? WHERE  
node.id = ?
[2006-09-05 14:11:47,527] [engine]: ['root', 1]
[2006-09-05 14:11:47,531] [engine]: UPDATE node SET path=?,  
parent_id=?, next_sibling_id=? WHERE node.id = ?
[2006-09-05 14:11:47,532] [engine]: ['first', 1, 3, 2]
[2006-09-05 14:11:47,536] [engine]: UPDATE node SET path=?,  
parent_id=?, prev_sibling_id=? WHERE node.id = ?
[2006-09-05 14:11:47,537] [engine]: ['second', 1, 2, 3]
[2006-09-05 14:11:47,539] [engine]: COMMIT



On Sep 5, 2006, at 10:12 AM, Nick Joyce wrote:

> I am attempting to extend the self referential example in the docs
> http://www.sqlalchemy.org/docs/index.myt? 
> paged=no#advdatamapping_circular
> by adding properties 'prev_sibling' and 'next_sibling'. (See attached
> script)
>
> When run, the following exception is raised:
>
> Traceback (most recent call last):
>   File "tree.py", line 79, in ?
>     session.flush()
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/session.py", line  
> 234,
> in flush
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/unitofwork.py", line
> 197, in flush
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/unitofwork.py", line
> 359, in execute
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/unitofwork.py", line
> 407, in _sort_dependencies
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/unitofwork.py", line
> 395, in sort_hier
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/unitofwork.py", line
> 800, in _sort_circular_dependencies
>   File "build/bdist.linux-i686/egg/sqlalchemy/orm/topological.py",  
> line
> 139, in sort
> sqlalchemy.exceptions.FlushError: Circular dependency detected
> {<Node(path=first)>  (idself=1079711436): {<Node(path=second)>
> (idself=1079711468): True, <Node(path=root)>  (idself=1079711404):
> True}, <Node(path=root)>  (idself=1079711404): {<Node(path=second)>
> (idself=1079711468): True, <Node(path=first)>  (idself=1079711436):
> True}, <Node(path=second)>  (idself=1079711468): {<Node(path=first)>
> (idself=1079711436): True, <Node(path=root)>  (idself=1079711404):  
> True}}[]
>
> I am doing something wrong? If so can someone point me in the right
> direction ...
>
> Thanks,
>
> Nick
> import sqlalchemy.mods.threadlocal
> from sqlalchemy import *
>
> engine = create_engine('sqlite:///:memory:', echo=True);
> metadata = BoundMetaData(engine)
>
> node_table = Table('node', metadata,
>     Column('id', Integer, primary_key=True),
>     Column('path', String(50), nullable=False),
>     Column('parent_id', Integer, ForeignKey('node.id'),  
> nullable=True),
>     Column('prev_sibling_id', Integer, ForeignKey('node.id'),  
> nullable=True),
>     Column('next_sibling_id', Integer, ForeignKey('node.id'),  
> nullable=True)
> )
>
> class Node(object):
>     def __init__(self, path=''):
>         self.path = path
>
>     def has_child_nodes(self):
>         return len(self.children) == 0
>
>     def append_child(self, child):
>         try:
>             lc = self.children[len(self.children) - 1]
>         except IndexError, e:
>             lc = None
>
>         self.children.append(child)
>
>         child.parent = self
>
>         if lc is not None:
>             lc.next_sibling = child
>             child.previous_sibling = lc
>
>     def __repr__(self):
>         return '<Node(path=%s)>' % self.path
>
> n_mapper = mapper(Node, node_table, properties={
>     'parent': relation(
>         Node,
>         lazy=True,
>         primaryjoin=node_table.c.parent_id==node_table.c.id,
>         uselist=False
>     ),
>     'children': relation(
>         Node,
>         primaryjoin=node_table.c.id==node_table.c.parent_id,
>         lazy=True,
>         cascade="all, delete-orphan"
>     ),
>     'previous_sibling': relation(
>         Node,
>         primaryjoin=node_table.c.prev_sibling_id==node_table.c.id,
>         lazy=True,
>         uselist=False
>     ),
>     'next_sibling': relation(
>         Node,
>         primaryjoin=node_table.c.next_sibling_id==node_table.c.id,
>         lazy=True,
>         uselist=False
>     )
> })
>
> if __name__ == '__main__':
>     node_table.create()
>
>     root = Node('root')
>     first = Node('first')
>     second = Node('second')
>
>     root.append_child(first)
>     root.append_child(second)
>
>     print first==second.previous_sibling
>
>     session = objectstore.session
>
>     session.flush()
> ---------------------------------------------------------------------- 
> ---
> Using Tomcat but need to do more? Need to support web services,  
> security?
> Get stuff done quickly with pre-integrated technology to make your  
> job easier
> Download IBM WebSphere Application Server v.1.0.1 based on Apache  
> Geronimo
> http://sel.as-us.falkag.net/sel? 
> cmd=lnk&kid=120709&bid=263057&dat=121642______________________________ 
> _________________
> Sqlalchemy-users mailing list
> Sqlalchemy-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users

Reply via email to