
在 Django 模板中无法直接用字符串变量(如 "123")驱动 {% for %} 循环,必须传入可迭代对象(如 range(n) 或列表),且需通过 get_context_data() 正确注入上下文,而非 get_queryset()。
在 django 模板中无法直接用字符串变量(如 `"123"`)驱动 `{% for %}` 循环,必须传入可迭代对象(如 `range(n)` 或列表),且需通过 `get_context_data()` 正确注入上下文,而非 `get_queryset()`。
Django 模板的 {% for %} 标签只能遍历真正的 Python 可迭代对象(如 list、tuple、range、QuerySet),而不能遍历字符串(即使内容是数字序列,如 "12345")。你当前代码中:
volgordelijst = ""
for i in range(1, grondstoffen_count + 1):
volgordelijst += str(i) # → 结果是字符串 "12345",不是可迭代的数字序列!
该字符串在模板中 {% for i in volgordelijst %} 实际会逐字符迭代:'1', '2', '3', '4', '5' —— 而非整数 1, 2, 3, 4, 5,这不仅语义错误,还导致后续 {{ i }} 渲染为字符而非数字,使 query_grondstof{{ i }}naam 变成 query_grondstof1naam(正确)→ query_grondstof2naam(正确)…但若用户输入 10,字符串变为 "12345678910",循环将产生 11 次迭代(字符 '1','2',...,'1','0'),完全失控。
✅ 正确做法:在视图中传递 range(n) 对象
修改 get_context_data() 方法,移除 get_queryset() 中的 render() 调用(它破坏了 ListView 生命周期),并在上下文中注入 range(grondstoffen_count):
# views.py
class BehandelNieuweVoorraadView(generic.ListView):
template_name = "Ano_app/BehandelNieuweVoorraad.html"
model = Grondstof
checkaankomst = []
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['grondstof_options'] = self.optieLijst(1)
if self.checkaankomst == []:
context['aankomstgrondstoffen'] = self.optieLijst(2)
self.checkaankomst.extend(context['aankomstgrondstoffen'])
else:
context['aankomstgrondstoffen'] = self.checkaankomst
# ✅ 新增:从 GET 参数获取 count,并注入 range 对象
grondstoffen_count = self.request.GET.get('grondstoffen_count', '0')
try:
n = int(grondstoffen_count)
context['grondstoffen_range'] = range(1, n + 1) # [1, 2, ..., n]
except (ValueError, TypeError):
context['grondstoffen_range'] = range(0) # 空 range,安全兜底
return context
# ... optieLijst() 方法保持不变 ...
def get_queryset(self):
# ❌ 移除所有 render() 调用!ListView 的 get_queryset 必须返回 QuerySet
if 'submit_hoeveelheden' in self.request.GET:
# 处理提交逻辑(不返回响应)
grondstofnamen = [self.request.GET.get(f"query_grondstof{i}naam", "") for i in range(1, 6)]
grondstofhoeveelheden = [
float(self.request.GET.get(f"query_grondstof{i}hoeveelheid", "0"))
for i in range(1, 6)
]
verdeelAangekomenGrondstoffen(grondstofnamen, grondstofhoeveelheden, ...)
elif 'submit_correctelevering' in self.request.GET:
pass # 仅处理,不返回
# ✅ 不做任何 return → 默认调用父类 get_queryset() 返回 Grondstof.objects.all()
return super().get_queryset() # 保证返回 QuerySet
模板中直接使用 grondstoffen_range:
<!-- BehandelNieuweVoorraad.html -->
⚠️ 关键注意事项:
-
永远不要在
get_queryset()中调用render():它会中断 Django 的通用视图流程,导致上下文丢失、分页失效、get_context_data()不被调用; -
range(n)是轻量级可迭代对象,模板中高效安全; - 若需保留用户已填数据(如刷新后恢复输入),可在模板中用
{{ request.GET.query_grondstof1naam }}回显; - 前端建议增加 JS 校验:当
grondstoffen_count改变时,动态生成/销毁表单区块,提升体验(非必须,但推荐)。
通过以上修正,即可实现「用户输入数量 → 后端生成对应 range → 模板精准循环渲染 N 组字段」的完整闭环。











