0

I want to implement django recursive template rendering for getting users and their subordinates. However, I've got a ErrorRuntimeError at /admin/users/3 maximum recursion depth exceeded in instancecheck. I'm using django 1.9. The code is given below

The input is like that: [{name: 'user1@mail.com', id: 1, next: True}, {name: 'user2@mail.com', id: 2, next: True}, {name: 'user3@mail.com', id: 3, next: False}]

users_hierarchy.html

<ul>
{% for user in users %}
    <li>{{ user.name }}</li>
    {% if user.next %}
        <ul>
           {% include 'users/user_hierarchy.html' with data=user %}
        </ul>
    {% endif %}
{% endfor %}

I expect a html such as:

<ul>
<li>user1@mail.com
    <ul>
        <li>user2@mail.com
    <ul>
         <li>user3@mail.com</li>
    </ul>
        </li>  
    </ul>
</li>

What I am doing wrong?

PolyMorph
  • 11
  • 3
  • You're passing the same user to the include, so the recursion can never return. You really need to pass the *next* user to the include; but there isn't a good way of getting it with the structure you have. – Daniel Roseman Feb 08 '19 at 13:27
  • @DanielRoseman How could I pass the next user to the include? And what the better way to to organize my structure? – PolyMorph Feb 08 '19 at 13:34
  • As I say, you can't do it in the template with the structure you have. Where does this data come from? Do you have control over the format? Ideally you want a structure like `{name: 'user1@mail.com', children: [{name: 'user2', children: [{name: 'user3'}]]}`. – Daniel Roseman Feb 08 '19 at 13:39
  • The data is actually a RawQuerySet which is formed in for-loop by me to array of dictionaries, so I should change the form of input object and the code above will work? – PolyMorph Feb 08 '19 at 14:21
  • Well, you would need to change the if statement to `if user.children` and the include to `with users=user.children`. – Daniel Roseman Feb 08 '19 at 14:23
  • Of course, thanks a lot! – PolyMorph Feb 08 '19 at 14:25

1 Answers1

0

I explain why you are in an infinite recursion

From djanto include template docs:

An included template is rendered within the context of the template that includes it.

That means you are iterating over users again and again:

<ul>
{% for user in users %}                 <-----(1)<------------------------<
    <li>{{ user.name }}</li>                                              |
    {% if user.next %}                                                    |
        <ul>                                                              |
           {% include 'users/user_hierarchy.html' with data=user %} --(2)->

At (1) you iterate over users. At first iteration you call the include (2). At this point you go to (1) (in nested included template) and start iteration again.

dani herrera
  • 48,760
  • 8
  • 117
  • 177
  • Thanks for the explanation, but how can I pass the next user within the same template? – PolyMorph Feb 08 '19 at 13:37
  • What about to use django-mptt ? Take a look to this question: https://stackoverflow.com/questions/32044/how-can-i-render-a-tree-structure-recursive-using-a-django-template – dani herrera Feb 08 '19 at 14:49