Django模板forloop.counter访问二维列表报索引越界问题排查
问题产生原因
forloop变量的作用域仅绑定到距离最近的一层for循环,嵌套循环中内层的forloop.counter会覆盖外层的同名变量。
你最初编写的两层嵌套循环代码中,链式调用的两个index过滤器传入的forloop.counter全是内层遍历team_members循环的计数器,和外层遍历teams的循环没有任何关系。内层循环每迭代一次,计数器从1开始逐次累加,当计数器值超过内层子列表的最大索引值时,就会触发列表索引越界。你硬编码索引值时使用的是固定常量,不会随循环迭代变化,因此可以正常运行。- Django模板内置的
forloop.counter是从1开始计数的,和Python列表从0开始的索引规则存在1位偏移,当计数器值等于列表长度时,对应取列表的第长度位元素,刚好超出列表最大索引(最大索引为长度-1),也会触发越界。 - 你单独编写
{{team_members|index:forloop.counter}}可以正常运行,是因为这行代码所处的位置没有内层循环覆盖forloop变量,拿到的是外层循环的计数器,且取值范围刚好在team_members一级列表的索引范围内,没有触发越界条件。
修复方案
- 嵌套循环中提前把外层循环的索引值用
{% with %}标签存为独立变量,避免内层循环作用域覆盖;索引用forloop.counter0(从0开始计数,和Python列表索引规则一致)替代forloop.counter,消除偏移量问题:
如果不想额外定义with变量,也可以通过{% for team in teams %} {% with outer_idx=forloop.counter0 %} {% for member_item in team_members %} {{ team_members|index:outer_idx|index:forloop.counter0 }} {% endfor %} {% endwith %} {% endfor %}forloop.parentloop.counter0取上一层循环的0起始索引,不过嵌套层级较多时不推荐这种写法,很容易数错parentloop的层级。 - 你补充的tooltip属性代码,把
forloop.counter换成forloop.counter0即可解决索引偏移导致的越界问题,调整后代码如下:<div class="card card-body" data-toggle="tooltip" data-placement="bottom" data-html="true" twipsy-content-set="true" class="tooltip ficon-help-icon" title="Leader: {% with team_member=team_members|index:forloop.counter0 %} {{ team_member|index:0 }} {% endwith %}<br>Members: {{team_members.1.1}}"> {{team.name|teamName}} </div> - 优化自定义
index过滤器,增加类型转换和异常容错,避免非预期值导致页面渲染崩溃:@register.filter def index(sequence, position): try: pos = int(position) return sequence[pos] except (IndexError, ValueError, TypeError): return ''
内容的提问来源于stack exchange,提问作者Sergo
相关产品推荐
相关产品推荐

