向Jinja宏传递单元素数组时的编译结果不符合预期问题
解决Jinja宏单元素数组解析异常问题
问题根源
你遇到的问题本质是Python语法特性导致的:('02')并不会被识别为单元素元组,它只是带括号的字符串,最终求值为'02'。当宏接收这个参数后直接拼入SQL语句,就会变成in 02,丢失了必要的括号和引号。正确的单元素元组写法应该是('02',)(注意末尾的逗号)。
解决方案
方案1:调用宏时传入正确的可迭代对象
在调用宏时,确保传递的是列表或带逗号的单元素元组:
{{ test_macro('code', ('02',)) }} {{ test_macro('code', ['02']) }}
此时宏接收的codes参数是可迭代集合,Jinja会自动将其格式化为符合SQL规范的('02')或['02'],两种格式在SQL的IN子句中都能正常工作。
方案2:修改宏内部逻辑,兼容单个值输入
如果希望宏能自动处理单个字符串输入,无需调用方额外加逗号,可以修改宏的逻辑,统一处理单个值和集合:
{% macro test_macro( col_name=column_name, codes=list_of_codes ) %} {# 把单个值转为单元素列表,统一后续处理逻辑 #} {% set codes = [codes] if codes is string or not codes is iterable else codes %} {# 转义元素中的单引号,避免SQL注入风险 #} {% set formatted_codes = codes | map('string') | map('replace', "'", "''") | list %} {{ log("Codes:" ~ codes, True) }} case when {{ col_name }} in ('{{ "', '".join(formatted_codes) }}') then 1 else 0 end {% endmacro %}
这个修改实现了两个核心功能:
- 自动将单个字符串或非可迭代值转为列表,确保后续处理的一致性
- 对每个元素进行单引号转义,避免因内容含单引号导致SQL语法错误或注入风险
现在无论你传入'02'、('02')、('02',)还是['02'],宏都会输出正确的SQL:
case when code in ('02') then 1 else 0 end
方案3:简化格式处理(适用于可信输入场景)
如果输入内容是完全可信的,无需考虑SQL注入,也可以用更简洁的写法:
{% macro test_macro( col_name=column_name, codes=list_of_codes ) %} {% set codes = [codes] if codes is string else codes %} {{ log("Codes:" ~ codes, True) }} case when {{ col_name }} in ({{ codes | map('string') | map('quote') | join(', ') }}) then 1 else 0 end {% endmacro %}
这里用quote过滤器直接给每个元素添加单引号,再通过join拼接,效果和方案2一致,但省略了单引号转义步骤。
内容的提问来源于stack exchange,提问作者Shankar
相关产品推荐
相关产品推荐

