15

descendants(include_self=True)1つのノードではなく、ノードのリスト(QuerySet)のすべてを取得しようとしています。これは1つの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を提供できますか?ここで、私がノードのpkのリストを持っていると仮定できます。

編集:それが役立つ場合-私の「some_nodes」はすべて同じ親ディレクトリに配置され、ツリー内で同じ「レベル」を持ちます。

4

3 に答える 3

11

それ以降のバージョンのmpttには、すでにこの関数がオブジェクトマネージャに組み込まれています。したがって、これに対する解決策は次のとおりです。

Node.objects.get_queryset_descendants(my_queryset, include_self=False)
于 2016-01-13T18:52:36.970 に答える
10

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>] 
于 2011-04-21T07:07:31.927 に答える
1

Django mpttは、MySQLの階層データの管理ドキュメントで説明されているように、変更された事前注文ツリートラバーサルメソッドを使用します。

特定のノードの下にあるツリー内のすべてのノードを返すための次のクエリがあります。

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の番号であり、すべての子は2つの間にnode.lft値を持ちます。

明らかに、この例では親が1つだけであり、親を見つけるには親名を使用する必要があることを前提としています。親ノードデータがすでにあるので、次のようなことができます。

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値の間のすべての値を取得することもできます。これにより、多くのBETWEEN句ではなく、巨大なINステートメントを使用できるようになります。

上記のいずれかをRawQuerysetと組み合わせると、モデルが元に戻ります。

于 2011-04-20T09:10:59.187 に答える