Jinja2 condition not matching within an expression, how to resolve this? - jinja2

I am currently having troubles with the first if statement in a Jinja2 template resolving to else even though both conditions are met:
{%- elif frontend_type == 'beast' -%}
{{ radosgw_frontend_type }} {{ 'ssl_' if radosgw_frontend_ssl_certificate and haproxy_frontend_ssl_termination is sameas false else '' }}endpoint={{ _rgw_binding_socket }}{{ ' ssl_certificate='+radosgw_frontend_ssl_certificate if radosgw_frontend_ssl_certificate else '' }}
{%- endif -%}
The problematic snippet seems to be and haproxy_frontend_ssl_termination is sameas false as the other condition works fine. I am not sure why this condition is not met even though it seems to work in another template when encapsulated in {% %}.
Any help would be greatly appreciated!

I suspect your problem is the use of the sameas test. From the documentation:
sameas(value, other)
Check if an object points to the same memory address than another object:
That's almost never what you want to do. If you're checking to see if an expression is false, you don't need to explicitly compare it to false. E.g., you could simply write:
{{ 'ssl_' if radosgw_frontend_ssl_certificate and not haproxy_frontend_ssl_termination else '' }}

Related

Shopify Looping Over JSON Metafield Arrays

For some reason, I can't access an array within a JSON metafield.. I've tried the other StackOverflow answers, and I'm using value, etc. but just can't figure it out, here's my metafield:
product.metafields.artist.releases
with a value of:
{
  "releases": [
   { 
"id": 0,
    "releaseName": "lofi 1",
    "coverArt": "",
    "releaseLink": “”
},
 { 
"id": 1,
    "releaseName": " lofi 2",
    "coverArt": "",
    "releaseLink": “”
}
]}
(which formats to: "{\"releases\":[{\"id\":0,\"releaseName\":\"lofi 1\",\"coverArt\":\"\",\"releaseLink\":“”},{\"id\":1,\"releaseName\":\"lofi 2\",\"coverArt\":\"google.com\",\"releaseLink\":“”}]}")
and I'm using this in the product.custom.liquid:
{{ product.metafields.artist.releases.value }}
{% assign releases = product.metafields.artist.releases.value %}
{% for release in releases.releases %}
{{ release.releaseName }}
{% endfor %}
the first one shows up fine, and if I assign it and do {{ releases }} it shows up fine as well so I know the assignment is working, but I can't forloop over it (mind you that the first object in the JSON is also called releases (I've also tried renaming it all to unique names just in case and that didn't help))
For some reason when it is a multidimensional JSON array it acts weird. There is a simple fix for it, just add (-) at the end of your assigned variable:
{%- assign releases = product.metafields.artist.releases.value -%}
{% for release in releases.releases %}
{{ release.releaseName }}
{%- endfor -%}
Hope it solves your problem like it did mine!
Liquid is not going to work on JSON like this. If you want to iterate through an array of JSON objects, use Javascript.
As lov2code points out by adding (-) it trims the output for any unnecessary white space, which enables you to traverse the JSON array.

dbt jinja returning the results of a query

