2011-04-19 160 views
12

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

实例(我现在所拥有的,实际上是不工作:)

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来运行吗?在这里,您可以假设我有一个 节点的pk列表。

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

回答

9

大感谢Craig德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>] 
+0

这太棒了!我认为它应该'Node.objects'而不是'Node.tree',尽管 – Cory 2016-01-12 21:12:58

+0

实际上这是现在内置到管理器中的。看到我的替代答案。 – Cory 2016-01-13 18:53:36

1

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 

我会离开它作为一个练习你为如何生成一个单独的条款之间的每个父节点(提示“ AND“.join)

或者,您可以在每个父代中使用范围生成器来获取每个父代的lft和rgt值(包含)之间的所有值。然后,您可以使用巨大的IN语句而不是大量的BETWEEN子句。

将上面的任意一个与RawQueryset结合起来,您将得到模型。

+0

嗯,我刚刚意识到我可能会使用这个自己提取父母的大量树木,这也是目前由于大量缓慢的相关的问题到大量的生成的查询调用 – Chris 2011-04-20 09:12:25

+0

这不是非常精确的答案,我问:没有tree_id在这个声明!因此,选择lft和right之间的节点的想法是正确的。 – thedk 2011-04-21 06:58:48