
在django模板中无法直接通过list.{{week.number}}.0等方式动态索引嵌套列表,需借助自定义模板过滤器实现安全、可读的动态访问。
django模板语言(DTL)本身不支持动态变量作为列表或嵌套结构的索引(例如 activity_list.{{ week.number }}.0),因为点号(.)访问符仅支持静态属性名或整数下标字面量(如 .0、.1),不支持表达式求值。当您尝试使用 activity_list.week.number.0 时,Django 会将其解析为字面属性链(即查找名为 “week” 的属性,再找其 “number” 属性),而非将 week.number 的值(如 2)作为索引代入。
✅ 正确解法:编写轻量级自定义模板过滤器
在您的应用目录下(如 myapp/templatetags/list_extras.py),创建如下过滤器:
# myapp/templatetags/list_extras.py from django import template register = template.Library() @register.filter def get_item(container, key): """ 安全获取容器中指定键/索引的值。 支持 list[int], dict[key], 以及带 __getitem__ 的对象。 """ try: return container[key] except (KeyError, TypeError, IndexError): return None
⚠️ 别忘了在模板顶部加载该标签库:
{% load list_extras %}
✅ 模板中使用示例(假设 week 是 Plan 对象的一个属性或循环变量,且 week.number 返回整数 0–N):
{% for week in plan.weeks_range %} {# 假设您在视图中传入了 range(weeks) 或类似结构 #} Week {{ week }}
{% with monday_activity=activity_list|get_item:week|get_item:0 %} {% if monday_activity %} Monday: {{ monday_activity.name }} ({{ monday_activity.distance }} km)
{% else %} Monday: No activity
{% endif %} {% endwith %} {% endfor %}
? 关键说明:
- 过滤器链 |get_item:week|get_item:0 等价于 python 中的 activity_list[week][0];
- 使用 {% with %} 提升可读性与复用性,避免重复调用;
- 过滤器内置异常捕获,防止模板崩溃,返回 None(可配合 |default:”–” 处理空值);
- 切勿在视图中“预展开”所有数据(如构建含完整活动结构的字典),这会破坏关注点分离;保持逻辑在后端、展示在模板,而动态索引由过滤器桥接。
? 进阶建议:若频繁操作此类嵌套结构,可在视图中将 activity_list 封装为支持属性访问的类(如 WeekActivities),但对简单场景,自定义过滤器是最简洁、符合 Django 设计哲学的方案。