Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
181 views
in Technique[技术] by (71.8m points)

python - Jinja2 indentation when using inline and non-inline blocks

I have the template below:

{% macro entry(e) %}
<li>
    <a href="{% if 'link' in e %}{{ e.link }}{% else %}{{ e.path }}{% endif %}">
        <code>{{ e.title }}</code>
    </a>{% if e.desc  %} - {{ e.desc }}{% endif %}
    {% if e.date %}<time datetime="{{ e.date }}"> ({{ e.date.split('-')[0] }})</time>{% endif %}
</li>
{% endmacro %}
<ul>
    {% for e in entries %}
    {{ entry(e) }}
    {% endfor %}
</ul>

which I'm trying to render into this HTML with proper indentation and no blank lines:

<ul>
    <li>
        <a href="link">
            <code>title</code>
        </a> - desc
        <time datetime="2020"> (2020)</time>
    </li>
</ul>

I've tried various permutations of trim_blocks and lstrip_blocks to no avail. How can I achieve the desired output?

Sample code:

from jinja2 import Environment, FileSystemLoader, Template

foo = (
    (True, True),
    (True, False),
    (False, True),
    (False, False),
)

template_string = """
{% macro entry(e) %}
<li>
    <a href="{% if 'link' in e %}{{ e.link }}{% endif %}">
        <code>{{ e.title }}</code>
    </a>{% if e.desc  %} - {{ e.desc }}{% endif %}
    {% if e.date %}<time datetime="{{ e.date }}"> ({{ e.date.split('-')[0] }})</time>{% endif %}
</li>
{% endmacro %}
<ul>
    {% for e in entries %}
    {{ entry(e) }}
    {% endfor %}
</ul>
"""

entries = [
    {'title': 'title', 'date': '2020', 'desc': 'desc', 'link': 'link'}
]

for trim_blocks, lstrip_blocks in foo:
    env = Environment(trim_blocks=trim_blocks, lstrip_blocks=lstrip_blocks)

    template = env.from_string(template_string)

    print("------------------------")
    print("trim_blocks:", trim_blocks)
    print("lstrip_blocks:", lstrip_blocks)
    print("------------------------")
    print(template.render(entries=entries))

# ------------------------
# trim_blocks: True
# lstrip_blocks: True
# ------------------------
# 
# <ul>
#     <li>
#     <a href="link">
#         <code>title</code>
#     </a> - desc<time datetime="2020"> (2020)</time></li>
# 
# </ul>
# ------------------------
# trim_blocks: True
# lstrip_blocks: False
# ------------------------
# 
# <ul>
#         <li>
#     <a href="link">
#         <code>title</code>
#     </a> - desc    <time datetime="2020"> (2020)</time></li>
# 
#     </ul>
# ------------------------
# trim_blocks: False
# lstrip_blocks: True
# ------------------------
# 
# 
# <ul>
# 
#     
# <li>
#     <a href="link">
#         <code>title</code>
#     </a> - desc
# <time datetime="2020"> (2020)</time>
# </li>
# 
# 
# </ul>
# ------------------------
# trim_blocks: False
# lstrip_blocks: False
# ------------------------
# 
# 
# <ul>
#     
#     
# <li>
#     <a href="link">
#         <code>title</code>
#     </a> - desc
#     <time datetime="2020"> (2020)</time>
# </li>
# 
#     
# </ul>
question from:https://stackoverflow.com/questions/65649891/jinja2-indentation-when-using-inline-and-non-inline-blocks

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You will want the combination of trim_blocks and lstrip_blocks both being False. So, the last version you have is actually quite close.

To achieve the desired output though, you will need to make use of whitespace control mechanisms provided by Jinja2. In particular, you will be interested in this:

You can also strip whitespace in templates by hand. If you add a minus sign (-) to the start or end of a block (e.g. a For tag), a comment, or a variable expression, the whitespaces before or after that block will be removed:

Therefore, by adding - signs in the for loop and macro, you can remove the unwanted newlines which occur upon expansion.

In the case of the for loop, add it to both sides of start and end of the block. However, in the case of the macro, add it only on one side -- if you add it to both, it will merge the <ul> and <li> onto the same line (and similarly for the closing tags).

The following should work for you:

from jinja2 import Environment, FileSystemLoader, Template

template_string = """
{%- macro entry(e) %}
    <li>
        <a href="{% if 'link' in e %}{{ e.link }}{% endif %}">
            <code>{{ e.title }}</code>
        </a>{% if e.desc  %} - {{ e.desc }}{% endif %}
        {% if e.date %}<time datetime="{{ e.date }}"> ({{ e.date.split('-')[0] }})</time>{% endif %}
    </li>
{% endmacro -%}
<ul>
    {%- for e in entries -%}
        {{ entry(e) }}
    {%- endfor -%}
</ul>
"""

entries = [
    {'title': 'title', 'date': '2020', 'desc': 'desc', 'link': 'link'}
]

env = Environment(trim_blocks=False, lstrip_blocks=False)
template = env.from_string(template_string)
print(template.render(entries=entries))

Which gives the desired output:

<ul>
    <li>
        <a href="link">
            <code>title</code>
        </a> - desc
        <time datetime="2020"> (2020)</time>
    </li>
</ul>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...