Search code examples
jinja2

Concatenate optional variables in Jinja without duplicating whitespace


Question

I want to concatenate variables in Jinja by separating them with exactly one space (' ') where some of the variables might be undefined (not known to the template which ones).

import jinja2

template = jinja2.Template('{{ title }} {{ first }} {{ middle }} {{ last }}')
result = template.render(first='John', last='Doe')  # result == ' John  Doe'

I've been searching for a template string alternative that returns 'John Doe' instead of ' John Doe' in this case.

First attempt

Use

{{ [title, first, middle, last]|reject("undefined")|join(" ") }}

as template (which actually works), however

  • it's confusing
  • once I want to use a macro on one of the arguments (that e.g. puts middle in brackets if it is not undefined) and therefore return an empty string instead of Undefined this stops working.

2nd attempt

Replace multiple spaces with one space

{% filter replace("  ", " ") -%}
{{ title }} {{ first }} {{ middle }} {{ last }}
{%- endfilter %}

which actually only would work in all cases with a regular expression search/replace like

{% filter regex_replace(" +", " ") -%}
{{ title }} {{ first }} {{ middle }} {{ last }}
{%- endfilter %}

but regex_replace is not built-in (but could be provided by a custom regular expression filter).

Still I would not consider this to be optimal as double spaces in the content of variables would be replaced as well.


Solution

  • you dont use the power of jinja2/python, use the if else and test if a variable is defined:

    import jinja2
    
    template = "{{ title ~ ' ' if title is defined else '' }}"
    template += "{{first ~ ' ' if first is defined else '' }}"
    template += "{{ middle ~ ' ' if middle is defined else '' }}"
    template += "{{ last if last is defined else '' }}"
    
    template = jinja2.Template(template)
    result = template.render(first='John', last='Doe')
    print("----------")
    print(result)
    print("----------")
    

    result:

    ----------
    John Doe
    ----------
    

    if you want to use regex, use :

    import re
      :
      :
    template = jinja2.Template("{{ title }} {{ first }} {{ middle }} {{ last }}")
    result = template.render(first='John', last='Doe')
    result = re.sub(" +", " ", result.strip())
    
    • strip() deletes any leading and trailing whitespaces including tabs (\t)

    or a mixed of both solutions to avoid to suppress spaces not wanted

    import jinja2
    
    template = "{{ title ~ ' ' if title is defined else '' }}"
    template += "{{first ~ ' ' if first is defined else '' }}"
    template += "{{ middle ~ ' ' if middle is defined else '' }}"
    template += "{{ last if last is defined else '' }}"
    
    template = jinja2.Template(template)
    result = template.render(first='John', last='Doe').strip()