在python中创建数据结构以在Jinja2模板中使用

时间:2014-02-04 11:26:17

标签: python html csv jinja2

我想使用python读取CSV数据,然后使用Jinja2输出它来制作平面文件HTML报告。我想使用的CSV数据如下:

State,City,Issue,Date
Michigan,Detroit,Economic Issues,12/11/14
Michigan,Detroit,Poor Schools,12/11/14
Michigan,Battle Creek,Economic Issues,2/12/14
Georgia,Atlanta,Lack of Transit,2/12/14
Georgia,Atlanta,Traffic,2/12/14
Georgia,Cummings,Economic Issues,12/11/14
Georgia,Cummings,Poor Schools,12/11/14
Georgia,Athens,Traffic,12/11/14
Florida,Miami,Weather Issues,12/11/14
Florida,Miami,Poor Schools,2/12/14
Florida,Miami,Economic Issues,2/12/14
Florida,Miami,Lack of Transit,2/12/14
Florida,Sarasota,Economic Issues,2/12/14
Florida,Levy,Poor Schools,2/12/14
Florida,Lee,Traffic,2/12/14
California,Los Angeles,Traffic,12/11/14
Alaska,Anchorage,Weather Issues,2/12/14

我希望每个州都有一行,然后每个州都有相关的问题和日期。

输出类似于:

Michigan
        Detroit        Economic Issues        12/11/2014
                       Poor Schools           12/11/2014
        Battle Creek   Economic Issues        02/12/2014
Georgia
        Atlanta        Lack of Transit        02/12/2014
                       Traffic                02/12/2014
        Cummings       Economic Issues        12/11/2014

我喜欢使用Jinja2并为此数据的输出创建模板。我的问题是,我不确定构建此数据然后移交给模板的最佳方法。

我应该创建一个国家字典,每个城市,问题和日期信息都是一个列表吗?它应该只是一个列表清单吗?我对数据结构的外观非常困惑,因此我可以轻松地在Jinja2模板中进行迭代。

1 个答案:

答案 0 :(得分:1)

您可以使用groupby() filter

将序列分组到模板中
<table>
{% for state in csvrows|groupby('State') %}
    <tr><td rowspan="4">{{ state.grouper }}</td></tr>
    {% for city in state.list|groupby('City') %}
        {% for row in city.list %}
            <tr>
                <td>{% if loop.first %}{{ row.City }}{% endif %}</td>
                <td>{{ row.Issue }}</td>
                <td>{{ row.Date }}</td>
            </tr>
        {% endfor %}
    {% endfor %}
{% endfor %}
</table>

groupby()过滤器生成组对象,每个对象都具有listgrouper属性。后者是构建组的值(因此外部循环中的State值,下一循环中的City),.list属性是值的序列都具有相同的StateCity值。

然后你需要生成的是一系列字典; groupby()过滤器甚至可以为您排序数据。只需将一个csv.DictReader()对象传递给Jinja2,就可以了。

Jinja中的groupby()过滤器几乎与itertools.groupby() function完全相同,您可以使用一些打印语句生成相同的所需输出:

>>> from itertools import groupby
>>> from operator import itemgetter
>>> state_key = itemgetter('State')
>>> for state, cities in groupby(sorted(rows, key=state_key), state_key):
...     print state
...     city_key = itemgetter('City')
...     for city, group in groupby(sorted(cities, key=city_key), city_key):
...         print '\t', city
...         for row in group:
...             print '\t\t', row['Issue'], row['Date']
... 
Alaska
    Anchorage
        Weather Issues 2/12/14
California
    Los Angeles
        Traffic 12/11/14
Florida
    Lee
        Traffic 2/12/14
    Levy
        Poor Schools 2/12/14
    Miami
        Weather Issues 12/11/14
        Poor Schools 2/12/14
        Economic Issues 2/12/14
        Lack of Transit 2/12/14
    Sarasota
        Economic Issues 2/12/14
Georgia
    Athens
        Traffic 12/11/14
    Atlanta
        Lack of Transit 2/12/14
        Traffic 2/12/14
    Cummings
        Economic Issues 12/11/14
        Poor Schools 12/11/14
Michigan
    Battle Creek
        Economic Issues 2/12/14
    Detroit
        Economic Issues 12/11/14
        Poor Schools 12/11/14

这是直接从您的样本CSV数据生成的;过滤器也应用排序,就像上面的python示例一样。