Мне пришлось один раз написать похожий алгоритм. У меня было представление, отображающее дерево MPTT, это было очень большое дерево, поэтому я не мог загрузить все его данные в шаблон HTML. Поэтому я отображал только корневые узлы при начальной загрузке и использовал Ajax для загрузки других узлов.
Это работало хорошо, пока мой начальник не попросил меня реализовать опцию «поиск». При поиске нужно было просмотреть все узлы и взорвать дерево, если оно нашло совпадение. Мне потребовалось некоторое время, чтобы понять это, но я наконец понял. Вот решение, которое придумало:
from django.db.models import Q
def get_parents(self, qs):
tree_list = {}
query = Q()
for node in qs:
if node.tree_id not in tree_list:
tree_list[node.tree_id] = []
parent = node.parent.pk if node.parent is not None else None,
if parent not in tree_list[node.tree_id]:
tree_list[node.tree_id].append(parent)
query |= Q(lft__lt=node.lft, rght__gt=node.rght, tree_id=node.tree_id)
return YourModel.objects.filter(query)
Для запуска требуется только два запроса: начальный qs
передан в качестве аргумента и последний набор запросов, возвращенный функцией. tree_list
- это словарь, в котором хранятся узлы, которые уже были добавлены в набор запросов, это оптимизация, и алгоритм не нужен для работы. Но так как я работал с относительно большим деревом, мне пришлось включить его.
Полагаю, вы могли бы превратить этот метод в менеджера и сделать его более общим, то есть заставить его работать для любой модели MPTT, а не только YourModel