How can I render a tree structure (recursive) using a django template?

I have a tree structure in memory that I would like to render in HTML using a Django template.

class Node():
  name = "node name"
  children = []

There will be some object root that is a Node, and children is a list of Nodes. root will be passed in the content of the template.

I have found this one discussion of how this might be achieved, but the poster suggests this might not be good in a production environment.

Does anybody know of a better way?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Using with template tag, I could do tree/recursive list.

Sample code:

main template: assuming ‘all_root_elems’ is list of one or more root of tree

<ul>
{%for node in all_root_elems %} 
    {%include "tree_view_template.html" %}
{%endfor%}
</ul>

tree_view_template.html renders the nested ul, li and uses node template variable as below:

<li> {{node.name}}
    {%if node.has_childs %}
        <ul>
         {%for ch in node.all_childs %}
              {%with node=ch template_name="tree_view_template.html" %}
                   {%include template_name%}
              {%endwith%}
         {%endfor%}
         </ul>
    {%endif%}
</li>

Method 2

I’m too late.
All of you use so much unnecessary with tags, this is how I do recursive:

In the “main” template:

<!-- lets say that menu_list is already defined -->
<ul>
    {% include "menu.html" %}
</ul>

Then in menu.html:

{% for menu in menu_list %}
    <li>
        {{ menu.name }}
        {% if menu.submenus|length %}
            <ul>
                {% include "menu.html" with menu_list=menu.submenus %}
            </ul>
        {% endif %}
    </li>
{% endfor %}

Method 3

I think the canonical answer is: “Don’t”.

What you should probably do instead is unravel the thing in your view code, so it’s just a matter of iterating over (in|de)dents in the template. I think I’d do it by appending indents and dedents to a list while recursing through the tree and then sending that “travelogue” list to the template. (the template would then insert <li> and </li> from that list, creating the recursive structure with “understanding” it.)

I’m also pretty sure recursively including template files is really a wrong way to do it…

Method 4

this might be way more than you need, but there is a django module called ‘mptt’ – this stores a hierarchical tree structure in an sql database, and includes templates for display in the view code. you might be able to find something useful there.

here’s the link : django-mptt

Method 5

Yes, you can do it. It’s a little trick,
passing the filename to {% include %} as a variable:

{% with template_name="file/to_include.html" %}
{% include template_name %}
{% endwith %}

Method 6

Django has a built in template helper for this exact scenario:

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#unordered-list

Method 7

I had the same problem and I wrote a template tag. I know there are other tags like this out there but I needed to learn to make custom tags anyway 🙂 I think it turned out pretty well.

Read the docstring for usage instructions.

github.com/skid/django-recurse

Method 8

Does no one like dicts ? I might be missing something here but it would seem the most natural way to setup menus. Using keys as entries and values as links pop it in a DIV/NAV and away you go !

From your base

# Base.html
<nav>
{% with dict=contents template="treedict.html" %}
 {% include template %}
{% endwith %}
<nav>

call this

# TreeDict.html
<ul>
{% for key,val in dict.items %}
 {% if val.items %}
  <li>{{ key }}</li>
  {%with dict=val template="treedict.html" %}
   {%include template%}
  {%endwith%}
 {% else %} 
  <li><a href="{{ val }}" rel="nofollow noreferrer noopener">{{ key }}</a></li>
 {% endif %}
{% endfor %} 
</ul>

It haven’t tried the default or the ordered yet perhaps you have ?

Method 9

correct this:

root_comment.html

{% extends 'students/base.html' %}
{% load i18n %}
{% load static from staticfiles %}

{% block content %}

<ul>
{% for comment in comments %}
    {% if not comment.parent %}                   ## add this ligic
    {% include "comment/tree_comment.html" %}
    {% endif %}
{% endfor %}
</ul>

{% endblock %}

tree_comment.html

<li>{{ comment.text }}
    {%if comment.children %}
        <ul>
         {% for ch in comment.children.get_queryset %}     # related_name in model
              {% with comment=ch template_name="comment/tree_comment.html" %}
                   {% include template_name %}
              {% endwith %}
         {% endfor %}
         </ul>
    {% endif %}
</li>

for example – model:

from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _


# Create your models here.
class Comment(models.Model):
    class Meta(object):
        verbose_name = _('Comment')
        verbose_name_plural = _('Comments')

    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        parent_link=True,
        related_name='children',
        null=True,
        blank=True)

    text = models.TextField(
        max_length=2000,
        help_text=_('Please, your Comment'),
        verbose_name=_('Comment'),
        blank=True)

    public_date = models.DateTimeField(
        auto_now_add=True)

    correct_date = models.DateTimeField(
        auto_now=True)

    author = models.ForeignKey(User)

Method 10

I had a similar issue, however I had first implemented the solution using JavaScript, and just afterwards considered how I would have done the same thing in django templates.

I used the serializer utility to turn a list off models into json, and used the json data as a basis for my hierarchy.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x