您需要遍历clusters 中包含的项目或通过索引引用它,因为它是一个列表。
诀窍是了解 YAML 解析器返回的数据结构以及如何从 Jinja 中访问该结构。
Jinja 表达式大多只是 Python 代码,有一些细微差别。例如,Jinja 提供了一个快捷方式,允许您使用点语法访问字典。通常,在 Python 中,人们会使用mydict['keyname'] 来检索一个值。然而,Jinja 也支持mydict.keyname,实际上它实际上调用了mydict.keyname,但是当它失败时,它会尝试mydict['keyname'] 作为后备。如果两者都失败,则会引发第一个错误,这就是您所看到的 ('list object' has no attribute 'id')。
请注意,clusters 项目包含一个列表(如 - 所示),这就是错误涉及“列表对象”的原因。您无法使用mylist.keyname 或mylist['keyname'] 访问列表中的项目。您要么需要遍历列表,要么通过编号索引引用特定项目(第一项为mylist[0])。除非您确定列表永远不会包含一个以上的项目(在这种情况下,为什么它是一个列表?),否则您可能希望遍历这些项目。
您似乎试图仅包含 id 为 1 的单个项目的数据。如果这始终是列表中的第一项,您可以这样做:servers.clusters.[0].test。但是,如果您不能确定这一点,那么您需要遍历所有项目并将实际语句包装在 if 语句中,该语句检查 id 是否等于先前设置的变量 id。
第一行的IP 列如下:
{% for cluster in servers.clusters %}{% if cluster.id == id %}{{ cluster.test }}{% endif %}{% endfor %}
请注意,cluster.id 引用了 clusters 中项目的键 id。不是{% set id = 1 %}设置的id。但是,可以与它进行比较,如果两者相等(在这种情况下都包含值1),则表达式为 True 并执行其中包含的表达式。当两者不相等时,则忽略。
第二行也有同样的问题。但是,nodes 还包含一个字符串列表。这些项目中没有任何属性,因此您只需在第二个循环中呈现node(而不是node.id、node.ip 和node.fqdn)。因此,我假设你想要这样的东西:
{% for cluster in servers.clusters %}{% if cluster.id == id %}|{% for node in cluster.nodes %} {{ node }} |{% endfor %}{% endif %}{% endfor %}
当然,您可以将所有这些组合在一起,并且只执行一次循环:
{% set id = 1 %}
| | IP | FQDN |
|-------|----|------|
{% for cluster in servers.clusters %}{% if cluster.id == id %}| test | {{ cluster.test }} | |
|{% for node in cluster.nodes %} {{ node }} |{% endfor %}
{% endif %}
{% endfor %}
当然,如果您想将所有 clusters 合并到一个表中,您将删除 if 检查并为每个集群保留一行。但那将是您要求的另一张桌子。
如果您想为每个集群创建一个单独的表,您有几个选择。您可以使用相同的方法并简单地重新定义 id 变量。像这样:
### Cluster 1
{% set id = 1 %}
| | IP | FQDN |
|-------|----|------|
{% for cluster in servers.clusters %}{% if cluster.id == id %}| test | {{ cluster.test }} | |
|{% for node in cluster.nodes %} {{ node }} |{% endfor %}
{% endif %}
{% endfor %}
### Cluster 2
{% set id = 2 %}
| | IP | FQDN |
|-------|----|------|
{% for cluster in servers.clusters %}{% if cluster.id == id %}| test | {{ cluster.test }} | |
|{% for node in cluster.nodes %} {{ node }} |{% endfor %}
{% endif %}
{% endfor %}
请注意,两者之间的唯一区别是前两行:
### Cluster 2
{% set id = 2 %}
其他一切都是一样的。但是如果你只是重复相同的代码,那效率不是很高。未来需要对每个集群进行任何更改。相反,只需将整个事情包装在一个循环中:
{% for cluster in servers.clusters %}
### Cluster {{ cluster.id }}
| | IP | FQDN |
|-------|----|------|
| test | {{ cluster.test }} | |
|{% for node in cluster.nodes %} {{ node }} |{% endfor %}
{% endfor %}
请注意,循环包含了所有内容,包括标题。然后标头获取cluster.id。而且,由于表的主体将针对每个集群重复,我们不需要 if 语句将其限制在一个集群中。
需要注意的是,这种方法只有在每个集群的数据都采用相同的格式/结构时才有效。