# API

class treebeard.models.Node(*args, **kwargs)

  Bases: `Model`

  Node class

  This is the base class that defines the API of all tree models in this library:

  > - `treebeard.mp_tree.MP_Node` (materialized path)

  > - `treebeard.ns_tree.NS_Node` (nested sets)

  > - `treebeard.al_tree.AL_Node` (adjacency list)

  Warning

  Please be aware of the Known Caveats when using this library.

  classmethod add_root(**kwargs)

    Adds a root node to the tree. The new root node will be the new rightmost root node. If you want to insert a root node at a specific position, use `add_sibling()` in an already existing root node instead.

    Parameters:

      - **kwargs – object creation data that will be passed to the inherited Node model

      - instance – Instead of passing object creation data, you can pass an already-constructed (but not yet saved) model instance to be inserted into the tree.

    Returns:

      the created node object. It will be save()d by this method.

    Raises:

      NodeAlreadySaved – when the passed `instance` already exists in the database

    Example:

        MyNode.add_root(numval=1, strval='abcd')

    Or, to pass in an existing instance:

        new_node = MyNode(numval=1, strval='abcd')
        MyNode.add_root(instance=new_node)

  add_child(**kwargs)

    Adds a child to the node. The new node will be the new rightmost child. If you want to insert a node at a specific position, use the `add_sibling()` method of an already existing child node instead.

    Parameters:

      - **kwargs – Object creation data that will be passed to the inherited Node model

      - instance – Instead of passing object creation data, you can pass an already-constructed (but not yet saved) model instance to be inserted into the tree.

    Returns:

      The created node object. It will be save()d by this method.

    Raises:

      NodeAlreadySaved – when the passed `instance` already exists in the database

    Example:

        node.add_child(numval=1, strval='abcd')

    Or, to pass in an existing instance:

        new_node = MyNode(numval=1, strval='abcd')
        node.add_child(instance=new_node)

  add_sibling(pos=None, **kwargs)

    Adds a new node as a sibling to the current node object.

    Parameters:

      - pos –

        The position, relative to the current node object, where the new node will be inserted, can be one of:

        - `first-sibling`: the new node will be the new leftmost sibling

        - `left`: the new node will take the node’s place, which will be moved to the right 1 position

        - `right`: the new node will be inserted at the right of the node

        - `last-sibling`: the new node will be the new rightmost sibling

        - `sorted-sibling`: the new node will be at the right position according to the value of node_order_by

      - **kwargs – Object creation data that will be passed to the inherited Node model

      - instance – Instead of passing object creation data, you can pass an already-constructed (but not yet saved) model instance to be inserted into the tree.

    Returns:

      The created node object. It will be saved by this method.

    Raises:

      - InvalidPosition – when passing an invalid `pos` parm

      - InvalidPosition – when `node_order_by` is enabled and the `pos` parm wasn’t `sorted-sibling`

      - MissingNodeOrderBy – when passing `sorted-sibling` as `pos` and the `node_order_by` attribute is missing

      - NodeAlreadySaved – when the passed `instance` already exists in the database

    Examples:

        node.add_sibling('sorted-sibling', numval=1, strval='abc')

    Or, to pass in an existing instance:

        new_node = MyNode(numval=1, strval='abc')
        node.add_sibling('sorted-sibling', instance=new_node)

  delete(*args, **kwargs)

    Removes a node and all it’s descendants.

    Note

    Call our queryset’s delete to handle children removal. Subclasses will handle extra maintenance.

  classmethod get_tree(parent=None)
    Returns:

      A list of nodes ordered as DFS, including the parent. If no parent is given, the entire tree is returned.

  get_depth()
    Returns:

      the depth (level) of the node

    Example:

        node.get_depth()

  get_ancestors()
    Returns:

      A queryset containing the current node object’s ancestors, starting by the root node and descending to the parent. (some subclasses may return a list)

    Example:

        node.get_ancestors()

  get_children()
    Returns:

      A queryset of all the node’s children

    Example:

        node.get_children()

  get_children_count()
    Returns:

      The number of the node’s children

    Example:

        node.get_children_count()

  get_descendants()
    Returns:

      A queryset of all the node’s descendants, doesn’t include the node itself (some subclasses may return a list).

    Example:

        node.get_descendants()

  get_descendant_count()
    Returns:

      the number of descendants of a node.

    Example:

        node.get_descendant_count()

  get_first_child()
    Returns:

      The leftmost node’s child, or None if it has no children.

    Example:

        node.get_first_child()

  get_last_child()
    Returns:

      The rightmost node’s child, or None if it has no children.

    Example:

        node.get_last_child()

  get_first_sibling()
    Returns:

      The leftmost node’s sibling, can return the node itself if it was the leftmost sibling.

    Example:

        node.get_first_sibling()

  get_last_sibling()
    Returns:

      The rightmost node’s sibling, can return the node itself if it was the rightmost sibling.

    Example:

        node.get_last_sibling()

  get_prev_sibling()
    Returns:

      The previous node’s sibling, or None if it was the leftmost sibling.

    Example:

        node.get_prev_sibling()

  get_next_sibling()
    Returns:

      The next node’s sibling, or None if it was the rightmost sibling.

    Example:

        node.get_next_sibling()

  get_parent(update=False)
    Returns:

      the parent node of the current node object. Caches the result in the object itself to help in loops.

    Parameters:

      update – Updates the cached value.

    Example:

        node.get_parent()

  get_root()
    Returns:

      the root node for the current node object.

    Example:

        node.get_root()

  get_siblings()
    Returns:

      A queryset of all the node’s siblings, including the node itself.

    Example:

        node.get_siblings()

  is_child_of(node)
    Returns:

      `True` if the node is a child of another node given as an argument, else, returns `False`

    Parameters:

      node – The node that will be checked as a parent

    Example:

        node.is_child_of(node2)

  is_descendant_of(node)
    Returns:

      `True` if the node is a descendant of another node given as an argument, else, returns `False`

    Parameters:

      node – The node that will be checked as an ancestor

    Example:

        node.is_descendant_of(node2)

  is_sibling_of(node)
    Returns:

      `True` if the node is a sibling of another node given as an argument, else, returns `False`

    Parameters:

      node – The node that will be checked as a sibling

    Example:

        node.is_sibling_of(node2)

  is_root()
    Returns:

      True if the node is a root node (else, returns False)

    Example:

        node.is_root()

  is_leaf()
    Returns:

      True if the node is a leaf node (else, returns False)

    Example:

        node.is_leaf()

  move(target, pos=None)

    Moves the current node and all it’s descendants to a new position relative to another node.

    Parameters:

      - target – The node that will be used as a relative child/sibling when moving

      - pos –

        The position, relative to the target node, where the current node object will be moved to, can be one of:

        - `first-child`: the node will be the new leftmost child of the `target` node

        - `last-child`: the node will be the new rightmost child of the `target` node

        - `sorted-child`: the new node will be moved as a child of the `target` node according to the value of `node_order_by`

        - `first-sibling`: the node will be the new leftmost sibling of the `target` node

        - `left`: the node will take the `target` node’s place, which will be moved to the right 1 position

        - `right`: the node will be moved to the right of the `target` node

        - `last-sibling`: the node will be the new rightmost sibling of the `target` node

        - `sorted-sibling`: the new node will be moved as a sibling of the `target` node according to the value of `node_order_by`

        Note

        If no `pos` is given the library will use `last-sibling`, or `sorted-sibling` if `node_order_by` is enabled.

    Returns:

      None

    Raises:

      - InvalidPosition – when passing an invalid `pos` parm

      - InvalidPosition – when `node_order_by` is enabled and the `pos` parm wasn’t `sorted-sibling` or `sorted-child`

      - InvalidMoveToDescendant – when trying to move a node to one of it’s own descendants

      - PathOverflow – when the library can’t make room for the node’s new position

      - MissingNodeOrderBy – when passing `sorted-sibling` or `sorted-child` as `pos` and the `node_order_by` attribute is missing

    Note

    The node can be moved under another root node.

    Examples:

        node.move(node2, 'sorted-child')
        node.move(node2, 'prev-sibling')

  save(*args, force_insert=False, force_update=False, using=None, update_fields=None)

    Save the current instance. Override this in a subclass if you want to control the saving process.

    The ‘force_insert’ and ‘force_update’ parameters can be used to insist that the “save” must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

  classmethod get_first_root_node()
    Returns:

      The first root node in the tree or `None` if it is empty.

    Example:

        MyNodeModel.get_first_root_node()

  classmethod get_last_root_node()
    Returns:

      The last root node in the tree or `None` if it is empty.

    Example:

        MyNodeModel.get_last_root_node()

  classmethod get_root_nodes()
    Returns:

      A queryset containing the root nodes in the tree.

    Example:

        MyNodeModel.get_root_nodes()

  classmethod load_bulk(bulk_data, parent=None, keep_ids=False)

    Loads a list/dictionary structure to the tree.

    Parameters:

      - bulk_data –

        The data that will be loaded, the structure is a list of dictionaries with 2 keys:

        - `data`: will store arguments that will be passed for object creation, and

        - `children`: a list of dictionaries, each one has it’s own `data` and `children` keys (a recursive structure)

      - parent – The node that will receive the structure as children, if not specified the first level of the structure will be loaded as root nodes

      - keep_ids – If enabled, loads the nodes with the same primary keys that are given in the structure. Will error if there are nodes without primary key info or if the primary keys are already used.

    Returns:

      A list of the added node PKs.

    Note

    Any internal data that you may have stored in your nodes’ data (`path`, `depth`) will be ignored.

    Note

    If your node model has a ForeignKey this method will try to load the related object before loading the data. If the related object doesn’t exist it won’t load anything and will raise a DoesNotExist exception. This is done because the dump_data method uses integers to dump related objects.

    Note

    If your node model has `node_order_by` enabled, it will take precedence over the order in the structure.

    Example:

        data = [{'data':{'desc':'1'}},
                {'data':{'desc':'2'}, 'children':[
                  {'data':{'desc':'21'}},
                  {'data':{'desc':'22'}},
                  {'data':{'desc':'23'}, 'children':[
                    {'data':{'desc':'231'}},
                  ]},
                  {'data':{'desc':'24'}},
                ]},
                {'data':{'desc':'3'}},
                {'data':{'desc':'4'}, 'children':[
                  {'data':{'desc':'41'}},
                ]},
        ]
        # parent = None
        MyNodeModel.load_bulk(data, None)

    Will create:

  classmethod dump_bulk(parent=None, keep_ids=True)

    Dumps a tree branch to a python data structure.

    Parameters:

      - parent – The node whose descendants will be dumped. The node itself will be included in the dump. If not given, the entire tree will be dumped.

      - keep_ids – Stores the pk value (primary key) of every node. Enabled by default.

    Returns:

      A python data structure, described with detail in `load_bulk()`

    Example:

        tree = MyNodeModel.dump_bulk()
        branch = MyNodeModel.dump_bulk(node_obj)

  classmethod find_problems()

    Checks for problems in the tree structure.

  classmethod fix_tree()

    Solves problems that can appear when transactions are not used and a piece of code breaks, leaving the tree in an inconsistent state.

  classmethod get_descendants_group_count(parent=None)

    Helper for a very common case: get a group of siblings and the number of descendants (not only children) in every sibling.

    Parameters:

      parent – The parent of the siblings to return. If no parent is given, the root nodes will be returned.

    Returns:

      A list (NOT a Queryset) of node objects with an extra attribute: descendants_count.

    Example:

        # get a list of the root nodes
        root_nodes = MyModel.get_descendants_group_count()

        for node in root_nodes:
            print '%s by %s (%d replies)' % (node.comment, node.author,
                                             node.descendants_count)

  classmethod get_annotated_list(parent=None, max_depth=None)

    Gets an annotated list from a tree branch.

    Parameters:

      - parent – The node whose descendants will be annotated. The node itself will be included in the list. If not given, the entire tree will be annotated.

      - max_depth – Optionally limit to specified depth

    Example:

        annotated_list = MyModel.get_annotated_list()

    With data:

    Will return:

        [
            (a,     {'open':True,  'close':[],    'level': 0})
            (ab,    {'open':True,  'close':[],    'level': 1})
            (aba,   {'open':True,  'close':[],    'level': 2})
            (abb,   {'open':False, 'close':[],    'level': 2})
            (abc,   {'open':False, 'close':[0,1], 'level': 2})
            (ac,    {'open':False, 'close':[0],   'level': 1})
        ]

    This can be used with a template like:

        {% for item, info in annotated_list %}
            {% if info.open %}
                <ul><li>
            {% else %}
                </li><li>
            {% endif %}

            {{ item }}

            {% for close in info.close %}
                </li></ul>
            {% endfor %}
        {% endfor %}

    Note

    This method was contributed originally by Alexey Kinyov, using an idea borrowed from django-mptt.

    Added in version 1.55.

  classmethod get_annotated_list_qs(qs)

    Efficiently generates an annotated list from a queryset.

    The queryset MUST be ordered by path, otherwise it will yield incorrect results. The queryset must also represent the entirety of a branch of a tree: excluded objects will not be fetched and will result in gaps in the tree.