【问题标题】:Creating a data structure in python for use in a Jinja2 template在 python 中创建用于 Jinja2 模板的数据结构
【发布时间】:2014-02-04 11:26:16
【问题描述】:

我想使用 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 模板中进行迭代。

【问题讨论】:

  • Jinja2 不应该成为您决定是否使用列表或字典的驱动因素 - 它可以同样轻松地与任何一个一起使用。
  • @lanzz 这是一个很好的观点,当然你是对的。我只是不确定构建数据的最佳/最常见方式。

标签: python html csv jinja2


【解决方案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 属性是所有具有相同 @987654331 的值的序列@ 或 City 值。

然后,您需要生成的只是一系列字典; 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 示例一样。

【讨论】:

  • 谢谢 Martijn。在您的模板示例的第 11 行,我认为您需要有 {% endfor %}。我应该将csv.DictReader 传递给template.redner() 吗?
  • @ajt:是的,只需传入DictReader() 对象。模板标签已更正,对此感到抱歉。
  • Martijn:这给了我错误ValueError: dictionary update sequence element #0 has length 4; 2 is required。感谢您的所有帮助。
  • @ajt:我刚刚查看了groupby() 过滤器源,我发现它还为您对输入进行了排序(文档可能需要提及)。
  • @ajt:您在代码中的哪个位置更新字典?这是dict.update() 抛出的异常,我的示例代码中没有任何内容更新字典。
猜你喜欢
  • 2014-05-27
  • 2017-02-14
  • 2022-07-11
  • 2016-07-17
  • 1970-01-01
  • 2020-11-17
  • 2013-08-13
  • 1970-01-01
  • 2019-02-18
相关资源
最近更新 更多