S
S
Sergey Degtyar2019-09-24 10:12:44
Django
Sergey Degtyar, 2019-09-24 10:12:44

How to display a category tree in Django?

There is a model
class Category(models.Model):
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE, related_name='children')
name = models.CharField(max_length=50)
You need to build and output a tree in the template! It needs to be done without django-mptt and other modules.
Tell me how to do it and where to dig
. I didn’t find much information on this topic on the Internet. Everywhere offer django-mptt

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey Gornostaev, 2019-09-24
@sergey-gornostaev

Without MPTT and others like it, only recursion, but it slowly and terribly eats up resources.

J
javedimka, 2019-09-24
@javedimka

Once upon a time I did this. Satisfied, I downloaded django-mptt and converted it to mptt

# Example model
class Category(models.Model):
    parent = models.ForeignKey('Category',
                               on_delete=models.CASCADE,
                               verbose_name=_('Parent'),
                               related_name='children',
                               blank=True,
                               null=True)
    title = models.CharField(_('Title'), max_length=64, unique=True)
    slug = models.SlugField(max_length=50)
    objects = CategoryManager()

    
# Manager with method to build tree using directed graph
class CategoryManager(models.Manager):

    def _traverse(self, hierarchy, graph, items):
        for item in items:
            hierarchy.append(item)
            hierarchy.append(self._traverse([], graph, graph[item.title]))
        return hierarchy

    def as_tree(self):
        """Returns FK hierarchy in form of nested lists."""

        qs = super().get_queryset().exclude(
            title='Unassigned'
        ).select_related('parent')

        roots = []
        children = []
        for item in qs:
            roots.append(item) if item.parent is None else children.append(item)

        graph = {item.title: set() for item in qs}

        sorted_children = sorted(children, key=lambda x: x.parent.title)
        grouped = groupby(children, key=lambda x: x.parent.title)

        for title, group in grouped:
            graph[title].update(group)

        return self._traverse([], graph, roots)
    

# To render in template in form of simple nested unordered list use built-in filter:
# https://docs.djangoproject.com/en/dev/ref/templates/builtins/#unordered-list

{{ tree|unordered_lsit }}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question