Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-mptt completely buggy or am I doing it wrong?

I'm attempting to use django-mptt with very little luck. This is with Python2.5, windows, sqlite3, Django 1.2pre , django-mptt latest from svn.

The code:

model:

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)

setup:

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()

This should create a tree with one root and two children hanging off of each non-leaf node.

Now the fun begins:

>>> 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>]

Why are so many of the ancestors wrong? For example, node 10 should have ancestors, (0,1,10)

Am I doing something wrong or are there bugs in django-mptt?

like image 372
Parand Avatar asked Jan 28 '10 07:01

Parand


1 Answers

I wouldn't say it's buggy, but there is a gotcha that you need to be aware of.

When you add a child to a parent, the child's tree attributes are correctly updated with the MPTT-specific lft, rght and level values.

However, django-mptt does not update the version of the parent that you are holding. The version in the database is updated, but the copy in your local variable is not (remember that Django model instances don't have identity, so don't get updated when the database, or other instances referring to the same database row, update).

This means that the next child you add to the parent object will get the wrong left and right values, and if you do subsequently save the parent that too will have the wrong values.

The solution is to reload the parent from the database each time you add a child:

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)
like image 126
Daniel Roseman Avatar answered Sep 29 '22 21:09

Daniel Roseman