【问题标题】:Jinja - How to pass on dynamic range to an expression?Jinja - 如何将动态范围传递给表达式?
【发布时间】:2022-11-23 16:53:53
【问题描述】:

我有一个 csv 文件,我正在使用 Ansible read_csv 将其作为字典阅读

id,name,quantity,type
1,apple,10,fruit
2,orange,20,fruit
3,carrot,5,veg
4,beetroot,2,veg
5,onion,3,veg
6,tomato,4,both
7,pear,4,fruit
8,banana,6,fruit
9,persimon,4,fruit
10,guava,4,fruit
11,pepper,4,veg
12,potato,5,veg
13,cherry,5,fruit

等价的字典变成

"{'1': {'id': '1', 'name': 'apple', 'quantity': '10', 'type': 'fruit'}, '2': {'id': '2', 'name': 'orange', 'quantity': '20', 'type': 'fruit'}, '3': {'id': '3', 'name': 'carrot', 'quantity': '5', 'type': 'veg'}, '4': {'id': '4', 'name': 'beetroot', 'quantity': '2', 'type': 'veg'}, '5': {'id': '5', 'name': 'onion', 'quantity': '3', 'type': 'veg'}, '6': {'id': '6', 'name': 'tomato', 'quantity': '4', 'type': 'both'}, '7': {'id': '7', 'name': 'pear', 'quantity': '4', 'type': 'fruit'}, '8': {'id': '8', 'name': 'banana', 'quantity': '6', 'type': 'fruit'}, '9': {'id': '9', 'name': 'persimon', 'quantity': '4', 'type': 'fruit'}, '10': {'id': '10', 'name': 'guava', 'quantity': '4', 'type': 'fruit'}, '11': {'id': '11', 'name': 'pepper', 'quantity': '4', 'type': 'veg'}, '12': {'id': '12', 'name': 'potato', 'quantity': '5', 'type': 'veg'}, '13': {'id': '13', 'name': 'cherry', 'quantity': '5', 'type': 'fruit'}}"

我的逻辑是将列表分成批次,每次 2 个名称 所以我要找的输出是["carrot", "beetroot"], ["onion", "pepper"]等等

当我在 jinja 表达式中对 [0:2] 范围进行硬编码时,以下逻辑完美运行

{% set my_fruit_list = [] %}
{%- for item in (fruits_dict.dict| dict2items | selectattr("value.type", "match", "^veg$"))[0:2]  -%}
{{ my_fruit_list.append(item.value.name) }}
{%- endfor -%}
my_list=["{{ my_fruit_list|join('", "') }}"]

但是当我尝试将其更改为动态变量时,它不起作用。我在下面试过

{% set input_range = "[0:2]" %}
{%- for item in (fruits_dict.dict| dict2items | selectattr("value.type", "match", "^veg$"))input_range  -%}

有什么办法可以将“input_range”作为动态参数传递给表达式吗?

还有没有更好的方法来获取 selectattr 而无需将 csv 转换为 dictdict2items

【问题讨论】:

标签: ansible jinja2


【解决方案1】:

简而言之:

{% set my_fruit_list = [] %}
{% set fruit_start = 0 %}
{% set fruit_end = 1 %}
{%- for item in (fruits_dict.dict| dict2items | selectattr("value.type", "match", "^veg$"))[fruit_start:fruit_end]  -%}
{{ my_fruit_list.append(item.value.name) }}
{%- endfor -%}
my_list=["{{ my_fruit_list|join('", "') }}"]

