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