I want to traverse list, and for each element of the list I have to traverse respective element of the other list of lists in jinja2.
The lists:
devices=["device1","device2","device3"]
device_ports=[["device1port1","device1port2"],["device2port1","device2port2"],["device3port1","device3port2"]]
Jinja Template:
{% for device,device_port in devices,device_ports %}
{% for port in device_port %}
{{device}} {{port}}
{% endfor %}
{% endfor %}
Expected Template Output:
device1 device1port1
device1 device1port2
device2 device2port1
device2 device2port2
device3 device3port1
device4 device4port2
Error:
ValueError: too many values to unpack (expected 2)
It's better to use indexing here. You can easily access current item index in the loop and perform traversing you're looking for:
{% for device in devices %}
{% for port in device_ports[loop.index0] %}
{{device}} {{port}}
{% endfor %}
{% endfor %}
loop.index0 here is an index of the current item in devices (i. e. device) and you can use this index to access corresponding item from the device_ports.
Related
In my Jinja template, model.DataType value can be user defined or built in. My requirenement is if model.DataType start with the three letters ARR, then do a specific operation.
Example of values:
ARRstruct124
ARR_int123
ARR123123
CCHAR
UUINT
etc.
{% set evenDataType = model.eventDataType %}
{%if evenDataType | regex_match('^ARR', ignorecase=False) %}
// do the operation
{%else%}
// do the operation
{% endif %}
With this template, I am getting the error
{%if evenDataType | regex_match('^ARR', ignorecase=False) %}
jinja2.exceptions.TemplateAssertionError: no filter named 'regex_match'
There is indeed no regex_match filter in the Jinja builtin filters. You might have found some examples using it, but this is an additional filter provided by Ansible, so it won't work outside of Ansible.
This said, your requirement does not need a regex to be fulfilled, you can use the startswith() method of a Python string.
So, you template should be:
{% set evenDataType = model.eventDataType %}
{% if evenDataType.startswith('ARR') %}
`evenDataType` starts with 'ARR'
{% else %}
`evenDataType` does not starts with 'ARR'
{% endif %}
I'm trying to make a template which iterates over a list to check if a string exists. if it does then something happens, if the string isn't in the list, something else should happen. The issue is the result is repeated for all the lines in the list, which i do not want.
e.g.
The list is some simple yaml
LIST:
- A
- B
- C
Jinja looks like
{% for line in mylist %}
{% if 'A' in line %}
{{ A }} Was found in the list
{% else %}
{{ A }} Was not found
{% endif %}
{% endfor %}
So when 'A' matches i get this
A Was found in the list
A Was not found
A Was not found
And when 'A' does not match i get this:
A Was not found
A Was not found
A Was not found
Basically i need to stop it iterating over the list and just do one thing if it matches or one thing if it doesn't match
So if 'A' matches i need it to just do
A was found
If 'A' doesn't match i need it to just do A was not found
Use some kind of flag variable:
{% set ns = namespace(found=false) %}
{% for line in mylist %}
{% if 'A' in line %}
{% set ns.found=true %}
{% endif %}
{% endfor %}
{% if ns.foo %}
{{ A }} Was found in the list
{% else %}
{{ A }} Was not found
{% endif %}
At its most basic level I need to append a partial object path onto an existing object path. In this particular instance I can't use plugins.
Say you have an object path:
{{ site.data.grants.2015.Return.ReturnHeader.ReturnTypeCd }}
Which, of course, can also be referenced as follows:
{% assign var = "ReturnTypeCd" %}
{{ site.data.grants.2015.Return.ReturnHeader[var] }}
How would I go about adding additional levels of nesting to the variable?
{% assign xTest = "Return.ReturnHeader.ReturnTypeCd" %}
{{ site.data.grants.2015[xTest] }}
//does not work
I've played around with both dot and bracket notations and using append as well as capture, but can't seem to find a solution that works.
This works :
Data file is _data/grants.yml
"2015":
Return:
ReturnHeader:
ReturnTypeCd: "Et hop !"
Getting deep target with a "dotted" string :
{% assign dataPath = site.data.grants.2015 %}
{% assign target = "Return.ReturnHeader.ReturnTypeCd" %}
{% comment %} ++++ Transform target string to an array {% endcomment %}
{% assign labels = target | split:"." %}
{% comment %} ++++
Looping in labels array and reassigning dataPath on each loop.
This goes deeper and deeper in the data tree
++++ {% endcomment %}
{% for label in labels %}
<h2>Label : {{ label }}</h2>
{% assign dataPath = dataPath[label] %}
<p>dataPath : {{ dataPath }}</p>
{% endfor %}
I'd like to iterate over a set of objects and find the maximum of one particular attribute, however jinja2 ignores any action within an iterator on a variable declared outside of the iterator. For example:
{% set maximum = 1 %}
{% for datum in data %}
{% if datum.frequency > 1 %}
{% set maximum = datum.frequency %}
{% endif %}
{% endfor %}
{# maximum == 1 #}
datum.frequency is definitely greater than 1 for some datum in data.
EDIT (solution)
This is similar to this post, but there's a bit more to it. The following works and is very ugly.
{% set maximum = [1] %}
{% for datum in data %}
{% if datum.freq > maximum[-1] %}
{% if maximum.append( datum.freq ) %}{% endif %}
{% endif %}
{% endfor %}
{% set maximum = maximum[-1] %}
Have you considered writing a custom filter to return the highest value of a particular attribute within your collection? I prefer to minimize the amount of logic I use in Jinja2 templates as part of maintaining a 'separation of concerns'.
Here is a link to a very good example of how one can be written in python:
Custom jinja2 filter for iterator
Once you have your filter returning the value you need access it by using '|' like so:
{% set maximum = datum|filtername %}
I have a Jekyll app (using Liquid) and I'd like to know how to, in Liquid, group a collection of items into a small subset of collections.
For instance, pretend I have this array:
fruits = ['apples', 'oranges', 'bananas', 'pears', 'grapes']
What I'd really like to do, in the Liquid page, is get this:
fruit_groups = [['apples', 'oranges'], ['bananas', 'pears'], ['grapes', null]]
For example, Ruby on Rails can do this with their .group_by method attached to enumerables.
Can I do this in Liquid?
Use case: I have a big collection of items, but I need to convert them into columns of <ul> elements. So, if I have three columns, I need to get three sub-collections.
Thanks!
This doesn't answer your question directly, but I'm not sure that you'd want to do what you're describing (and I'm pretty sure you can't) - Liquid is a templating system, not a fully fledged programming language. I suspect that you'll be able to achieve your end goal using some of the for loop and cycle features: http://code.google.com/p/liquid-markup/wiki/UsingLiquidTemplates
eg:
<ul>
{% for fruit in fruits %}
{% capture pattern %}{% cycle 'odd_class', 'even_class' %}{% endcapture %}
<li class={{ pattern }}>{{ fruit }}</li>
{% endfor %}
</ul>
or
<ul class="odd">
{% for fruit in fruits %}
{% capture pattern %}{% cycle 'odd', 'even' %}{% endcapture %}
{% if pattern == 'odd' %}
<li>{{ fruit }}</li>
{% endif%}
{% endfor %}
</ul>
<ul class="even">
{% for item in fruits %}
{% capture pattern %}{% cycle 'odd', 'even' %}{% endcapture %}
{% if pattern == 'even' %}
<li>{{ fruit }}</li>
{% endif%}
{% endfor %}
</ul>
If you have three columns, you'd just have three steps in your cycle, and three directions to go in your if statement.
If all that fails, you could write a plugin (in Ruby) that will restructure your data before it ever hits the template layer, but I suspect that would be overkill.