This project provides a simple and convenient way to store hierarchical data (i.e. a tree) in Django. By inheriting from the
HierarchicalModel class provided, you automatically get the extra fields you need, and the special methods required to insert data into this special form of table. This project provides the nested set abstraction for hierarchical models, which (roughly speaking) is slow to write to but very fast to read from. django-hierarchy is BSD-licensed, and external contribution is very welcome.
For comparison, see the django-mptt project which provides similar functionality, and is probably better documented.
NOTE: because of some embedded SQL statements, this project currently only works for MySQL backends. If you're interested in having it run with Postgres or SQLite, please let me know.
- The latest stable release: django-hierarchy-0.2.1.zip
- The most recent snapshot: django-hierarchy-tip.zip
Django-hierarchy is also available through PyPI, so it can be installed by running
$ easy_install django-hierarchy
in your shell.
Firstly, define your model by subclassing the
from django.db import models from hierarchy.models import HierarchicalModel class FoodType(HierarchicalModel): name = models.CharField(max_length=100)
Two extra hidden integer fields have been created for you,
right_visit, which are needed for the nested set abstraction to work.
There are several ways you can go from here, depending on your application.
Option A: store an entire tree at once
This is the faster way to construct a tree. Firstly, build your tree.
>>> from hierarchy.tree import TreeNode >>> food = TreeNode('food') >>> fruit = TreeNode('fruit') >>> food.add_child(fruit) >>> for name in ('apple', 'orange', 'banana'): >>> fruit.add_child(TreeNode(name)) >>> food.layout() # pretty-print the tree food └─ fruit ├─ orange ├─ apple └─ banana
Now that you've built the tree, you can store it to your model as follows:
>>> food.store(FoodType, label_field='name')
You just provide your model (in this case
FoodType), and tell it which field to map node labels to. Note that storing the tree this way will clear any existing nodes from the database, effectively overwriting them.
Option B: add things incrementally
If you add things incrementally, each extra insert takes additional time since it also needs to perform an SQL
UPDATE on the entire tree. Still, this way is supported for situations when you don't know the tree in advance.
>>> food = FoodType(name='food', left_visit=1, right_visit=2) >>> food.save() >>> fruit = root.add_child(name='fruit') >>> fruit.add_child(name='orange') >>> fruit.add_child(name='apple') >>> fruit.add_child(name='banana')
Note that we had to set
right_visit values manually for the root node before we could add children. This version of the abstraction always requires a root node. If you want to store a forest, just use a dummy root node and add your top level nodes as its children.