在数据库中,我有一个表,其中有一个外键(深度是多树中的深度级别):
id name depth path parent_id
1 A 0 1 Null
2 A1 1 1,2 1
3 A2 1 1,3 1
4 A11 2 1,2,4 2
5 A111 3 1,2,4,5 4
6 B 0 1 Null
7 C 0 1 Null
我通过查询得到数据库中的所有类别。深度可以是无限的。
当我从数据库中获取查询时,我将根据每个记录和对象进行查询。
我需要将每个子对象附加到父对象,作为list属性中的元素:
for item in items:
create object A
has a A a parent; no - do nothing
create object A1
has object A1 a parent; yes A.list[0] = A1
create object A2
has object A2 a parent; yes A.list[1] = A2
创建列表后,我需要找回:
for item in items:
item.name
has item.name A children - yes
-> for itemAkid in itemAchildren:
itemAkid.name
答案 0 :(得分:2)
我将假设您的查询为完整的子树生成行。
如果您对查询进行 sort 排序时,可以按深度颠倒的顺序创建关系,并将为先前深度创建的节点作为字典从父id到object保留下来。 / p>
class TreeNode:
def __init__(id, name, children=()):
self.id = id
self.name = name
self.children = children
query = '''\
SELECT
id, name, parent_id
FROM <TABLENAME>
WHERE <CRITERIA>
ORDER_BY depth DESC
'''
cursor.execute(query, (parameters, ...))
roots = []
parentless = {}
for id, name, parent_id in cursor:
children = tuple(parentless.pop(id, ()))
object = TreeNode(id, name, children)
if parent_id is not None:
parentless.setdefault(parent_id, []).append(object)
else:
roots.append(object)
如果您使用的是产生映射模型类实例的ORM,则只需用游标上的循环替换为ORM结果上的循环(仍然使用相同的顺序),删除object = TreeNode(...)
行,并从ORM为您生成的对象中检索id
和parent_id
的值。在每个对象上将子级设置为新列表或元组属性。
因为位于最高depth
值的叶节点会先被处理,所以在处理其父节点时,所有子节点都已被处理并添加到parentless[id]
列表中。如果当前节点有任何子节点,则parentless.get(id, ())
将产生它们的序列。
但是,如果您使用的是现有的ORM,请不要重新发明这个轮子。也不要使用邻接表,对于分层数据,有更好的SQL模型,例如closure table或Modified Preorder Tree Traversal。对于Django,有a series of options available,特别是django-closuretree,django-mptt或django-treebeard。后者支持邻接表表结构,应该可以将现有模型直接移到it's support for adjacency lists。