如何使用Jinja2模板引擎生成JSON

9
我将尝试从.xlsx文件生成一个json文件。
到目前为止,我已经能够从文件中获取数据,但是我不确定如何使用jinja2将它们放在json中。模板结构存在问题,我该如何解决?
输出应该像这样:
  "Matches": {    
    "1": {
      "time": "19:00",
      "teams": "Team 1 - Team 2"
    },
    "2": {
      "time": "21:00",
      "teams": "Team 3 - Team 4"
    },
    ...
    ...
    ...
  }

我的代码大概是这样的。显然模板部分有误。

from openpyxl import load_workbook
from jinja2 import Template


start_coloumn_of_matches = 3
end_coloumn_of_matches = 20

wb = load_workbook(filename = 'myfile.xlsx')
sheet_ranges = wb['Sheet1']

keys = []
teams = []
times = []


for x in range(start_coloumn_of_matches, end_coloumn_of_matches + 1):
    team_column = 'A' + str(x)
    time_column = 'D' + str(x)
    teams.append(sheet_ranges[team_column].value)
    times.append(sheet_ranges[time_column].value)
    keys.append(x)



template = Template(''' 
"Matches": {
        {% for key in keys %}
      "{{key}}": 
        {% endfor %}
      {
        {% for team in teams %}
        "teams": "{{team}}",
        {% endfor %}
        {% for time in times %}
        "time": "{{time}}"
        {% endfor %}
        }

    }, 

    ''' )

print(template.render(teams = teams, times = times, keys = keys))
3个回答

13

手动构建JSON有可能会不小心生成一个无效的JSON字符串。使用工具来完成这个任务更加安全,同时也能使你的模板更加简洁。

如果你正在使用Jinja 2.9或更高版本,则可以使用内置的tojson过滤器,自动将Python对象*转换为JSON。

>>> import pprint

>>> # Construct some test data
>>> matches = ['1', '2', '3']
>>> times = ['19:00', '21:00', '23:00']
>>> teams = ['Team 1 - Team 2', 'Team 3 - Team 4', 'Team 5 - Team 6']

>>> # Combine the data structures to match the required output
>>> match_data = [dict(zip(['time', 'team'], pair)) for pair in zip(times, teams)]
>>> combined = {x: y for x, y in zip(matches, match_data)}
>>> pprint.pprint(combined)
{'1': {'team': 'Team 1 - Team 2', 'time': '19:00'},
 '2': {'team': 'Team 3 - Team 4', 'time': '21:00'},
 '3': {'team': 'Team 5 - Team 6', 'time': '23:00'}}

>>> template = jinja2.Template("""{{ matches | tojson(indent=2) }}""")
>>> print(template.render(matches=combined))
{
  "1": {
    "team": "Team 1 - Team 2",
    "time": "19:00"
  },
  "2": {
    "team": "Team 3 - Team 4",
    "time": "21:00"
  },
  "3": {
    "team": "Team 5 - Team 6",
    "time": "23:00"
  }
}

对于早期的Jinja版本,请使用 Python 标准库中的 json 包构造 json,然后在您的模板中呈现该 json。

>>> import json    
>>> # Serialise our object as json; setting the indent argument gives
>>> # the pretty printed format that we want.
>>> jdata = json.dumps(combined,  indent=2) 
>>> print(jdata)
{
  "1": {
    "time": "19:00",
    "team": "Team 1 - Team 2"
  },
  "2": {
    "time": "21:00",
    "team": "Team 3 - Team 4"
  },
  "3": {
    "time": "23:00",
    "team": "Team 5 - Team 6"
  }
}

>>> # Pass the json to the template for rendering.
>>> template = jinja2.Template("""{{ matches }}""")
>>> print(template.render(matches=jdata))
{
  "1": {
    "time": "19:00",
    "team": "Team 1 - Team 2"
  },
  "2": {
    "time": "21:00",
    "team": "Team 3 - Team 4"
  },
  "3": {
    "time": "23:00",
    "team": "Team 5 - Team 6"
  }
}

据我所知,此过滤器仅处理原始数据类型(primitives); 如果您的数据包括日期时间类型,例如,您需要先将它们转换为字符串。


1
加一下前两句话:不要使用jinja2生成json。更好的做法是不要使用jinja2来生成JSON。 - Uri London
2
除了在直接使用Python不可行的情况下,例如在Ansible中,@Uri并没有什么帮助... - Gert van den Berg

1
我发现了一个Gist,fork它并进行了一些微小的修改以适应Python 3.x的兼容性,结果完美地运行了。

https://gist.github.com/jerrydboonstra/bedb5ccbe6200b5d794447ed38aeb342

它有一个名为example.json的文件,其中包含“{{ variable }}”标记作为模板,以及一个名为runner.py的文件,该文件从模板和输入数据结构组合输出。

enter image description here


1
我找到了答案。将列表压缩到“matches”变量中,并像这样构建模板:
template = Template(''' 
"Matches": {
        {% for key, team, time in matches %}
      "{{key}}": 
      {
        "teams": "{{team}}",
        "time": "{{time}}"
        },
            {% endfor %}
    }
    ''' )


print(template.render(matches=zip(keys, teams, times)))

这会产生无效的JSON,因为外部字典中的最后一项也有逗号。这就是为什么snakecharmerb在他的回答中建议使用转换工具来生成JSON的原因。 - Andreas Maier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接