Django MPTT
django-mptt is a reusable Django application that simplifies the implementation of Modified Preorder Tree Traversal (MPTT) for hierarchical data in Django models. It provides tools for managing and working with trees of model instances, including automatic updates for tree structures, custom managers, and admin classes. The current version is 0.18.0, and while it continues to receive compatibility updates for newer Django and Python versions, the project maintainers note that the project is "currently unmaintained" in terms of active feature development, suggesting users consider alternatives for new projects.
Warnings
- deprecated The `django-mptt` project is officially marked as 'unmaintained'. While it receives compatibility updates, active feature development has ceased. For new projects or if you require ongoing maintenance, consider alternatives like `django-tree-queries` (which leverages PostgreSQL's Recursive CTEs).
- gotcha When performing tree reorganizations (e.g., `insert_at`, `move_to`), existing model instances in your application's memory might become stale and hold outdated MPTT field values. You must manually call `refresh_from_db()` on affected instances to load the updated data from the database.
- gotcha The `tree_id` field is considered volatile and should not be used to uniquely identify or store references to specific trees in your application logic, as these IDs can change during node movement operations.
- gotcha Calling `delete()` on a `MPTTModel` instance correctly removes the node and its entire subtree. However, performing bulk deletes directly on a QuerySet (e.g., `MyModel.objects.filter(...).delete()`) will bypass MPTT's hooks and lead to an inconsistent tree structure.
- breaking Prior to version 0.15, django-mptt had broader Python and Django compatibility. Version 0.15 dropped support for Python <3.9 and Django <3.2. Subsequent versions continue to drop older Django/Python support to maintain compatibility with the latest stable releases.
- gotcha When using multiple inheritance with `MPTTModel`, it is crucial that `MPTTModel` is the *first* class inherited (e.g., `class MyModel(MPTTModel, OtherMixin):`). Failing to do so can result in `AttributeError: 'NoneType' object has no attribute 'name'` during model validation due to Django's inheritance resolution.
Install
-
pip install django-mptt
Imports
- MPTTModel
from mptt.models import MPTTModel
- TreeForeignKey
from mptt.models import TreeForeignKey
- MPTTModelAdmin
from mptt.admin import MPTTModelAdmin
- DraggableMPTTAdmin
from mptt.admin import DraggableMPTTAdmin
Quickstart
# settings.py
INSTALLED_APPS = [
# ...
'mptt',
'myapp', # your app name
# ...
]
# myapp/models.py
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', on_delete=models.CASCADE,
null=True, blank=True, related_name='children')
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return self.name
# myapp/admin.py
from django.contrib import admin
from mptt.admin import DraggableMPTTAdmin
from .models import Category
@admin.register(Category)
class CategoryAdmin(DraggableMPTTAdmin):
list_display = ('tree_actions', 'indented_title',)
list_display_links = ('indented_title',)
# Optional: to expand the tree by default
expand_tree_by_default = True