You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django模板嵌套循环:基于外层计数器访问内层列表索引

在Django模板中根据外层循环索引访问内层列表元素

问题背景

需要实现类似普通Python中通过外层循环索引访问对应内层列表的逻辑:

parent_list = ['One','Two','Three']
child_list = ['A','B','C']

for idx, item in enumerate(parent_list):
    for child_item in child_list[idx]:
        print(str(idx), item, child_item)

但在Django模板中尝试用with和forloop.counter0保存外层索引时,无法通过royalty_items.outer_counter的方式动态访问对应索引的元素,硬写固定索引(如royalty_items.0)只会重复显示同一组内容。

现有代码情况

模板代码(尝试失败版本)

{% for item in payout_items %}
    {% with forloop.counter0 as outer_counter %}
    <h2>{{ item.market_place }} on {{ item.entry_date }}:
        {% for item in royalty_items.outer_counter %}
            <tr>
            <th scope="row">{{ item.id }}</th>
            <td>{{ item.entry_date }}</td>
            <td>{{ item.market_place }}</td>
            </tr>
        {% endfor %}
    {% endwith %}
{% endfor %}

视图层代码

视图中已准备好对应的两个列表:

detail_object = AccountingPeriod.objects.get(pk=detail_id)
payout_items = Payout.objects.filter(sales_period_start__range=[detail_object.period_start, detail_object.period_end])

royalty_items = []
for payout in payout_items:
    temp = Royalty.objects.filter(entry_date__range=[payout.sales_period_start, payout.sales_period_end]).filter(market_place=payout.market_place)
    print(str(payout.sales_period_start) + " - " + str(payout.sales_period_end) + " - " + payout.market_place + " = " + str(len(temp)))
    royalty_items.append(temp)

渲染参数:

render(request, 'royalties/accounting_period/summary.html', {'detail_object': detail_object, 'payout_items': payout_items, 'royalty_items': royalty_items})

当前解决方案(自定义过滤器)

通过自定义过滤器实现索引访问:

@register.filter()
def getRoyaltySet(royalty_items, outer_counter):
    return royalty_items[outer_counter]

更优雅的解决方案

方案1:视图层打包元组(推荐)

遵循Django“尽量将逻辑放在视图层”的原则,在视图中将payout对象和对应的royalties列表打包成元组,避免模板处理索引逻辑:

修改视图代码

detail_object = AccountingPeriod.objects.get(pk=detail_id)
payout_items = Payout.objects.filter(sales_period_start__range=[detail_object.period_start, detail_object.period_end])

# 打包payout对象和对应的royalties列表
payout_royalty_pairs = []
for payout in payout_items:
    royalties = Royalty.objects.filter(
        entry_date__range=[payout.sales_period_start, payout.sales_period_end],
        market_place=payout.market_place
    )
    payout_royalty_pairs.append( (payout, royalties) )

修改渲染参数

render(request, 'royalties/accounting_period/summary.html', {
    'detail_object': detail_object,
    'payout_royalty_pairs': payout_royalty_pairs
})

优化后的模板代码

模板逻辑更简洁,直接遍历打包好的元组:

{% for payout, royalties in payout_royalty_pairs %}
    <h2>{{ payout.market_place }} on {{ payout.entry_date }}:</h2>
    <table>
        {% for royalty in royalties %}
            <tr>
                <th scope="row">{{ royalty.id }}</th>
                <td>{{ royalty.entry_date }}</td>
                <td>{{ royalty.market_place }}</td>
            </tr>
        {% endfor %}
    </table>
{% endfor %}

方案2:模板层使用内置方法(无需修改视图)

如果不想调整视图,除了自定义过滤器,还可以利用Django模板的slice过滤器结合forloop.counter0,不过写法稍显繁琐:

{% for item in payout_items %}
    {% with outer_idx=forloop.counter0 %}
        <h2>{{ item.market_place }} on {{ item.entry_date }}:</h2>
        <table>
            {% for royalty in royalty_items|slice:outer_idx|slice:":1"|first %}
                <tr>
                    <th scope="row">{{ royalty.id }}</th>
                    <td>{{ royalty.entry_date }}</td>
                    <td>{{ royalty.market_place }}</td>
                </tr>
            {% endfor %}
        </table>
    {% endwith %}
{% endfor %}

但这种方式可读性不如方案1,因此更推荐视图层打包元组的方案。

内容的提问来源于stack exchange,提问作者Byte Insight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:16:09