Django Treebeard
django-treebeard is a Django library providing efficient implementations for tree structures using Materialized Path (MPTT), Adjacency List, and Nested Sets algorithms. It offers a robust way to manage hierarchical data directly within Django models. The current stable version is 5.0.5, with releases typically aligning with Django's major versions to maintain compatibility and introduce new features.
Warnings
- breaking Version 5.x of `django-treebeard` dropped support for older Python and Django versions. Specifically, `django-treebeard` 5.x requires Python 3.10+ and Django 4.2+.
- gotcha All concrete (non-abstract) tree models must define `node_order_by` as a list of field names. Failing to do so will result in a `TreebeardMissingNodeOrderBy` exception or non-deterministic sibling ordering.
- gotcha The `AL_Node` (Adjacency List) implementation is significantly less efficient for tree traversal operations (like fetching descendants or ancestors) compared to `MP_Node` or `NS_Node`, especially with deep or large trees.
- gotcha Adding a Treebeard model to an existing table that already contains data requires careful data migration to correctly populate the tree fields (path, depth, numchild, etc.). Simply running `migrate` will likely result in errors or an invalid tree.
Install
-
pip install django-treebeard
Imports
- MP_Node
from treebeard.mp_tree import MP_Node
- AL_Node
from treebeard.al_tree import AL_Node
- NS_Node
from treebeard.ns_tree import NS_Node
Quickstart
from django.db import models
from treebeard.mp_tree import MP_Node
# Define a simple tree model inheriting from MP_Node (Materialized Path)
# This is generally the recommended tree type for most use cases.
class Category(MP_Node):
name = models.CharField(max_length=255)
# Crucial for deterministic ordering of siblings
node_order_by = ['name']
class Meta:
verbose_name_plural = 'categories'
def __str__(self):
return self.name
# Example usage (e.g., in a Django shell or view):
# Create root nodes
# root1 = Category.add_root(name='Electronics')
# root2 = Category.add_root(name='Books')
# Add children to root1
# phone = root1.add_child(name='Phones')
# laptop = root1.add_child(name='Laptops')
# Add a grandchild to phone
# iphone = phone.add_child(name='iPhones')
# Retrieve and traverse
# for node in Category.get_tree():
# print(f"{'--' * node.depth} {node.name}")