I am trying to model the following situation:
given some query, return multi-column result-set (e.g. run_query or db_utils.get_query_results_as_dict
iterate over in a case/statment
for exmaple:
{% set conditions = dbt_utils.get_query_results_as_dict("select comment, criteria from "
~ ref('the_model') %}
...
select case
{% for condition in conditions %}
when {{ condition["criteria"] }}
then {{ condition["comment"] }}
{% endfor %}
Have not been able to get this to work, any guidance appreciated.
Some ideas I tried:
get_column_values x2 and zipping them into a new list of tuples. zip not recognised
get the count(*) from the_model then trying to iterate over the range - ran into issues with types
various for conditions {% for k, v in conditions.items() %}
Was able to self resolve with the following:
{% set conditions = dbt_utils.get_query_results_as_dict("select criteria, comment from " ~ ref('reference_data') ~ " order by sequence desc") %}
with main as (
select * from {{ ref('my_other_model') }}
),
-- [NEEDS_REVIEW] there's probably a cleaner way to do this iteration - however it's interpolated result. Could do with the zip function.
comments as (
select
*,
case
{# {{- log(conditions, info=True) -}} #}
{%- for comment in conditions.COMMENT -%}
when {{ conditions.CRITERIA[loop.index0] }}
then '{{ comment }}'
{% endfor %}
end as comment
from main
)
select * from comments
The gotchas:
this was on snowflake, so the keys returned by the function will be up-cased as that is how I loaded the data.
Using the loop.index0 to get the current iteration of the loop and index into the other collection of tuples (in this case CRITERIA).
i added a SEQUENCE key to my reference data just to ensure consistent rendering by using that to order. The criteria do overlap a-little bit so this was important.

Compare two grain values inside state.sls using jinja expressions

I am creating a state which will trigger some module if both of the grains are not matching. I have tried several options, but no luck.
Based on comparison, False will trigger my module and that module will change GRAIN_B value to match with GRAIN_A. So during every highstate my module will not get triggered, unless there is a change in GRAIN_A.
Any suggestions please.
I have tried several jinja expressions.
{% if grains['GRAIN_A'] not in grains.get('GRAIN_B','None') %}
{% set GRAIN_B = grains.get('GRAIN_B','None') %}
{% if grains['GRAIN_A'] != {{ GRAIN_B }} %}```
```{% if grains['GRAIN_A'] not in grains.get('GRAIN_B','None') %}
MY_MODULE:
module.run:
- func: MYMODULE.FUNCTION_A
{% endif %}```
Issue fixed, there is a \n character in my GRAIN_A output, which makes the evaluation condition fails.
This condition works already.
{% if grains['GRAIN_A'] not in grains.get('GRAIN_B','None') %}
MY_MODULE:
module.run:
- func: MYMODULE.FUNCTION_A
{% endif %}

How to use IF statement in twig for given use case

I am using twig for templating
{{ content.field_votre_type_the_profil[0] }} returns "test string"
so when i compare it in if statement it not working...
for example
{% if content.field_votre_type_the_profil[0] == "test string" %}
<p>Hey i found the string</p>
{% endif %}
I am not getting the "Hey i found the string" in output..
Any idea?
Try reversing the logic, and say:
{% if content.field_votre_type_the_profil[0] != "test string" %}
If your P tag appears, there is a problem with your value being lost/overwritten somewhere.
If you can't get it to print your html no matter what your logic is: check that your syntax is correct, make sure there are no errors happening with the plugin itself, etc.
Let me know if you've tried anything else, I'll respond with more help.
Try this and tell me what it prints:
{% if content.field_votre_type_the_profil[0] == "test string" %}
<p>Hey i found the string</p>
{% else %}
<h1>Your variable is being overwritten, or not included for some reason</h1>
{% endif %}
{{ content.field_votre_type_the_profil[0] }}
I was able to solve it..
I had to go one level deeper to do this if calculation.
{% if content.field_votre_type_the_profil[0]['#markup'] == "test string" %}

Jinja2 template variable if None Object set a default value

How to make a variable in jijna2 default to "" if object is None instead of doing something like this?
{% if p %}
{{ p.User['first_name']}}
{% else %}
NONE
{%endif %}
So if object p is None I want to default the values of p (first_name and last_name) to "".
Basically
nvl(p.User[first_name'], "")
Error receiving:
Error: jinja2.exceptions.UndefinedError
UndefinedError: 'None' has no attribute 'User'
Use the none test (not to be confused with Python's None object!):
{% if p is not none %}
{{ p.User['first_name'] }}
{% else %}
NONE
{% endif %}
or:
{{ p.User['first_name'] if p is not none else 'NONE' }}
or if you need an empty string:
{{ p.User['first_name'] if p is not none }}
{{p.User['first_name'] or 'My default string'}}
According to docs you can just do:
{{ p|d('', true) }}
Cause None casts to False in a boolean context.
As addition to other answers, one can write something else if variable is None like this:
{{ variable or '' }}
Following this doc you can do this that way:
{{ p.User['first_name']|default('NONE') }}
To avoid throw a exception while "p" or "p.User" is None, you can use:
{{ (p and p.User and p.User['first_name']) or "default_value" }}
With ChainableUndefined, you can do that.
>>> import jinja2
>>> env = jinja2.Environment(undefined=jinja2.ChainableUndefined)
>>> env.from_string("{{ foo.bar['baz'] | default('val') }}").render()
'val'
source
if you want to set your own default value instead of None than simply do this
{{your_var|default:'default name'}}
As another solution (kind of similar to some previous ones):
{{ ( p is defined and p.User is defined and p.User['first_name'] ) |default("NONE", True) }}
Note the last variable (p.User['first_name']) does not have the if defined test after it.
I usually define an nvl function, and put it in globals and filters.
def nvl(*args):
for item in args:
if item is not None:
return item
return None
app.jinja_env.globals['nvl'] = nvl
app.jinja_env.filters['nvl'] = nvl
Usage in a template:
<span>Welcome {{ nvl(person.nick, person.name, 'Anonymous') }}<span>
// or
<span>Welcome {{ person.nick | nvl(person.name, 'Anonymous') }}<span>
As of Ansible 2.8, you can just use:
{{ p.User['first_name'] }}
See https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.8.html#jinja-undefined-values
You can simply add "default none" to your variable as the form below mentioned:
{{ your_var | default('NONE', boolean=true) }}