Wiki

Clone wiki

django-hierarchy / Home

Django Hierarchy

Overview

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.

Download

Django-hierarchy is also available through PyPI, so it can be installed by running

$ easy_install django-hierarchy

in your shell.

Example

Firstly, define your model by subclassing the HierarchicalModel class.

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, left_visit and 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 left_visit and 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.

Updated