Django-MPTT полностью глючит или я делаю это неправильно? - PullRequest
7 голосов
/ 28 января 2010

Я пытаюсь использовать django-mptt без особой удачи. Это с Python2.5, windows, sqlite3, Django 1.2pre, django-mptt последней из svn.

Код:

Модель:

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

    def __unicode__(self):
        return self.name

mptt.register(Node)

установка:

nodes = []
for i in range(15):
    n = Node(name='node'+str(i))
    n.save()
    nodes.append(n)

nodes[0].move_to(None)
nodes[0].save()
for n in range(1,15):
    nodes[n].move_to(nodes[(n-1)/2],'last-child')
    nodes[n].save()

Это должно создать дерево с одним корнем и двумя дочерними элементами, свисающими с каждого неконечного узла.

Теперь начинается самое интересное:

>>> nodes[0].children.all()
[<Node: node1>, <Node: node2>]
>>> nodes[0].get_descendants()
[]

>>> nodes[0].get_descendants(True)
[<Node: node0>, <Node: node2>]


>>> for n in nodes:
...     print n, n.get_ancestors()
...
node0 []
node1 [<Node: node0>]
node2 [<Node: node0>]
node3 [<Node: node0>, <Node: node2>]
node4 [<Node: node0>, <Node: node2>]
node5 [<Node: node0>, <Node: node2>]
node6 [<Node: node0>, <Node: node2>]
node7 [<Node: node0>, <Node: node2>, <Node: node6>]
node8 [<Node: node0>, <Node: node2>, <Node: node6>]
node9 [<Node: node0>, <Node: node2>, <Node: node6>]
node10 [<Node: node0>, <Node: node2>, <Node: node6>]
node11 [<Node: node0>, <Node: node2>, <Node: node6>]
node12 [<Node: node0>, <Node: node2>, <Node: node6>]
node13 [<Node: node0>, <Node: node2>, <Node: node6>]
node14 [<Node: node0>, <Node: node2>, <Node: node6>]

Почему так много предков не правы? Например, узел 10 должен иметь предков, (0,1,10)

Я что-то не так делаю или в django-mptt есть ошибки?

1 Ответ

14 голосов
/ 28 января 2010

Я бы не сказал, что он глючит, но есть недоработка, о которой вам нужно знать.

Когда вы добавляете дочерний элемент к родительскому элементу, атрибуты дочернего дерева корректно обновляются со значениями lft, rght и level, характерными для MPTT.

Однако django-mptt не обновляет версию родительского элемента, который у вас есть. Версия в базе данных обновлена, но копия в локальной переменной отсутствует (помните, что экземпляры модели Django не имеют идентификатора, поэтому не обновляйте, когда база данных или другие экземпляры, ссылающиеся на ту же строку базы данных, обновляются ).

Это означает, что следующий дочерний элемент, который вы добавляете в родительский объект, получит неправильные левое и правое значения, и если впоследствии вы сохраните родительский объект, у него тоже будут неправильные значения.

Решение заключается в перезагрузке родительского элемента из базы данных при каждом добавлении дочернего элемента:

for n in range(1,15):
    parent_pos = (n-1)/2
    parent = nodes[parent_pos]
    nodes[n].move_to(parent, 'last-child')
    nodes[n].save()
    nodes[parent_pos] = Node.objects.get(pk=parent.pk)
...