Jinja2中如何处理变量为字符串或列表的循环问题?
解决Jinja模板中字符串被拆分为字符遍历的问题
问题场景
需求为:变量是列表时,循环输出每行allow 子网段;变量是字符串时,直接输出一行allow 子网段。但当前模板渲染字符串变量时,会被拆成单个字符逐个输出,不符合预期。
当前模板
{% if prefixes[1] is defined %} {%- for p in prefixes -%} allow {{p}} {% endfor -%} {% else %} allow {{prefixes}} {% endif %} {# 期望下方走else分支,输出一行allow 30.0.0.0/24 #} {% if subnets[1] is defined %} {%- for s in subnets -%} allow {{s}} {% endfor -%} {% else %} allow {{subnets}} {% endif %}
变量值
{ "prefixes": ["10.0.0.0/24", "20.0.0.0/24"], "subnets": "30.0.0.0/24" }
实际渲染结果
allow•10.0.0.0/24 allow•20.0.0.0/24 allow•3 allow•0 allow•. allow•0 allow•. allow•0 allow•. allow•0 allow•/ allow•2 allow•4
预期渲染结果
allow•10.0.0.0/24 allow•20.0.0.0/24 allow•30.0.0.0/24
问题根源
Jinja中字符串属于可迭代对象,且能通过索引访问单个字符(比如"30.0.0.0/24"[1]对应字符0),所以{% if subnets[1] is defined %}的判断结果为真,会进入for循环遍历字符串的每个字符,导致错误输出。
解决方案
替换判断条件,直接检查变量是否为列表类型,或者判断是可迭代对象且不是字符串。推荐用更精准的列表类型判断:
修改后的模板
{% if prefixes is list %} {%- for p in prefixes -%} allow {{p}} {% endfor -%} {% else %} allow {{prefixes}} {% endif %} {# 现在会正确走else分支 #} {% if subnets is list %} {%- for s in subnets -%} allow {{s}} {% endfor -%} {% else %} allow {{subnets}} {% endif %}
如果需要兼容其他可迭代的非字符串类型,也可以用以下判断方式:
{% if prefixes is iterable and prefixes is not string %} {%- for p in prefixes -%} allow {{p}} {% endfor -%} {% else %} allow {{prefixes}} {% endif %}
验证结果
修改后的模板渲染后,会得到符合预期的输出:
allow•10.0.0.0/24 allow•20.0.0.0/24 allow•30.0.0.0/24
内容的提问来源于stack exchange,提问作者NetworkLearner
相关产品推荐
相关产品推荐

