2π
β
For future reference..
objects.rebuild() is only needed in some special cases. Normally mptt sets the left and right values of your nodes correctly just by setting the parent id of your node. This is also mentioned in the docs
I experienced an issue with not correctly set left, right values because I saved the new node, !before! I reset the position values of the other, already existing siblings. When inserting new nodes for a tree with the meta attribute order_insertion_by
set, one has to first reset the order_insertion_by value for all siblings, and after that, save the new node. This way mptt is able to recalculate correctly the left right values.
See my (simplified) example below:
models.py
class Node(MPTTModel):
"""
Representation of a single node
"""
name = models.CharField(max_length=200)
parent = TreeForeignKey('self', null=True, blank=True, related_name='%(app_label)s_%(class)s_children')
position = models.PositiveIntegerField(max_length=10) #for nodes on the same hierarchy level we have to define the position in which they are displayed
class MPTTMeta:
order_insertion_by = ['position']
views.py
new_node = Node(name="new node", parent=parent_node, position=1)
update_node_positions(new_node, 1) #routine to update the node positions
new_node.save()
update_node_positions
def update_node_positions(node, mode):
"""
Procedure to update the node positions
Three different modes available:
1 = insert node
2 = update position, parent stays the same
3 = update position and change parent
4 = trashed
"""
if mode == 1 or mode==3:
#if node has been inserted at the beginning
if node.position == 1:
node.get_siblings().update(position=F('position') + 1)
#if node has been inserted not at beginning and not at the last position
elif node.position != node.get_siblings().count() + 1:
#update positions of siblings right of node by one
node.get_siblings().filter(position__gte=node.position).update(position=F('position') + 1)
if mode == 3:
#since we removed the node from a parent, we have to decrement the positions of the former siblings right of the node by one
if node._original_parent is not None:
#do updates only for nodes which had a parent before. will not be executed for root nodes
node._original_parent.get_children().filter(position__gt=node._original_position).update(position=F('position') - 1)
if mode == 2:
#if old position is left of new position -> decrement position by 1 for nodes which have position <= node.position AND > node.original_position
if node.position > node._original_position:
node.get_siblings().filter(Q(position__lte=node.position) & Q(position__gt=node._original_position)).update(position=F('position') - 1)
#if old position is right of new position -> increment position by 1 for nodes which have position >= node.position AND < node.original_position
if node.position < node._original_position:
node.get_siblings().filter(Q(position__gte=node.position) & Q(position__lt=node._original_position)).update(position=F('position') + 1)
if mode == 4:
#decrement position by 1 for nodes which have position > node.position
node.get_siblings().filter(Q(position__gt=node.position)).update(position=F('position') - 1)
π€Thomas Kremmel
Source:stackexchange.com