11

In Jinja2 I'm looking for a way to check if at least one of a list of variables has a value. Basically in python I would do:

if any([item['genre'], item['type'], item['color']]):

However, in Jinja the following isn't valid:

{% if any([item['genre'], item['type'], item['color']]) %}
# some part of the Jinja template
{% endif %}

Is there a way to have the same "any()" check in Jinja2?

For background: the full piece of code that I currently try to add (but isn't valid):

{% if any([item['genre'], item['type'], item['color']]) %}
<ItemProperties>
    <ItemProperty key="genre">{{ item['genre'] }}</ItemProperty>
    <ItemProperty key="type">{{ item['type'] }}</ItemProperty>
    <ItemProperty key="color">{{ item['color'] }}</ItemProperty>
</ItemProperties>
{% endif %}
KCDC
  • 666
  • 2
  • 7
  • 13
  • 1
    For 3 hardcoded entries, why not just use `if item['genre'] or item['type'] or item['color']`? Jinja2 is Python-*like*, not Python itself, there is no `any()`. – Martijn Pieters Feb 07 '19 at 14:29
  • `any(item['genre'], item['type'], item['color'])` -> `any` accepts only one argument, so that wouldn't work even in plain Python – ForceBru Feb 07 '19 at 14:32
  • @ForceBru: I think we can still work out what is being asked, though. – Martijn Pieters Feb 07 '19 at 14:33
  • built-in functions are not available in jinja2, see https://stackoverflow.com/questions/6036082/call-a-python-function-from-jinja2 - you have to pass it to global enviroment somehow, I dont use it so I might be wrong – Derte Trdelnik Feb 07 '19 at 14:37
  • @DerteTrdelnik: that post is about registering a function; this is really a *filter*, so my answer below shows how to register `any()` and `all()`. – Martijn Pieters Feb 07 '19 at 14:41
  • @ForceBru yeah that was a typo, forgot the squared brackets for the list. Edited. – KCDC Feb 07 '19 at 14:53
  • @Martijn Pieters `any` and `all` are python functions from module `builtins` you can register them the same way – Derte Trdelnik Feb 07 '19 at 14:54
  • @DerteTrdelnik: yes, I didn't say you couldn't. I'm saying that there is a better option. – Martijn Pieters Feb 07 '19 at 14:54

1 Answers1

19

There is no direct equivalent of the any() function in Jinja2 templates.

For 3 hard-coded elements, I'd just use boolean logic or:

{% if item['genre'] or item['type'] or item['color'] %}

Otherwise, you can use the select() filter without an argument (followed by first() to force iteration). Because select() is itself a generator, using first() on select() makes this short-circuit the way any() would:

{% if (item['genre'], item['type'], item['color'])|select|first %}

Without an argument, select() returns any objects from the input sequence that are true, and first() ensures it iterates no more than needed to find one such element.

The last option is to register a custom filter to just add any() to Jinja yourself; I'd also add all() in that case. You can register both functions directly, since neither takes options:

environment.filters['any'] = any
environment.filters['all'] = all

at which point you can then use

{% if (item['genre'], item['type'], item['color'])|any %}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @MartijnPieters question asked for Jinja2, so this is not necessarily interesting, but since this is the first thing coming up when googling for use of any in Jinja it might still be good to add: Jinja3 has a reject filter, with which one might simulate any `if any(value not in list for value in values)` becomes `if values | reject("in", some_list) | first`. Maybe not the best example, but worked for me. [The docs.](https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.reject) – Fynn Aug 08 '23 at 18:15
  • 1
    @Fynn: basically, `reject` is the inverse of `select`, the implementation for these filters uses a [single `select_or_reject()` function](https://github.com/pallets/jinja/blob/86f28a9df0a97a3d3bfa3785b082651e2a8e994d/src/jinja2/filters.py#L1757-L1770) with a different `modfunc` callable that is returns either `value` or `not value`. It's not unique to Jinja 3, both `select` and `reject` were [added in version 2.7](https://jinja.palletsprojects.com/en/3.1.x/changes/#version-2-7). – Martijn Pieters Aug 09 '23 at 16:53