Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tree structure of parent child relation in django templates

how do i implement the tree structure in django templates with out using django-mptt.

i have model.

class Person(TimeStampedModel):
    name  = models.CharField(max_length=32)
    parent      = models.ForeignKey('self', null=True, blank=True, related_name='children')

now i want ..

 Parent
    Child 1
         subchild 1.1
         subchild 1.2
             nextsubchild 1.2.1
    Child 2
    Child 3

there names should be click able to show their profile.

like image 803
Ahsan Avatar asked Mar 08 '11 07:03

Ahsan


2 Answers

I just finished implementing this. I wanted a tree structure for a sub-navigation, but I did not want to do anything strange with recursive templates.

The solution I implemented is very simple: I simply recurse in the view (in my case a generic helper function) and flatten out the hierarchical structure into a simple list. Then, in my template I just use a for loop to iterate over the list.

Each element in the list can be one of three things: "in", the object, or "out". In my case, I'm constructing a series of ul li elements in the view, so when I encounter "in" I create a new ul, when I encounter "out" I close the ul. Otherwise, I render the item.

My template code looks like this:

<ul>
    {% for item in sub_nav %}     
        {% if item == "in" %}         
            <ul>
        {% else %}
            {% if item == "out" %}
                    </ul>
                </li>
            {% else %}
                <li>
                    <a href='{{item.full_url}}'>{{item.name}}</a>
                    {% if item.leaf %}
                        </li>
                    {% endif %}
            {% endif %}
        {% endif %}
    {% endfor %}
</ul>

The code in the helper function looks like this:

def get_category_nav(request,categories=None):
    """Recursively build a list of product categories. The resulting list is meant to be iterated over in a view"""
    if categories is None:
        #get the root categories
        categories = ProductCategory.objects.filter(parent=None)
        categories[0].active=True
    else:
        yield 'in'

    for category in categories:
        yield category
        subcats = ProductCategory.objects.select_related().filter(parent=category)
        if len(subcats):
            category.leaf=False
            for x in get_category_nav(request,subcats):
                yield x
        else:
            category.leaf=True
    yield 'out'

Using those snippets, you should be able to build any sort of hierarchical tree you'd like without doing any recursion in the template, and keeping all the logic in the view.

I know there was already an accepted answer for this, but I thought I'd post the technique in case it helps anyone else.

like image 131
Clayton Gulick Avatar answered Oct 13 '22 07:10

Clayton Gulick


from Django while loop question and

http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags

# view.py

@register.inclusion_tag('children.html')
def children_tag(person):
    children = person.children.all()
    return {'children': children}

# children.html

<ul>
    {% for child in children %}
    <li> <a href="{{ child.get_absolute_url }}">{{ child }}</a></li>
        {% if child.children.count > 0 %}
        {% children_tag child %}
        {% endif %}
    {% endfor %}
</ul>


# your template

{% children_tag parent %}
    
like image 41
dting Avatar answered Oct 13 '22 07:10

dting