您需要遍历其中包含的项目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
is包含单个项目的数据1
。如果这将始终是列表中的第一项,您可以这样做servers.clusters.[0].test
:但是,如果您不能确定这一点,那么您将需要遍历所有项目并将实际语句包装在 if 语句中,该语句检查 id 是否等于先前的 set variable id
。
像这样IP
的第一行的列:
{% for cluster in servers.clusters %}{% if cluster.id == id %}{{ cluster.test }}{% endif %}{% endfor %}
请注意,cluster.id
它引用了id
中的项目的键clusters
。它不是由id
设置的{% set id = 1 %}
。但是,可以与它进行比较,如果两者相等(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 语句将其限制在一个集群中。
需要注意的是,这种方法只有在每个集群的数据都采用相同的格式/结构时才有效。