mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-17 06:07:27 -04:00
update example to work with new collections class
This commit is contained in:
@@ -3,6 +3,7 @@ introduces a new selection method which selects an entire tree of nodes at once,
|
||||
advantage of a custom MapperExtension to assemble incoming nodes into their correct structure."""
|
||||
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import *
|
||||
from sqlalchemy.util import OrderedDict
|
||||
|
||||
engine = create_engine('sqlite:///:memory:', echo=True)
|
||||
@@ -30,25 +31,19 @@ treedata = Table(
|
||||
|
||||
class NodeList(OrderedDict):
|
||||
"""subclasses OrderedDict to allow usage as a list-based property."""
|
||||
|
||||
def append(self, node):
|
||||
self[node.name] = node
|
||||
def __iter__(self):
|
||||
return iter(self.values())
|
||||
|
||||
|
||||
def remove(self, node):
|
||||
del self[node.name]
|
||||
|
||||
class TreeNode(object):
|
||||
"""a hierarchical Tree class, which adds the concept of a "root node". The root is
|
||||
the topmost node in a tree, or in other words a node whose parent ID is NULL.
|
||||
All child nodes that are decendents of a particular root, as well as a root node itself,
|
||||
reference this root node.
|
||||
this is useful as a way to identify all nodes in a tree as belonging to a single
|
||||
identifiable root. Any node can return its root node and therefore the "tree" that it
|
||||
belongs to, and entire trees can be selected from the database in one query, by
|
||||
identifying their common root ID."""
|
||||
reference this root node. """
|
||||
|
||||
def __init__(self, name):
|
||||
"""for data integrity, a TreeNode requires its name to be passed as a parameter
|
||||
to its constructor, so there is no chance of a TreeNode that doesnt have a name."""
|
||||
self.name = name
|
||||
self.children = NodeList()
|
||||
self.root = self
|
||||
@@ -57,35 +52,42 @@ class TreeNode(object):
|
||||
self.data =None
|
||||
self.parent_id = None
|
||||
self.root_id=None
|
||||
|
||||
def _set_root(self, root):
|
||||
self.root = root
|
||||
for c in self.children:
|
||||
c._set_root(root)
|
||||
|
||||
def append(self, node):
|
||||
if isinstance(node, str):
|
||||
node = TreeNode(node)
|
||||
node.parent = self
|
||||
node._set_root(self.root)
|
||||
self.children.append(node)
|
||||
|
||||
def __repr__(self):
|
||||
return self._getstring(0, False)
|
||||
|
||||
def __str__(self):
|
||||
return self._getstring(0, False)
|
||||
|
||||
def _getstring(self, level, expand = False):
|
||||
s = (' ' * level) + "%s (%s,%s,%s, %d): %s" % (self.name, self.id,self.parent_id,self.root_id, id(self), repr(self.data)) + '\n'
|
||||
if expand:
|
||||
s += ''.join([n._getstring(level+1, True) for n in self.children.values()])
|
||||
return s
|
||||
|
||||
def print_nodes(self):
|
||||
return self._getstring(0, True)
|
||||
|
||||
class TreeLoader(MapperExtension):
|
||||
"""an extension that will plug-in additional functionality to the Mapper."""
|
||||
|
||||
def after_insert(self, mapper, connection, instance):
|
||||
"""runs after the insert of a new TreeNode row. The primary key of the row is not determined
|
||||
until the insert is complete, since most DB's use autoincrementing columns. If this node is
|
||||
the root node, we will take the new primary key and update it as the value of the node's
|
||||
"root ID" as well, since its root node is itself."""
|
||||
|
||||
if instance.root is instance:
|
||||
connection.execute(mapper.mapped_table.update(TreeNode.c.id==instance.id, values=dict(root_node_id=instance.id)))
|
||||
instance.root_id = instance.id
|
||||
@@ -96,10 +98,11 @@ class TreeLoader(MapperExtension):
|
||||
append root nodes to the result list, and will attach child nodes to their appropriate parent
|
||||
node as they arrive from the select results. This allows a SELECT statement which returns
|
||||
both root and child nodes in one query to return a list of "roots"."""
|
||||
|
||||
if instance.parent_id is None:
|
||||
result.append(instance)
|
||||
else:
|
||||
if isnew or populate_existing:
|
||||
if isnew or selectcontext.populate_existing:
|
||||
parentnode = selectcontext.identity_map[mapper.identity_key(instance.parent_id)]
|
||||
parentnode.children.append_without_event(instance)
|
||||
# fire off lazy loader before the instance is part of the session
|
||||
|
||||
Reference in New Issue
Block a user