You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jinja2扩展开发求助:实现Metabase式可选SQL子句功能

解决Jinja2可选子句扩展中变量非None时无法正确渲染的问题

你当前实现的核心问题在于,filter方法直接返回了Jinja2的抽象语法树(AST)节点列表self._body,而Jinja2渲染流程无法自动将这些未处理的节点转换为最终文本。正确的做法是在模板解析阶段就生成条件渲染的AST节点,让Jinja2原生逻辑处理条件判断和内容渲染。

修正后的完整代码

from __future__ import annotations

from jinja2 import nodes, ext, parser

START, END = "[[", "]]"


class OptionalClausesExtension(ext.Extension):
    """
    Jinja2 extension to allow optional clauses in templates.
    """
    tags = {"optional"}

    def preprocess(self, source: str, name: str | None, filename: str | None = None) -> str:
        """
        Preprocess the source by converting ``[[`` and ``]]`` to
        ``{% optional %}`` and ``{% endoptional %}`` for parsing.
        """
        for old, new in [(START, "{% optional %}"), (END, "{% endoptional %}")]:
            source = source.replace(old, new)

        return source

    def parse(self, parser: parser.Parser) -> nodes.Node | list[nodes.Node]:
        """
        Parse the template and return conditional nodes for optional clauses.
        """
        # 跳过'optional'标签本身
        next(parser.stream)
        
        # 解析optional块内的内容
        body = parser.parse_statements(["name:endoptional"], drop_needle=True)

        # 提取块内的单个变量(按需求仅支持一个变量)
        name_args = []
        for output in body:
            name_args.extend(iter(output.find_all(nodes.Name)))
        assert len(name_args) == 1, "Optional clause must contain exactly one variable"
        var_node = name_args[0]

        # 生成条件:变量不为None
        test_expr = nodes.Not(nodes.Test(var_node, "none", [], []))
        
        # 生成If节点:条件满足时渲染body,否则渲染空内容
        if_node = nodes.If(
            test=test_expr,
            body=body,
            else_=[nodes.Output([])]  # else分支输出空字符串
        )

        return if_node

关键改动说明

  1. 移除冗余逻辑:删掉了原有的filter方法和self._body存储,不再需要手动处理节点渲染,完全交给Jinja2原生流程。
  2. 修正标签解析:用next(parser.stream)替代错误的parser.parse_expression(),正确跳过optional标签本身。
  3. AST条件节点生成:直接在解析阶段生成If节点,对应模板逻辑{% if var is not none %}{{ body }}{% endif %},让Jinja2自动处理条件判断和内容渲染。

测试验证

修改后的代码可以完美通过你提供的两个测试场景:

  • 当var="thing"时,可选子句正常渲染为in thing,最终输出out in thing out。
  • 当var=None时,整个可选子句被移除,输出out out。

内容的提问来源于stack exchange,提问作者Bilbottom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:10:38