Jinja2如何进行高级切片

Jinja2 how to perform advanced slicing

我有一个列表,"foos" 如果我有超过 5 个 "foos" 我想针对前 2 个做一些特定的事情,然后针对其余的做一些特定的事情。

所以我有点想要 HTML 中这样的东西:

<div id="accordion">
    <p>Foo1<p>
    <p>Foo2<p>
    <div id="collapseMe" class="panel-collapse collapse">
        <p>Foo3<p>
        <p>Foo4<p>
        etc...
    </div>
</div>

<a data-parent="#accordion" href="#collapseMe"><p>Expand</p></a>

所以,我已经在 J​​inga2 中解决了这个问题,但解决方案非常难看。我想知道我是否遗漏了什么?

<div id="accordion">
    {% for f in foos  %}
        {% if loop.index <= 2 %}
            <p>{{ f.txt }}</p>
        {% else %}
            {% if loop.index == 3 %}
                <div id="collapseMe" class="panel-collapse collapse">
                    <p>{{ f.txt }}</p>
            {% else %}
                    <p>{{ f.txt }}</p>
            {% endif %}
        {% endif %}
    {% endfor %}

    {% if foos | length > 2 %}
    </div>
    <a data-parent="#accordion" href="#collapseMe"><p>Expand</p></a>
    {% endif %}
</div>

虽然这很有效,但我认为一定有更好的方法来做到这一点。不幸的是,据我所知,Jinga2 中的切片函数非常有限,也许还有另一种我还没有采用的解决方法?我也不完全清楚 Batch 函数是如何工作的,但这可能有用吗?

您可以构建或找到一个过滤器,以便在 for 循环之前预先切分您的 foos 列表。

{% for f in foos|slice:"0:10:2" %}

您可以将大部分模板循环逻辑移动到过滤器本身,或者走简单的路线并在列表中使用现有的切片表示法:

from jinja2 import Environment, Undefined

def slice(iterable, pattern):
    if iterable is None or isinstance(iterable, Undefined):
        return iterable

    # convert to list so we can slice
    items = list(iterable)

    start  = None
    end    = None
    stride = None

    # split pattern into slice components
    if pattern:
        tokens = pattern.split(':')
        if len(tokens) >= 1:
            start  = tokens[0]
        if len(tokens) >= 2:
            end    = tokens[1]
        if len(tokens) >= 3:
            stride = tokens[2];

    return items[start:end:stride]

在其他地方,将过滤器添加到您的 Jinja2 环境中。

env = Environment()
env.filters['slice'] = slice

请注意,这是有效的,因为 [:::][None:None:None] 是相同的切片符号。