4

I have a the following dict:

{"name1":{"text":"my text 1", "status":"my status"}, "name2":{"text":"my text 2", "status":"my status"}}

Using Mako template, I want to create a html table. I tried the following:

Python snippet:

test = {"name1":{"text":"my text 1", "status":"my status"}, "name2":{"text":"my text 2", "status":"my status"}}
mytemplate = Template(filename='template/index.mako')
return mytemplate.render(data=test)

Mako snippet:

% for key, val in data.iteritems():
    <tr>
        <td>${loop.index + 1}</td>
        <td>${key}</td>
        % for tkey, tval in val.iteritems():
            <td>${tkey}</td>
            <td>${tval}</td>
        % endfor
    </tr>
% endfor

The above snippets raise error('str' object has no attribute 'iteritems').

What is the proper way to iterate over nested dicts?

Thank you

dwich
  • 1,710
  • 1
  • 15
  • 20
florin
  • 719
  • 12
  • 31

1 Answers1

2

It is oddly difficult to do this. I recently was trying to do something very similar, found this post, and was sad to see that it did not have any answers.

You asked for the "proper" way, and I would think that iterating over the items would be the most Pythonic way; but I was also unable to get that to work. I was able to get a recursive parser to work (with the added bonus that this will handle n-levels of nesting).

I got this to work:

from mako.template import Template

template = '''
${handleLevel(pages)}
<%def name="handleLevel(level, depth=0)">
    % if isinstance(level, dict):
            % for item in level:
                % if isinstance(level[item], dict):
                    <!-- print this item for this level -->
                        ${handleLevel(level[item], depth+1)}
                    <!-- end this level (close div or anything that should contain next level -->
                % else:
                    <!-- handle bottom level (linke, or div, etc.) -->
                    ${item}
                    <!-- close any elements for bottom level not already closed -->
                % endif
            % endfor
    % endif
</%def>
'''

nested = {
    'A': {'B': 'C'},
    'D': 'E',
}
page = Template(template).render(pages=nested)
print(page)

If you know you will only ever have one level of nesting, you could probably just do a for loop like:

from __future__ import print_function
from mako.template import Template

template = '''
% for key in data:
    <tr>
        <td>${loop.index + 1}</td>
        <td>${key}</td>
        % for secondKey in data[key]:
            <td>${secondKey}</td>
            <td>${data[key][secondKey]}</td>
        % endfor
    </tr>
% endfor
'''

test = {"name1":{"text":"my text 1", "status":"my status"}, "name2":{"text":"my text 2", "status":"my status"}}
page = Template(template).render(data=test)
print(page)

(tested in Python3 and 2)

Although, now that I've played some more with this, your code works fine for me in Python 2.7.15 and mako version 1.0.7 . . .

mshafer
  • 21
  • 3