Jinja2 and Json

33,824

Solution 1

The documentation reads:

It is possible to use loops recursively. This is useful if you are dealing with recursive data such as sitemaps. To use loops recursively you basically have to add the recursive modifier to the loop definition and call the loop variable with the new iterable where you want to recurse.

In your case this would be accomplished with the following:

<ul>
{% for key, value in linksList.items() recursive %}
    <li>
    {% if value is string %}
        <a href="{{ value }}">{{ key }}</a>
    {% else %}
        {{ key }}
        <ul>{{ loop(value.items()) }}</ul>
    {% endif %}
    </li>
{% endfor %}
</ul>

Solution 2

My 2 cents, just if someone comes here looking for rendering a JSON using Jinja, and complementing the response from @Ryon Sherman :)

  1. Since JSON may have int values as well as strings, you can use if value is mapping (and flip the if-condition)
  2. If your output must feel like a JSON you can use {{key|indent(width)}} + loop.depth
  3. In my case, the template was for an email and key|indent() didn't work as expected so I ended up using an auxiliar {% for %} loop:
<div>
    <code>{
    {% for key, value in dic.items() recursive %}
    {% if value is mapping %}
    <p>
     {% for it in range(loop.depth) %}&nbsp;&nbsp;{% endfor %}{{key}}: {
    </p>
    {{ loop(value.items()) }}
    <p>
      {% for it in range(loop.depth) %}&nbsp;&nbsp;{% endfor %}}
    </p>
    {% else %}
    <p>
      {% for it in range(loop.depth) %}&nbsp;&nbsp;{% endfor %}{{key}}: {{value}},
    </p>
    {% endif %}
    {% endfor %}
    }</code>
</div>
Share:
33,824
lennykey
Author by

lennykey

A software Engineer working with cloud technologies and a fan of Kotlin

Updated on July 10, 2022

Comments

  • lennykey
    lennykey almost 2 years

    I have for example a JSON File

    {
        "Google":{
        "Web":"www.web.de",
        "Apps":{
            "Drive": "DriveLink",
            "Dropbox": "DropboxLink"
        },
        "Google Main":"http://mail.google.com",
        "G+":"http://plus.google.com"
        },  
        "Social":{
        "Facebook":"http://www.facebook.de",
        "G+":"https://plus.google.com",
        "Xing":"http://www.xing.de",
        "LinkedIn":"http://www.linkedin.com",
        "Tumblr":"http://www.tumblr.com"
        },
        "Fun":{
        "Reddit":"http://www.reddit.com"
        }
    }
    

    As you can see I have under the section Google a Nested Section named Apps

    With CherryPy I hand over this JSON Object as following with the name linksList:

    @cherrypy.expose
    def index(self):
        linksFile = open('links.json', 'r')
        linksList = json.load(linksFile) 
    
        template = jinjaEnv.get_template('index.html')
        return template.render(linksList=linksList)
    

    What I want is to render following:

    1. Google
      • Web (as a link)
      • Google Main
      • G+
      • Apps
        • Drive
        • Dropbox
    2. Social
      • Facebook
      • G+
      • Xing

    and so on

    What I don't understand is to do is to render this nested Objects like "Apps" recursively

  • lennykey
    lennykey over 11 years
    Hey Ryon, thank you very much. That was exactly what I was searching for. What exactly helped was to test for a string. I tried for a dict a got an TemplateAssertionError: no test named 'dict'. Why is it that you cannot test for a dict or a list
  • Ryon Sherman
    Ryon Sherman over 11 years
    @lennykey It looks like Jinja doesn't provide a built-in test for dict or list though it is possible to create your own.