如何用Python结合Jinja2模板生成指定结构的YAML文件?
问题描述
我尝试用Python结合Jinja2模板生成YAML文件,当前代码会重复输出完整的name和topology结构,而我需要将所有交换机节点放在同一个nodes节点下。
当前Jinja2模板(eos-test-sb.clab.j2):
name: eos-lab topology: nodes: {{ switch_name }}: kind: ceos image: ceos:4.30.3M binds: - {{ switch_name }}.txt.json:/mnt/flash/EosIntfMapping.json:ro
Python代码:
import yaml import jinja2 i = [{"switch_name": "a"}, {"switch_name": "b"}] template_file = "eos-test-sb.clab.j2" env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath=".")) template = env.get_template(template_file) for device in i: result = template.render(device) print(result)
当前输出:
name: eos-lab topology: nodes: a: kind: ceos image: ceos:4.30.3M binds: - a.txt.json:/mnt/flash/EosIntfMapping.json:ro name: eos-lab topology: nodes: b: kind: ceos image: ceos:4.30.3M binds: - b.txt.json:/mnt/flash/EosIntfMapping.json:ro
期望输出:
name: eos-lab topology: nodes: a: kind: ceos image: ceos:4.30.3M binds: - a.txt.json:/mnt/flash/EosIntfMapping.json:ro b: kind: ceos image: ceos:4.30.3M binds: - b.txt.json:/mnt/flash/EosIntfMapping.json:ro
解决方案
问题核心是你循环渲染了整个完整模板,导致每次输出都重复生成name和topology结构。正确的做法是一次性把所有设备数据传给模板,在模板内部循环生成nodes下的各个节点。
方法1:修改Jinja2模板,支持设备列表
更新模板文件eos-test-sb.clab.j2,使用Jinja2的循环语法遍历设备列表:
name: eos-lab topology: nodes: {% for device in devices %} {{ device.switch_name }}: kind: ceos image: ceos:4.30.3M binds: - {{ device.switch_name }}.txt.json:/mnt/flash/EosIntfMapping.json:ro {% endfor %}
修改Python代码,将整个设备列表作为参数传给模板:
import jinja2 devices = [{"switch_name": "a"}, {"switch_name": "b"}] template_file = "eos-test-sb.clab.j2" env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath=".")) template = env.get_template(template_file) # 将设备列表以变量名devices传入模板 result = template.render(devices=devices) print(result)
方法2:拆分模板,先渲染节点再拼接(可选)
如果不想修改原模板结构,可以拆分模板实现:
- 创建单个节点的模板
node_template.j2:
{{ switch_name }}: kind: ceos image: ceos:4.30.3M binds: - {{ switch_name }}.txt.json:/mnt/flash/EosIntfMapping.json:ro
- 修改Python代码,先渲染所有节点再拼接成完整YAML:
import jinja2 devices = [{"switch_name": "a"}, {"switch_name": "b"}] # 加载节点模板 node_template = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath=".")).get_template("node_template.j2") # 渲染所有节点并拼接 nodes_content = "\n".join([node_template.render(device) for device in devices]) # 组合完整YAML内容 full_yaml = f"""name: eos-lab topology: nodes: {nodes_content}""" print(full_yaml)
两种方法都能得到期望的输出,推荐方法1,更符合Jinja2的模板设计逻辑,维护成本更低。
内容的提问来源于stack exchange,提问作者kryton007
相关产品推荐
相关产品推荐

