On Oct 22, 2008, at 6:27 PM, Wojciech Malinowski wrote:

>
> Hi,
>
> I've done a mapping of a (not typical) tree structure. It's not
> completed yet, but the work in progress can be seen here:
> http://wojciechmalinowski.com/tree.zip
>
> The idea was to make the model as simple as possible and do all the  
> work
> in the mapper. The model should have only a few properties that can  
> also
> be mapped by another tree structure (i.e. nested sets). I also  
> wanted to
> make it as generic as possible so I can use it for different classes  
> in
> my projects.
>
> I have a few questions now:
> 1) How to use SQLAlchemy extensions to create the special parent
> property that is now created using monkey-patching of a class? Is it
> possible?

well you are issuing a query to get at _parent so theres no "smooth"  
way to accomplish that.   You'd have to bring "_parent" in as a  
relation.   I redid the "persistence" side of your example, its  
attached.   This method is more in line with the "SQLAlchemy way" in  
that you define a complete structure, and all persistence-related SQL  
is issued during the flush().

> 2) How to use the technique shown in
> examples/derived_attributes/attributes.py to be able to filter other
> queries by node.all_children_with_self etc.

the derived attributes example is a little clever for me, we have a  
more old fashioned way of creating custom comparisons which is the  
comparable_property().   Those relations() overall are nice but i  
might want to put viewonly=True on them, and possibly even an  
immutable collection class, since they represent views which should  
not be written to.


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
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
-~----------~----~----~----~------~----~------~--~---

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.associationproxy import association_proxy


def map_model(Node, node_table, tree_table):
    class SetupDepth(MapperExtension):
        def before_insert(self, mapper, connection, instance):
            parent = instance.parent
            if parent and parent.assoc:
                instance.depth = parent.assoc.depth + 1
            else:
                instance.depth = 0
            
    class TreeAssoc(object):
        def __init__(self, node, parent):
            self.node = node
            self.parent = parent
            self.depth = 0
            
    mapper(TreeAssoc, tree_table, properties={
        'node':relation(Node, backref=backref('assoc', uselist=False), primaryjoin=node_table.c.id==tree_table.c.child_id)
    }, extension=SetupDepth())
    
    mapper(Node, node_table, properties={
        '_children':relation(TreeAssoc, backref='parent', primaryjoin=node_table.c.id==tree_table.c.parent_id, collection_class=set)
    })

    Node.children = association_proxy('_children', 'node', creator=lambda n: TreeAssoc(n, None))
    Node.parent = association_proxy('assoc', 'parent', creator=lambda n: TreeAssoc(None, n))
    
    def depth(self):
        if self.assoc:
            return self.assoc.depth
        else:
            return 0
    Node.depth = property(depth)

if __name__ == '__main__':
    engine = create_engine('sqlite:///:memory:', echo=True)
    metadata = MetaData()
    Session = sessionmaker(bind=engine)()


    example_node_table = Table('nodes', metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(50)),
    )

    example_tree_table = Table('tree', metadata,
        Column('id', Integer, primary_key=True),
        Column('parent_id', Integer, ForeignKey('nodes.id')),
        Column('child_id', Integer, ForeignKey('nodes.id')),
        Column('depth', Integer),
    )
    metadata.create_all(engine)
    
    class Node(object):

        def __init__(self, name, parent = None):
            self.name = name
            self.parent = parent

        def __repr__(self):
            return self.name

    map_model(Node, example_node_table, example_tree_table)
    n1 = Node('n1')
    n2 = Node('n2', parent=n1)
    n3 = Node('n3', parent=n1)
    n4 = Node('n4', parent=n2)

    Session.add(n1)
    Session.commit()

    assert n1.depth == 0
    assert n2.depth == 1
    assert n4.depth == 2

    assert n1.children == set([n2, n3])
    assert n4.parent is n2






Reply via email to