Jinja2 template variable if None Object set a default value - jinja2

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) }}

Related

SaltStack check if grain exists in Jinja file

I'm using SaltStack to manage my infra. Machines are hosted in different DCs, so they also have slightly different network setup.
Currently, I'm running into the following issue:
Comment: Unable to manage file: Jinja variable 'dict object' has no attribute 'macaddress'; line 9
---
[...]
ethernets:
{{ grains['interface_context'] }}:
dhcp4: {{ grains['dhcp4'] }}
dhcp6: {{ grains['dhcp6'] }}
addresses: [{{ grains['ipv4'] }}, "{{ grains['ipv6'] }}"]
{% if grains['macaddress'] %} <======================
match:
macaddress: {{ grains['macaddress'] }}
{% endif %}
routes:
- to: default
[...]
---
As the message indicates, the grain "macaddress" is missing, which I can confirm, it's not set for this minion. But What I do not understand is how I can simply check if this variable/grain exists at all within a jinja template?
I wouldn't expect this error to come up, as I actually wanted to catch it with the if statement.
Can somebody help?
Use get to return None instead of raising:
{% if grains.get('macaddress') is not none %}
Or if you want to treat "empty" values the same:
{% if not grains.get('macaddress') %}

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

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 '' }}

Jinja2: use template to build a string variable

Jinja2 supports very useful filters to modify a string, eg.
{{ my_string|capitalize }}
What about you want to build the input string? When the string is simple you can always use
{% set my_string = string_1 + string_2 %}
{{ my_string|capitalize }}
But it would be wonderful to actually build this string using templates, just like
{% set my_string = "{{ 'a' }}b{{ 'c' }}" %}
{{ my_string|capitalize }}
that would output Abc..
Did I miss something?
Answer exists in Jinja 2.8, as documented here
The answer is
{% set my_string %}
{{ 'a'}}b{{ 'c' }}
{% endset %}

Liquid shorthands?

Are there any liquid shorthands? For example I'm trying to express this in a more concise way:
{% if job.offsite %}}
{{job.offsite}}
{{% else %}}
{{ job.url }}
{% endif %}
For this particular example, you could write:
{{ job.offsite | default: job.url }}
The value provided to the default filter will be used if the left side of the expression is false or nil.

In Jinja2, how do you test if a variable is undefined?

Converting from Django, I'm used to doing something like this:
{% if not var1 %} {% endif %}
and having it work if I didn't put var1 into the context. Jinja2 gives me an undefined error. Is there an easy way to say {% if var1 == None %} or similar?
From the Jinja2 template designer documentation:
{% if variable is defined %}
value of variable: {{ variable }}
{% else %}
variable is not defined
{% endif %}
{% if variable is defined %} is true if the variable is None.
Since not is None is not allowed, that means that
{% if variable != None %}
is really your only option.
You could also define a variable in a jinja2 template like this:
{% if step is not defined %}
{% set step = 1 %}
{% endif %}
And then You can use it like this:
{% if step == 1 %}
<div class="col-xs-3 bs-wizard-step active">
{% elif step > 1 %}
<div class="col-xs-3 bs-wizard-step complete">
{% else %}
<div class="col-xs-3 bs-wizard-step disabled">
{% endif %}
Otherwise (if You wouldn't use {% set step = 1 %}) the upper code would throw:
UndefinedError: 'step' is undefined
In the Environment setup, we had undefined = StrictUndefined, which prevented undefined values from being set to anything. This fixed it:
from jinja2 import Undefined
JINJA2_ENVIRONMENT_OPTIONS = { 'undefined' : Undefined }
Consider using default filter if it is what you need. For example:
{% set host = jabber.host | default(default.host) -%}
or use more fallback values with "hardcoded" one at the end like:
{% set connectTimeout = config.stackowerflow.connect.timeout | default(config.stackowerflow.timeout) | default(config.timeout) | default(42) -%}
You can use kind of Jinja Elvis operator
{{ 'OK' if variable is defined else 'N/A' }}
or additionally check emptiness
{{ 'OK' if (variable is defined and variable) else 'N/A' }}
Jinja templates - Template Designer Documentation
{% if variable is defined %} works to check if something is undefined.
You can get away with using {% if not var1 %} if you default your variables to False eg
class MainHandler(BaseHandler):
def get(self):
var1 = self.request.get('var1', False)
I had an issue like this in Ansible. Ended up having to do a test on both #Garret and #Carsten / #azalea answers, so:
{% if variable is defined and variable %}
value of variable: {{ variable }}
{% else %}
variable is not defined or is falsy
{% endif %}
You can do this :
- debug:
msg: "Executed only if variable is defined"
when:
- variable is defined