繁体   English   中英

django-mptt get_descendants获取节点列表

[英]django-mptt get_descendants for a list of nodes

我试图让所有descendants(include_self=True)不是为一个节点,而是为了一个节点列表(一个QuerySet)。 这应该是一个SQL查询。

示例(实际上不起作用:)

some_nodes = Node.objects.filter( ...some_condition... ) 
some_nodes.get_descendants(include_self=True) #hopefully I would like 
to have all possible Nodes starting from every node of "some_nodes" 

我现在唯一的想法是遍历some_nodes并为每个节点运行get_descendants() - 但这是一个糟糕的解决方案(大量的SQL查询)。

如果没有干净的方法通过Django ORM这样做,你可以提供一个自定义SQL来运行吗? 在这里你可以假设我有一个Node的pk列表。

编辑:如果这可以帮助 - 我的所有“some_nodes”都放在同一个父目录中,并在树中具有相同的“级别”。

更高版本的mptt已经在对象管理器中内置了此功能 所以解决方法如下:

Node.objects.get_queryset_descendants(my_queryset, include_self=False)

非常感谢Craig de Stigter回答了关于django-mptt-dev小组的问题,万一有人需要它我很乐意从http://groups.google.com/group/django-mptt-dev/browse_thread/thread重新发布他的解决方案/ 637c8b2fe816304d

   from django.db.models import Q 
   import operator 
   def get_queryset_descendants(nodes, include_self=False): 
       if not nodes: 
           return Node.tree.none() 
       filters = [] 
       for n in nodes: 
           lft, rght = n.lft, n.rght 
           if include_self: 
               lft -=1 
               rght += 1 
           filters.append(Q(tree_id=n.tree_id, lft__gt=lft, rght__lt=rght)) 
       q = reduce(operator.or_, filters) 
       return Node.tree.filter(q) 

示例节点树:

T1 
---T1.1 
---T1.2 
T2 
T3 
---T3.3 
------T3.3.3 

用法示例:

   >> some_nodes = [<Node: T1>, <Node: T2>, <Node: T3>]  # QureySet
   >> print get_queryset_descendants(some_nodes)
   [<Node: T1.1>, <Node: T1.2>, <Node: T3.3>, <Node: T3.3.3>] 
   >> print get_queryset_descendants(some_nodes, include_self=True)
   [<Node: T1>, <Node: T1.1>, <Node: T1.2>, <Node: T2>, <Node: T3>, <Node: T3.3>, <Node: T3.3.3>] 

Django mptt使用MySQL Managing Hierarchical Data文档中描述的修改后的预订树遍历方法。

它具有以下查询,用于返回特定节点下的树中的所有节点:

SELECT node.name
FROM nested_category AS node, nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
    AND parent.name = 'ELECTRONICS'
ORDER BY node.lft;

秘密是parent.lft和parent.rgt数字,所有子节点之间都有一个node.lft值。

显然,该示例预先假定只有一个父项,并且您需要使用父名称来查找父项。 由于您已拥有父节点数据,因此您可以执行以下操作:

SELECT node.id
FROM node_table
WHERE node.lft BETWEEN parent[0].lft AND parent[0].rgt
    OR node.lft BETWEEN parent[1].lft AND parent[1].rgt

我将把它作为练习,让你知道如何为每个父节点生成一个单独的BETWEEN子句(提示,“AND”.join)

或者,您可以在每个父级上使用范围生成器来获取每个父级的lft和rgt值之间的所有值。 然后,您可以使用巨大的IN语句而不是许多BETWEEN子句。

将上述任一项与RawQueryset相结合,您将获得模型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM