2011-04-19 161 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