Combining two variables for use in Twig - html

I'm using Google app engine and I'm trying to set the value of a textarea based on the concatenation of two string variables. Let's say I have 4 items, and each item has multiple fields. So in my Python I'm passing the dictionary { 'value0': newValue }. I'm using a for loop (iterator value num) and I want to use in my HTML something equivalent to {{ value }}{{ num }} where the variable referenced is value0.
I've tried {{ value~num }} but nothing works. If I could use an array that would be even better - such as {{ value[num] }}

Related

How to pass variable while calling macros in post hook?

Currently I am calling macros in such a way:
"post_hook":["{{macros_append('string1','string2')}}"]})}}
I want to call it as
"post_hook":["{{macros_append(var1,var2)}}"]})}}
I have already tried setting variable before config like
{% set var1='value' %}
"post_hook":["{{macros_append(var1,var2)}}"]})}}
But this does not work. It does not take any value while calling macros.
This doesn't work because dbt is parsing the jinja of your post-hook in a different context from the model file. In short, the post-hook needs to stand on its own.
This is true of all configs. The hints are:
post_hook takes a list of strings. Those strings later get templated by the jinja templater. (this is why you quote them and nest the curlies! you should never really nest curlies otherwise)
Configs can also get passed in through .yml files, etc., which is partially why the templating is deferred
Your question omits the actual call to the config macro, which makes this a little more clear:
{{
config({
"post_hook": ["{{macros_append('string1','string2')}}"]
})
}}
So what are we to do? You could use jinja to build the string that gets passed into the config block. This is hacky and ugly, but it works:
(Note that ~ is the jinja string concatenation operator.)
{% set var1 = "string1" %}
{% set var2 = "string2" %}
{{
config({
"post_hook": ["{{ macros_append(" ~ var1 ~ "," ~ var2 ~ ") }}"]
})
}}
A slightly cleaner version of this would be to define the whole macro call in a variable, so you don't have to do the concatenation:
{% set my_hook = "{{ macros_append('string1', 'string2') }}" %}
{{
config({
"post_hook": [my_hook]
})
}}
A Better Way
Another option is to use the var() macro, which allows you to access a global variable in the jinja context. You define these global variables in your dbt_project.yml file:
...
vars:
var1: string1
var2: string2
and then you can access them with {{ var('var1') }} from any process that is templating jinja. In the case of your config block, that would look like:
{{
config({
"post_hook": ["{{ macros_append(var('var1'), var('var2')) }}"]
})
}}
Note that the post-hook here is just a string that contains the string "var('var1')", but that's fine, since the templater will fill that in later, when the string is templated.

Creating list of ip's in ansible using given range within jinja template

i want to generate a list of ip addresses (using range of last 8bits so 120-190 translates to x.x.x.120 - x.x.x.190) in defaults/main.yml in my role, and later use it to create new network interfaces and generate a new config file. I tried this approach:
defaults/main.yml:
ip_list: "{%for address_end in range(50,99)%} 192.168.0.{{address_end}}{%endfor%}"
conf_list: "{%for ip in ip_list%}server {{ip}}:6666 {%endfor%}"
and then to use it in template
template.conf.j2:
{% for conf_line in conf_list %}
{{conf_line}}
{% endfor %}
and all i got in generated config file was:
s
e
r
v
e
r
:
6
6
6
6
s
e
r
v
e
r
1
:
6
so my guess is that i'm not generating a list but just a long string and when I use for loop in template.conf.j2 I iterate over single chars. I tried using answer to this problem but all i got was syntax error. Any ideas for what might help me ?
You should format your vars as JSON lists if you want them to be lists.
1.1.1.1 2.2.2.2 3.3.3.3 is a string.
['1.1.1.1', '2.2.2.2', '3.3.3.3'] will be converted to list.
But there is alternative approach for you:
ip_list: "{{ lookup('sequence', 'start=50 count=12 format=192.168.0.%d', wantlist=True) }}"
conf_list: "{{ ip_list | map('regex_replace','(.*)','server \\1:6666') | list }}"
Kostantin answer was of much help, but i found just realized that generating config entries in my case could be solved in an less complex way. Instead of trying to iterate over list or a string variable variable in jinja template file template.conf.j2 like did with :
{% for conf_line in conf_list %}
{{conf_line}}
{% endfor %}
you could just enter insert new line signs while generating string in defaults/main.yml:
conf_list: "{%for ip in ip_list%}server {{ip}}:6666\n{%endfor%}"
and then just insert that whole string into a template.conf.j2 like this:
{{conf_line}}
nevertheless i have no other idea how to generate list of ip addresses other than the one Konstantin proposed.

Call a constructed variable name in Jinja2 template?

