Search code examples
django-mptt

Creating child records with django-mptt


I have successfully completed the django-mptt tutorial. What I cannot figure out how to do is create a child of a child.

By child of a child, i mean a third level deep and more. See example below, I want to create 1.3.1, 1.3.2, 1.3.1.1

1.0 Product Z
      1.1 Product A
      1.2 Product B
      1.3 Product P
            1.3.1 Product X
                   1.3.1.1 Product O
            1.3.2 Product Y
2.0 Product H

In the doco i found insert_node but dont understand it enough to get it working. Also i found something in the code comments (line 317) regarding insert_node that says:

NOTE: This is a low-level method; it does NOT respect ``MPTTMeta.order_insertion_by``.
        In most cases you should just set the node's parent and let mptt call this during save.

Should i be using 'insert_node' or is there a better way? If 'insert_node' should be used, then can you provide an example of its use?


Solution

  • This can be a little confusing, I admit. But as you can read here, the order_insertion_by field should only be used, when you're after something like a standard insertion behavior, for example alphabetically ordered trees and so on as it triggers an extra db query.

    However, if you want to insert a node at a specific point in your tree, you have to use either TreeManager.insert_node or MPTTModel.insert_at, the latter being a convenience method for calling the first.

    So, according to your example, this leads to the following three options to add a new 1.3.3 Product Q as last child of 1.3 Product P:

    new_node = ProductNode(name='1.3.3 Product Q')
    
    parent = ProductNode.objects.get(name='1.3 Product P')
    
    
    # With `order_insertion_by`
    
    new_node.parent = parent
    new_node.save()
    
    
    # With `TreeManager.insert_node`
    
    ProductNode.objects.insert_node(new_node, parent, position='last-child', save=True)
    
    
    # With `MPTTModel.insert_at`
    
    new_node.insert_at(parent, position='last-child', save=True)