Python循环渲染HTML邮件模板时数据无法正确匹配字段的问题
问题根因
渲染失败是三个错误叠加导致的:
- 数据结构和遍历逻辑不匹配:你传入的
picks是列存储字典(每个键对应一整列的数组),但模板里写{% for pick in picks %}时,Python字典默认遍历的是键名,也就是四次循环拿到的pick分别是'stocks'/'prices'/'option_details'/'change'四个字符串,字符串没有stock/prices这类属性,Jinja2取不到值就返回空,和你渲染出来的4个空行完全对应。 - 模板语法错误:你直接在HTML里写
#当注释,Jinja2不识别这种注释语法,这些#会被当成普通文本输出到页面;而且你写的字段名和字典里的键名也不匹配(模板里写的是pick.stock,字典里键是stocks多了个s)。 - HTML结构错误:你在
<tbody>下直接写了个没被<tr>包裹的<td align='left'>{{ picks }}</td>,浏览器会把它当成异常内容直接输出字典的原始字符串,就是你看到的那串字典原文。
修复方案
二选一即可:
方案1:调整数据结构为行存储(适配你原有模板的写法)
先在Python端把列存的字典转成每行一个对象的数组,再传入模板:
# 列存格式转成行存格式 formatted_picks = [] for idx in range(len(picks['stocks'])): formatted_picks.append({ 'stock': picks['stocks'][idx], 'prices': picks['prices'][idx], 'option_details': picks['option_details'][idx], 'change': picks['change'][idx] }) # 渲染时传入转换后的数据 msg = MIMEText( Environment().from_string(html_data).render(picks=formatted_picks, date=date_original), "html" )
同时修正模板里的错误:
- 删除
<tbody>下多余的、未被<tr>包裹的<td align='left'>{{ picks }}</td> - 把直接写
#的注释换成Jinja2官方注释格式{# 注释内容 #},或者直接删掉注释行,避免无效内容输出。
修正后的表格核心部分代码:
<tbody> {% for pick in picks %} <tr> <td align='center'>{{ pick.stock }}</td> <td align='center'>{{ pick.prices }}</td> {# 这是Jinja2正确注释格式,内容不会输出到最终页面 #} <td align='center'>{{ pick.option_details }}</td> <td align='center'>{{ pick.change }}</td> </tr> {% endfor %} </tbody>
方案2:不改动Python端数据,直接调整模板遍历逻辑
如果不想改Python侧的数据结构,直接在模板里按索引遍历对齐的四个数组即可,核心循环部分替换为:
<tbody> {% for i in range(picks.stocks|length) %} <tr> <td align='center'>{{ picks.stocks[i] }}</td> <td align='center'>{{ picks.prices[i] }}</td> <td align='center'>{{ picks.option_details[i] }}</td> <td align='center'>{{ picks.change[i] }}</td> </tr> {% endfor %} </tbody>
记得同样删掉那个多余的直接输出picks字典的td,以及无效的#注释行。
内容的提问来源于stack exchange,提问作者Doing Things Occasionally
相关产品推荐
相关产品推荐

