Flask Jinja模板if嵌套for循环时表格行无法渲染问题
问题背景
需要实现的效果为:仅当查询返回有效记录时,才在表格中渲染所有查询到的记录,初始模板实现代码如下:
{% if l > 0 %} {% for record in precord %} <tr> <td colspan=1>{{ record['date'] }}</td> <td colspan=2>{{ record['tasknote'] }}</td> </tr> {% endfor %} {% else %} <tr> <td colspan=3><center>No previous contacts. Get working!</center></td> </tr> {% endif %}
其中变量l为后端传入的查询返回记录总条数。实际测试时if判断逻辑可以根据记录数正确触发对应分支,但添加该if外层包裹后,存在记录时表格行始终无法正常输出;移除计数判断的包裹层时代码可完全正常运行,查阅Jinja官方文档未发现语法错误。
对应负责渲染模板的后端路由代码如下:
@app.route('/view/<id>', methods=["GET", "POST"]) @login_required def view(id): form = CreatePR() record = people.find_one({"_id": ObjectId(id)}) precord = history.find({"parentRecord": str(record['_id'])}).sort('date',pymongo.ASCENDING) listl = len(list(precord)) if request.method == "GET": return render_template('view.html', form=form, people=record, precord=precord, auth=current_user.is_authenticated, id=id, l=listl) elif request.method == "POST": date = request.form.get('date') tasknote = request.form.get('tasknote') adate = datetime.today() history.insert_one({"date": date, "tasknote": tasknote, "dateAdded": adate.strftime("%x"), "parentRecord": id}) flash('Your record has been added successfully.') return redirect(url_for('view', id=id))
故障原因
问题出在PyMongo的游标特性上:history.find()返回的是一次性迭代游标,执行listl = len(list(precord))操作时,已经将游标遍历到末尾完成了列表转换,游标不会自动重置到起始位置。后续把已经耗尽的游标传入模板,Jinja执行for record in precord循环时拿不到任何数据,因此虽然l的数值判断正确(大于0进入了对应分支),但循环体不会输出任何内容。
移除if判断包裹后代码看似正常,本质是之前测试时没有执行len(list(precord))这行耗尽游标的操作,游标还处于初始位置,可以正常遍历。
修复方案
两种方案均可解决问题,第二种更简洁:
- 方案1:后端转换列表后复用结果
将游标转列表的结果保存为变量,同时用于计数和传入模板,不要直接传递已耗尽的游标:# 原代码 listl = len(list(precord)) 替换为以下两行 precord_list = list(precord) listl = len(precord_list) # render_template参数中 precord=precord 替换为 precord=precord_list - 方案2:利用Jinja原生特性省略额外计数
Jinja的for循环原生支持else分支:当循环对象无任何内容可迭代时,自动执行else块逻辑,完全不需要后端额外传长度变量l,模板可以直接简化为:
注意使用该方案时,后端依然需要提前将游标转为列表传入,避免其他逻辑提前耗尽游标导致遍历为空。{% for record in precord %} <tr> <td colspan=1>{{ record['date'] }}</td> <td colspan=2>{{ record['tasknote'] }}</td> </tr> {% else %} <tr> <td colspan=3><center>No previous contacts. Get working!</center></td> </tr> {% endfor %}
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

