django-mptt получить потомков для списка узлов

Я пытаюсь получить все 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, чтобы вместо того, чтобы работать? Здесь можно сделать предположение, что у меня есть список ПК узла.

EDIT: если это может помочь - все мои "some_nodes" помещаются в тот же родительский каталог и имеют тот же "уровень" в дереве.

3 ответов


большое спасибо Крейг де Стигтер ответил на мой вопрос о django-mptt-dev group, если кому-то это нужно, я любезно перепечатываю его решение от 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>] 

более поздние версии mptt уже эта функция встроена в диспетчер объектов. Таким образом, решение этой проблемы выглядит следующим образом:

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

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;

секрет в родителе.лфт и родитель.номера rgt, все дети будут иметь узел.значение 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 для каждого родительского узла (подсказка, " и ".присоединяйтесь)

в качестве альтернативы вы можете использовать генератор диапазона для каждого родителя, чтобы получить все значения между значениями LFT и rgt каждого родителя включительно. Это позволяет вам использовать Giant в заявлении, а не много между статьи.

объединить или выше с RawQueryset и вы получите моделей.