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 и вы получите моделей.