django-mptt get_descendants для списка узлов - PullRequest
14 голосов
/ 20 апреля 2011

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

РЕДАКТИРОВАТЬ: Если это могло бы помочь - все мои "some_nodes" помещены в один и тот же родительский каталог и имеют одинаковый "уровень" в дереве.

Ответы [ 3 ]

9 голосов
/ 21 апреля 2011

Огромное спасибо Крэйгу де Стигтеру, который ответил на мой вопрос о группе django-mptt-dev, на случай, если кому-то это понадобитсяПример дерева узлов:

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>] 
9 голосов
/ 13 января 2016

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

Node.objects.get_queryset_descendants(my_queryset, include_self=False)
1 голос
/ 20 апреля 2011

Django mptt использует модифицированный метод обхода дерева предварительных заказов, как описано в документе Управление базами данных MySQL .

Он имеет следующий запрос для возврата всех узлов в дереве ниже aопределенный узел:

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, и вы получите модели обратно.

...