Models and Managers

About this document

This document describes the changes Django MPTT makes to your Django model classes and the custom tree manager it provides, so you can easily work with model instances as trees.

Contents

mptt.register - setting up a Django model for MPTT

The mptt module contains a register function, which users can call to set a Django model up for MPTT. This function takes as its arguments the model class itself and additional options related to working with the model as a tree.

mptt.register and syncdb

As discussed further below, the mptt.register function will dynamically add new fields to your models if certain required tree fields are not present.

As such, unless you are manually setting up all required tree fields in your models, you must have the call to mptt.register in place before you use Django's syncdb management command to create tables. Otherwise, you will have to recreate tables so the appropriate tree columns are in place in the database.

The following argument is required:

model
The model class which is to be set up for MPTT.

All remaining arguments are optional, but you should take care to specify appropriate fields names where the default field names do not fit with your model class' definition:

parent_attr

The name of a field which relates the model back to itself such that each instance can be a child of another instance. Defaults to 'parent'.

Users are responsible for setting this field up on the model class, which can be done like so:

parent = models.ForeignKey('self', null=True, blank=True, related_name='children')

For the following four arguments, if fields with the given names do not exist, they will be added to the model dynamically:

left_attr
The name of a field which contains the left tree node edge indicator, which should be a PositiveIntegerField. Defaults to 'lft'.
right_attr
The name of a field which contains the right tree node edge indicator, which should be a PositiveIntegerField. Defaults to 'rght'.
tree_id_attr

The name of a field which contains the tree id of each node, which should be a PositiveIntegerField. Defaults to 'tree_id'.

Items which do not have a parent are considered to be "root" nodes in the tree and will be allocated a new tree id. All descendants of root nodes will be given the same tree id as their root node.

level_attr

The name of a field which contains the (zero-based) level at which an item sits in the tree, which should be a PositiveIntegerField. Defaults to 'level'.

For example, root nodes would have a level of 0 and their immediate children would have have a level of 1.

tree_manager_attr
The name of an attribute which will hold a custom manager which is used to work with trees of model instances. Defaults to 'tree'.
order_insertion_by

The name of a field which should define ordering when new tree nodes are being inserted or existing nodes are being reparented. Defaults to None.

Note that this will require an extra database query to determine where nodes should be positioned when they are being saved. This option is handy if you're maintaining mostly static structures, such as trees of categories, which should always be in alphabetical order.

A mimimal example usage of mptt.register is given below, where the model being set up for MPTT is suitable for use with the default arguments which specify fields and the tree manager attribute:

from django.db import models

import mptt

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

mptt.register(Genre, order_insertion_by='name')

Model instance methods added by Django MPTT

The following instance methods will be added to your Django models when you set them up for MPTT:

The TreeManager custom manager

A custom manager, TreeManager is also added to your Django models when you set them up for MPTT - the attribute this manager can be accessed through is specified by the tree_manager_attr argument to mptt.register.

Any QuerySet created with this manager will be ordered based on the tree structure, with root nodes appearing in tree id order and and their descendants being ordered in a depth-first fashion.

The following manager methods are available:

Example usage

In the following examples, we have Category and Question models. Question has a category field which is a ForeignKey to Category.

Retrieving a list of root Categories which have a question_count attribute containing the number of Questions associated with each root and all of its descendants:

roots = Category.tree.add_related_count(Category.tree.root_nodes(), Question,
                                        'category', 'question_counts',
                                        cumulative=True)

Retrieving a list of child Categories which have a question_count attribute containing the number of Questions associated with each of them:

node = Category.objects.get(name='Some Category')
children = Category.tree.add_related_count(node.get_children(), Question,
                                           'category', 'question_counts')