Home > Software engineering >  Syntax "if any() / if all() in object" in Jinja
Syntax "if any() / if all() in object" in Jinja

Time:09-12

1. Summary

I can’t find, what is the correct syntax in Jinja2 for expressions like if any() in object/if all() in object.

2. MCVE

  • Live demo on Repl.it:

    """Jinja2 if any() in object MCVE."""
    from jinja2 import Template
    
    KIRA_BLOCK = """
    {% if 14 in range(1,5) or 4 in range(1,5) or 7 in range(1,5) %}
        Kira Goddess!
    {% endif %}
    """
    
    print(Template(KIRA_BLOCK).render())
    
    

How can I get the same result without duplicate code?

3. Not helped

  1. I tried searching for the answer to my question and similar examples in Google, GitHub and Jinja documentation

  2. I didn’t understand how can I use Jinja built-in filters to solve my problem

  3. I tried select() filter, as recommended in this answer on Stack Overflow. Like this:

    KIRA_BLOCK = """
    {% if (14,4,7)|select|first in range(1,5) %}
        Kira Goddess!
    {% endif %}
    """
    
  4. I tried to register a custom any() filter, as recommended in the same answer on Stack Overflow. Like this:

    """Jinja2 if any() in object MCVE."""
    from jinja2 import Environment
    from jinja2 import Template
    
    
    environment = Environment()
    
    environment.filters["any"] = any
    
    KIRA_BLOCK = """
    {% if (14,4,7)|any in range(1,5) %}
        Kira Goddess!
    {% endif %}
    """
    
    
    print(Template(KIRA_BLOCK).render())
    
    

4. Real example

For preventing XY problem:

I use similar templates in static site generator Pelican. Example:

{# [INFO] If any of the classes "attention", "caution" or "warning" exists in my article, I add specific styles #}
{% if "class=\"attenion\"" in article.content or if "class=\"caution\"" in article.content or if "class=\"warning\"" in article.content %}
    <link rel="preload" href="path/to/css/third-party/Admonition/admonition-warning.min.css" as="style" onl oad="this.rel='stylesheet'">

{# [INFO] Elif all classes "faq", "help" and "question" exists in my article, I add another styles #}
{% elif "class=\"faq\"" in article.content and if "class=\"help\"" in article.content and if "class=\"question\"" in article.content %}
    <link rel="preload" href="path/to/css/third-party/Admonition/admonition-question.min.css" as="style" onl oad="this.rel='stylesheet'">
{% endif %}

I don’t understand how to remove hard coding from these templates.

Thanks.

CodePudding user response:

I can’t find, what is the correct syntax in Jinja2 for expressions like if any() in object/if any() in object.

That's not how the any() function works in Python. You might write something like this:

if any(value == 4 for value in mylist):
    ...

The any() function, as shown in the documentation, is equivalent to:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False

The above unfortunately doesn't translate well into Jinja, because Jinja doesn't support list/tuple comprehensions, without which the any() function is much less useful.


Looking at what you're actually trying to do:

{#
   [INFO] If any of the classes "attention", "caution" or
  "warning" exists in my article, I add specific styles
#}
{% if "class=\"attenion\"" in article.content
     or if "class=\"caution\"" in article.content 
      or if "class=\"warning\"" in article.content %}
    <link rel="preload" href="path/to/css/third-party/Admonition/admonition-warning.min.css" as="style" onl oad="this.rel='stylesheet'">
{% endif %}

You could register a custom has_class filter that looks like this:

def has_class(content, classnames):
    return any(f'' in content for name in classnames)

And use it like this:

{#
   [INFO] If any of the classes "attention", "caution" or
  "warning" exists in my article, I add specific styles
#}
{% if article.content|has_class(['attention', 'caution', 'warning']) %}
    <link rel="preload" href="path/to/css/third-party/Admonition/admonition-warning.min.css" as="style" onl oad="this.rel='stylesheet'">
{% endif %}
  • Related