【讨论】:

    【解决方案2】:

    鉴于文件

    shell> cat /tmp/fruits.csv 
    id,name,quantity,type
    1,apple,10,fruit
    2,orange,20,fruit
    3,carrot,5,veg
    4,beetroot,2,veg
    5,onion,3,veg
    6,tomato,4,both
    7,pear,4,fruit
    8,banana,6,fruit
    9,persimon,4,fruit
    10,guava,4,fruit
    11,pepper,4,veg
    12,potato,5,veg
    13,cherry,5,fruit
    

    读取文件并通过键创建字典ID

        - read_csv:
            path: /tmp/fruits.csv
            key: id
          register: fruits
    

      fruits.dict:
        '1': {id: '1', name: apple, quantity: '10', type: fruit}
        '10': {id: '10', name: guava, quantity: '4', type: fruit}
        '11': {id: '11', name: pepper, quantity: '4', type: veg}
        '12': {id: '12', name: potato, quantity: '5', type: veg}
        '13': {id: '13', name: cherry, quantity: '5', type: fruit}
        '2': {id: '2', name: orange, quantity: '20', type: fruit}
        '3': {id: '3', name: carrot, quantity: '5', type: veg}
        '4': {id: '4', name: beetroot, quantity: '2', type: veg}
        '5': {id: '5', name: onion, quantity: '3', type: veg}
        '6': {id: '6', name: tomato, quantity: '4', type: both}
        '7': {id: '7', name: pear, quantity: '4', type: fruit}
        '8': {id: '8', name: banana, quantity: '6', type: fruit}
        '9': {id: '9', name: persimon, quantity: '4', type: fruit}
    

    1. 获取值并将它们分组类型
        by_type: "{{ fruits.dict.values()|groupby('type') }}"
      

        by_type:
          - - both
            - - {id: '6', name: tomato, quantity: '4', type: both}
          - - fruit
            - - {id: '1', name: apple, quantity: '10', type: fruit}
              - {id: '2', name: orange, quantity: '20', type: fruit}
              - {id: '7', name: pear, quantity: '4', type: fruit}
              - {id: '8', name: banana, quantity: '6', type: fruit}
              - {id: '9', name: persimon, quantity: '4', type: fruit}
              - {id: '10', name: guava, quantity: '4', type: fruit}
              - {id: '13', name: cherry, quantity: '5', type: fruit}
          - - veg
            - - {id: '3', name: carrot, quantity: '5', type: veg}
              - {id: '4', name: beetroot, quantity: '2', type: veg}
              - {id: '5', name: onion, quantity: '3', type: veg}
              - {id: '11', name: pepper, quantity: '4', type: veg}
              - {id: '12', name: potato, quantity: '5', type: veg}
      
      1. 创建字典
        my_dict: "{{ dict(by_type|map('first')|list|
                          zip(by_type|map('last')|
                                      map('map', attribute='name')|list)) }}"
      

        my_dict:
          both: [tomato]
          fruit: [apple, orange, pear, banana, persimon, guava, cherry]
          veg: [carrot, beetroot, onion, pepper, potato]
      
      1. 创建项目的批次。在哪里类型输入范围是参数
          my_list: |
            {% for batch in my_dict[type]|batch(input_range|int) %}
              - {{ batch }}
            {% endfor %}
      

      例如下面的循环

          - debug:
              msg: "{{ my_list }}"
            loop: "{{ my_dict.keys()|list }}"
            vars:
              type: "{{ item }}"
      

      对于input_range=2 给出

      TASK [debug] **************************************************************
      ok: [localhost] => (item=both) => 
        msg: |2-
            - ['tomato']
      ok: [localhost] => (item=fruit) => 
        msg: |2-
            - ['apple', 'orange']
            - ['pear', 'banana']
            - ['persimon', 'guava']
            - ['cherry']
      ok: [localhost] => (item=veg) => 
        msg: |2-
            - ['carrot', 'beetroot']
            - ['onion', 'pepper']
            - ['potato']
      

      对于input_range=3 给出

      TASK [debug] **************************************************************
      ok: [localhost] => (item=both) => 
        msg: |2-
            - ['tomato']
      ok: [localhost] => (item=fruit) => 
        msg: |2-
            - ['apple', 'orange', 'pear']
            - ['banana', 'persimon', 'guava']
            - ['cherry']
      ok: [localhost] => (item=veg) => 
        msg: |2-
            - ['carrot', 'beetroot', 'onion']
            - ['pepper', 'potato']
      
      1. 创建特定列表
          - set_fact:
              my_list_veg: "{{ my_list }}"
            vars:
              type: veg
              input_range: 3
          - debug:
              var: my_list_veg
      

        my_list_veg:
            - ['carrot', 'beetroot', 'onion']
            - ['pepper', 'potato']
      

      用于测试的完整剧本示例

      shell> cat pb.yml
      - hosts: localhost
        vars:
          input_range: 2
          by_type: "{{ fruits.dict.values()|groupby('type') }}"
          my_dict: "{{ dict(by_type|map('first')|list|
                            zip(by_type|map('last')|
                                        map('map', attribute='name')|list)) }}"
          my_list: |
            {% for batch in my_dict[type]|batch(input_range|int) %}
              - {{ batch }}
            {% endfor %}
            
        tasks:
          - read_csv:
              path: /tmp/fruits.csv
              key: id
            register: fruits
          - debug:
              var: fruits.dict|to_yaml
          - debug:
              var: by_type|to_yaml
          - debug:
              var: my_dict|to_yaml
      
          - debug:
              msg: "{{ my_list }}"
            loop: "{{ my_dict.keys()|list }}"
            vars:
              type: "{{ item }}"
      
          - set_fact:
              my_list_veg: "{{ my_list }}"
            vars:
              type: veg
              input_range: 3
          - debug:
              var: my_list_veg
      

      你可以覆盖输入范围从命令行,例如

      shell> ansible-playbook pb.yml -e input_range=3
      

    【讨论】:

      猜你喜欢
      • 2021-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-25
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      相关资源
      最近更新 更多