Is there a way in Jinja2 to construct a variable name and then call it? I want to do something like this:
{% for type in ('Students', 'Faculty', 'Groups') %}
{% set import_name = 'latest_' + type|lower + '_import' %}
{{ type }}: {{ import_name.created_at }}
{% endfor %}
I would expect the output to be something like this:
Students: 5/26/2016
Faculty: 5/25/2016
Groups: 5/25/2016
I have the variables latest_students_import, latest_faculty_import, and latest_groups_import set in the template scope, and would like to avoid having a large conditional in my for loop. I set import_name based on the type, and then try to "call" import_name. I want something like {{ call(import_name) }}. Is this possible, or is there another way I can go about this?
In this case, I suppose I could do it in reverse order loop through the three template variable names, and then "print" the shortened name, capitalized, but I would prefer to do it this way.
One possibility is to create a dict or a list on the server-side which contains your variables. You can then send that object to Jinja as a template variable. As it stands you are just setting import_name equal to string, which won't have the .created_at attribute.

How to grab a string before hyphen using Jinja2?

My variable is as such:
api-20150901r1_6.38
Using Jinja, I need a way to grab the string BEFORE the hyphen. There will always be one hyphen so I dont need to worry about multiple instances.
Assuming input_string is api-20150901r1_6.38
You can use set
{% set mylist = input_string.split('-') %}
This is your value "api" in this case
{{ mylist[0] }}

Liquid: Can I get a random element from an Array?

I'm trying to pick a random element from an array -- is this possible using Liquid/Jekyll?
I can create an array -- and access a given index ... but is there a way to "shuffle" the array and then select an index, and thus get a random element from the array?
prefix: ["Foo", "Bar", "Baz"]
---
{{ page.prefix[1] }}
# outputs "Bar"
The 2018 answer is
{% assign prefix = page.prefix | sample: 2 %}
{{ prefix[0] }}
As the OP asked about Jekyll, this can be found at: https://jekyllrb.com/docs/templates/
Liquid doesn't have a filter for picking a random element from an array or an integer interval.
If you want Jekyll to do that, you would have to create an extension to add that liquid filter.
However, I must point out that doing so would pick a random element every time the page is generated, but not every time the page is viewed.
If you want to get different random values every time you visit a page, your best option is using javascript and letting the client pick a random value. You can use liquid to generate the relevant javascript though.
You may be able to do that just in Liquid, but it could less of generic solution like the one provided by #Brendan. According to this article, you can generate a random liquid number between min & max. So simply:
Assign the min to 0 and max to your array's length.
Loop over the array till you find your random number and pick you element.
Here is an example, get your random array index:
{% assign min = 0 %}
{% assign max = prefix.size %}
{% assign diff = max | minus: min %}
{% assign randomNumber = "now" | date: "%N" | modulo: diff | plus: min %}
Then find your random value:
{{ prefix[randomNumber] }}
You can create a plugin to get a random element. Something like this:
module Jekyll
module RandomFilter
# Use sample to get a random value from an array
#
# input - The Array to sample.
#
# Examples
#
# random([1, 2, 3, 4, 5])
# # => ([2])
#
# Returns a randomly-selected item out of an array.
def random(input)
input.sample(1)
end
end
end
Liquid::Template.register_filter(Jekyll::RandomFilter)
Then do something like this in your template to implement:
{% assign myArray = '1|2|3|4|5 | split: '|' %}
{% assign myNumber = myArray | random %}
Without using a plugin (which might be a requirement if you are using github pages for example) and don't want the choice to be set only at build/rebuild time.
This uses collections as it's data source and some feature flags set in the page front matter.
{% if page.announcements %}
<script>
// homepage callout
var taglines=[
{% for txt in site.announcements %}
{{ txt.content | markdownify | jsonify | append: "," }}
{% endfor %}
]
var selection = document.querySelector('#tagline') !== null;
if(selection) {
document.querySelector('#tagline').innerHTML = taglines[ Math.floor(Math.random()*taglines.length) ];
}
</script>
{% endif %}
I use markdownify to process the content, jsonify to make it JavaScript safe and then append a comma to make my array.
The Javascript then populates one randomly at page load.
Add collection to config.yml
collections:
announcements:
Add flag to page
---
layout: home
title:
slider: true
announcements: true
---
collection content item (test.md)
---
published: true
---
This is a test post
You could adapt Liquid::Drop and whitelist Ruby's sample method.
See https://github.com/Shopify/liquid/blob/master/lib/liquid/drop.rb#L69:
You would need to change:
blacklist -= [:sort, :count, :first, :min, :max, :include?]
to:
blacklist -= [:sort, :count, :first, :min, :max, :include?, :sample]
Next you could just use:
{{ some_liquid_array.sample }}