Nested Set Model

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from django.db import models, connection
import operator

qn = connection.ops.quote_name

class Node(models.Model):
    parent    = models.ForeignKey('self', related_name="children", blank=True, null=True)
    position  = models.IntegerField(default=0)
    lft       = models.PositiveIntegerField(editable=False,default=1)
    rgt       = models.PositiveIntegerField(editable=False,default=1)

        
    def rebuild_tree(self, left):
        right = left+1
        for c in Node.objects.filter(parent=self).order_by('position'):
            right = c.rebuild_tree(right)
        self.lft = left
        self.rgt = right
        super(Node, self).save()
        return right+1

    def ancestors(self):
        query = """
        SELECT id FROM %s
        WHERE lft <= %s AND rgt >= %s
        ORDER BY lft;
        """ % (qn(self._meta.db_table), self.lft, self.rgt)
         
        cursor = connection.cursor()
        cursor.execute(query)
        results = cursor.fetchall()
        return map(operator.itemgetter(0), results)

    def save(self):
        super(Node, self).save()
        
        root = Node.objects.filter(parent__isnull=True)[0]
        root.rebuild_tree(1)

Comments

jshaffer (on November 3, 2007):

The in-progress implementation in Satchmo ticket 202 makes a little more sense. Specifically, the ancestors() equivalent retains Django's API and the save() method is a lot more efficient.

#

mikko (on February 1, 2008):

looks like django-mptt is something anyone looking at this should look at.

#

(Forgotten your password?)

You may use Markdown syntax here, but raw HTML will be removed.