【问题标题】:Variable usage in jinja2 inside markdown templatemarkdown 模板中 jinja2 中的变量使用
【发布时间】:2021-04-22 21:46:00
【问题描述】:

我正在尝试使用 jinja 创建 Markdown 文件的模板,并且变量的值存储在 .yml 文件中(一种主机清单)。

我的问题是我认为我试图填写的降价表并不容易,因为我已经尝试了许多使用 jinja2 工具和功能的替代方案,但仍然没有成功,我正在向社区解决这个问题,希望获得一些解决问题的见解或提示:

我的降价文件包含如下表:

## Servers

### Cluster 1
|       | IP | FQDN |
|-------|----|------|
|       |    |      |

我的值文件.yml如下:

servers:
  clusters:
    - id: 1
      test: X.X.X.X
      nodes:
        - X.X.X.X
        - X.X.X.X
        - X.X.X.X

为了检索正确的值来填充表格,我写了这个:

{% set id = 1 %}
|       | IP | FQDN |
|-------|----|------|
|  test  | {{servers.clusters.id.test}} |      |
{% for node in servers.clusters.id.nodes %}|node{{node.id}}|{{node.ip}}|{{node.fqdn}}|
{% endfor %} 

但它似乎不起作用并且错误不是很明确(当然对于 jinja2 初学者):

File "[PATH]/filename.md", line 34, in top-level template code
    |  test  | {{server.clusters.id.test}} |      |
  File "/usr/lib/python3.8/site-packages/jinja2/environment.py", line 471, in getattr
    return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'list object' has no attribute 'id'

欢迎所有建议。

【问题讨论】:

    标签: jinja2 markdown templating jinja2-cli


    【解决方案1】:

    您需要遍历clusters 中包含的项目或通过索引引用它,因为它是一个列表。

    诀窍是了解 YAML 解析器返回的数据结构以及如何从 Jinja 中访问该结构。

    Jinja 表达式大多只是 Python 代码,有一些细微差别。例如,Jinja 提供了一个快捷方式,允许您使用点语法访问字典。通常,在 Python 中,人们会使用mydict['keyname'] 来检索一个值。然而,Jinja 也支持mydict.keyname,实际上它实际上调用了mydict.keyname,但是当它失败时,它会尝试mydict['keyname'] 作为后备。如果两者都失败,则会引发第一个错误,这就是您所看到的 ('list object' has no attribute 'id')。

    请注意,clusters 项目包含一个列表(如 - 所示),这就是错误涉及“列表对象”的原因。您无法使用mylist.keynamemylist['keyname'] 访问列表中的项目。您要么需要遍历列表,要么通过编号索引引用特定项目(第一项为mylist[0])。除非您确定列表永远不会包含一个以上的项目(在这种情况下,为什么它是一个列表?),否则您可能希望遍历这些项目。

    您似乎试图仅包含 id1 的单个项目的数据。如果这始终是列表中的第一项,您可以这样做: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.idnode.ipnode.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 语句将其限制在一个集群中。

    需要注意的是,这种方法只有在每个集群的数据都采用相同的格式/结构时才有效。

    【讨论】:

    • 非常感谢您的时间和对这个问题的洞察力它确实解决了整个问题并且对您的解释非常有用现在我正确检索了第一个集群的值第二个集群一张不同的桌子仍然让我头疼,但我仍在努力寻找解决方案。
    • 如果这回答了您的问题,那么您可以通过点击上面的“接受”来接受答案。
    • 我添加了一些额外的信息来处理更多的集群。
    • 嘿@Waylan 它确实帮助我解决了主要问题,我很感激我的另一个问题我相信是纯粹的降价,因为我的所有桌子都按预期填满,除了一个仍在处理它,是的,我将接受答案再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多