django-mptt: как успешно перемещать узлы - PullRequest
5 голосов
/ 14 июня 2010

Джанго-Мптт, похоже, полон решимости выкинуть меня из головы.Я пытаюсь сделать что-то относительно простое: я собираюсь удалить узел, и мне нужно сделать что-то разумное с дочерними узлами.А именно, я бы хотел переместить их на один уровень вверх, чтобы они стали дочерними элементами родительского элемента их текущего родителя.

То есть, если дерево выглядит так:

 Root
  |
Grandpa
  |
Father
|    |
C1   C2

Ясобираюсь удалить отца, и хотел бы, чтобы C1 и C2 были детьми дедушки.

Вот код, который я использую:

class Node(models.Model):
    first_name   = models.CharField(max_length=80, blank=True)
    parent       = models.ForeignKey('self', null=True, blank=True, related_name='children')

    def reparent_children(self, parent):
        print "Reparenting"
        for child in self.get_children():
            print "Working on", child.first_name, "to parent", parent.email
            parent = Node.objects.get(id=parent.id)
            child.move_to(parent, 'last-child')
            child.save()

Поэтому я бы позвонил:

father.reparent_children(grandpa)
father.parent = None
father.save()

Это работает - почти.Дети сообщают о своих родителях как о дедушке:

c1.parent == grandpa  # True

Дедушка считает С1 и С2 среди своих детей

c1 in grandpa.children.all()   # True

Однако Рут отрицает этих детей.

c1.get_root() == father  # c1's root is father, instead of Root

c1 in root.get_descendants()  # False

Как заставить детей двигаться, а их корень не испортиться?

Ответы [ 2 ]

6 голосов
/ 15 июня 2010

Внутренние значения lft и rght изменятся при первом сохранении дочернего элемента (т. Е. Последняя строка вашего метода reparent_children). save() не обновляет экземпляры, которые у вас могут лежать. Я думаю безопасный способ сделать это - каждый раз повторять их из базы данных, например:

def reparent_children(self, parent):
    print "Reparenting"
    for child in self.get_children():
        print "Working on", child.first_name, "to parent", parent.email
        parent = Node.objects.get(id=parent.id)
        current_child = Node.objects.get(id = child.id)
        current_child.move_to(parent, 'last-child')
        current_child.save()

Некоторое время назад у меня было похожих проблем , и этот подход решил мою проблему.

1 голос
/ 06 октября 2017

Эта библиотека действительно смутила меня в последние несколько дней - похоже, что move_to действительно не выполняет то, что я хочу, и мое дерево перестает синхронизироваться.Я нашел решение, в котором я увереннее, за счет скорости и нетрадиционности.

Оно вращается вокруг метода менеджера partial_rebuild здесь .

def delete_node(self):
    if not self.parent:
        print("Should not delete root node, confusing behavior follows")
        return
    tree_id = self.tree_id
    parent = self.parent

    for child in self.get_children():
        child.parent = parent
        child.save()

    self.delete()
    Node.objects.partial_rebuild(tree_id)

Вы можете заменить child.parent = parent на child.move_node (parent), если хотите

...