About this document
This document describes the abstract model Django MPTT provides so you can easily work with model instances as trees.
The mptt
module contains a Model
class, which is an abstract model that provides all the fields and methods required for MPTT.
A mimimal example usage of mptt.Model
is given below, where the model being set up for MPTT is suitable for use with the default field and tree manager attributes:
import mptt
class Category(mptt.Model):
name = models.CharField(max_length=50, unique=True)
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
Options for MPTT can be given using an inner class MpttMeta
:
import mptt
class Genre(mptt.Model):
name = models.CharField(max_length=50, unique=True)
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
class MpttMeta:
order_insertion_by = 'name'
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 of1
.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
A list of field names which should define ordering when new tree nodes are being inserted or existing nodes are being reparented, with the most significant ordering field name first. Defaults to
[]
.It is assumed that any field identified as defining ordering will never be
NULL
in the database.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.
The following instance methods will be added to your Django models when you set them up for MPTT:
creates a QuerySet
containing the ancestors of the model instance.
These default to being in descending order (root ancestor first, immediate parent last); passing True
for the ascending
argument will reverse the ordering (immediate parent first, root ancestor last).
Creates a QuerySet
containing the immediate children of the model instance, in tree order.
The benefit of using this method over the reverse relation provided by the ORM to the instance's children is that a database query can be avoided in the case where the instance is a leaf node (it has no children).
Creates a QuerySet
containing descendants of the model instance, in tree order.
If include_self
is True
, the QuerySet
will also include the model instance itself.
Returns the number of descendants the model instance has, based on its left and right tree node edge indicators. As such, this does not incur any database access.
Returns the model instance's next sibling in the tree, or None
if it doesn't have a next sibling.
Returns the model instance's previous sibling in the tree, or None
if it doesn't have a previous sibling.
Returns the root node of the model instance's tree.
Creates a QuerySet
containing siblings of the model instance. Root nodes are considered to be siblings of other root nodes.
If include_self
is True
, the QuerySet
will also include the model instance itself.
Positions the model instance (which must not yet have been inserted into the database) in the tree based on target
and position
(when appropriate).
If commit
is True, the model instance's save()
method will be called before the instance is returned.
Returns True
if the model instance is a child node, False
otherwise.
Returns True
if the model instance is a leaf node (it has no children), False
otherwise.
Returns True
if the model instance is a root node, False
otherwise.
Moves the model instance elsewhere in the tree based on target
and position
(when appropriate).
Note
It is assumed that when you call this method, the tree fields in the instance you've called it on, and in any target
instance passed in, reflect the current state of the database.
Modifying the tree fields manually before calling this method or using tree fields which are out of sync with the database can result in the tree structure being put into an inaccurate state.
If target
is another model instance, it will be used to determine the type of movement which needs to take place, and will be used as the basis for positioning the model when it is moved, in combination with the position
argument.
A target
of None
indicates that the model instance should be turned into a root node. The position
argument is disregarded in this case.
Valid values for the position
argument and their effects on movement are:
'first-child'
The instance being moved should have
target
set as its new parent and be placed as its first child in the tree structure.'last-child'
The instance being moved should have
target
set as its new parent and be placed as its last child in the tree structure.'left'
The instance being moved should have
target
's parent set as its new parent and should be placed directly beforetarget
in the tree structure.'right'
The instance being moved should have
target
's parent set as its new parent and should be placed directly aftertarget
in the tree structure.
A ValueError
will be raised if an invalid value is given for the position
argument.
Note that some of the moves you could attempt to make with this method are invalid - for example, trying to make an instance be its own its own child or the child of one of its descendants. In these cases, a mptt.exceptions.InvalidMove
exception will be raised.
The instance itself will be also modified as a result of this call, to reflect the state of its updated tree fields in the database, so it's safe to go on to save it or use its tree fields after you've called this method.
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
TreeMeta
option..
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:
Adds a related item count to a given QuerySet
using its extra method, for a model which has a relation to this manager's model.
rel_cls
A Django model class which has a relation to this manager's model.
rel_field
The name of the field in
rel_cls
which holds the relation.count_attr
The name of an attribute which should be added to each item in this
QuerySet
, containing a count of how many instances ofrel_cls
are related to it throughrel_field
.cumulative
If
True
, the count will be for each item and all of its descendants, otherwise it will be for each item itself.
Returns the root node of tree with the given id.
Sets up the tree state for node
(which has not yet been inserted into in the database) so it will be positioned relative to a given target
node as specified by position
(when appropriate) when it is inserted, with any neccessary space already having been made for it.
A target
of None
indicates that node
should be the last root node.
If commit
is True
, node
's save()
method will be called before it is returned.
Moves node
based on target
, relative to position
when appropriate.
A target
of None
indicates that node
should be removed from its current position and turned into a root node. If node
is a root node in this case, no action will be taken.
The given node
will be modified to reflect its new tree state in the database.
For more details, see the move_to documentation above.
Creates a QuerySet
containing root nodes.
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')