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 [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
-~----------~----~----~----~------~----~------~--~---
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