【问题标题】:jinja2: including script, replacing {{variable}} and json encoding the resultjinja2:包括脚本,替换 {{variable}} 和 json 编码结果
【发布时间】:2016-09-08 13:06:01
【问题描述】:

我正在尝试使用 Jinja2 构建一个 json 文档,并且该文档有一个嵌套脚本。该脚本包含{{<variables>}},我需要将其与非json字符一起替换。因此,脚本之后需要使用json.dumps()进行json转义。

str = '{ "nestedScript" : {% include "scripts/sc.ps1" | json %} }'

escape 函数是不够的,因为最终产品包含的字符是有效的 HTML,但不是 JSON。

我的想法是这样的:

str = '{ "nestedScript" : {{ include("scripts/sc.ps1") | json}} %} }'

使用一些自定义过滤器或其他东西,但我似乎无法编写包含函数,以便它也可以在脚本中进行变量替换。到目前为止,这是我的脚本,我将其包含为全局:

完整示例

文件夹结构:

 .
 └── templates
     ├── test.json
     └── scripts
         └── script.ps1

模板文件:

test.json = '{
  "nestedScript" : {{ include("scripts/script.ps1") | json}}
}'

脚本:

loader = jinja2.FileSystemLoader("templates")
env = jinja2.Environment(loader=self.loader)
template = env.get_template("test.json")
template.render({
        'service_name': 'worker',
        'context_name': 'googlesellerratings',
    })

结果:

{
  "nestedScript" : "echo {{service_name}}"
}

【问题讨论】:

  • 你能举一个失败的例子吗?要使您的 include() 函数正常工作,它必须返回 JSON。因此,如果模板是带有{{…}} 占位符的文本文件,则该函数必须进行替换,然后对其进行反序列化,以便再次被| json 过滤器序列化。似乎没有意义。
  • 真正失败的不是json序列化,而是调用render时没有使用提供给模板的Context变量进行渲染。在当前示例中,任何 {{..}} 块都不会被渲染,我不知道如何实现这一点并将其转换为安全的 json。
  • 示例中缺少scripts/script.ps1 的内容以及对结果错误或您实际想要的结果的描述。此外程序不完整,缺少jinja2 的导入,未定义的self,模板结果被丢弃而不是打印。
  • 而且 Jinja2 2.8 版中没有include() 函数和json 过滤器。这些是如何定义的?

标签: python json jinja2


【解决方案1】:

以一种感觉有点生硬的方式解决了这个问题,所以我希望得到一些反馈。在实例化我的类时,我定义了一个名为 include_script 的全局函数:

loader = jinja2.FileSystemLoader(templates_folder)
env = inja2.Environment(loader=self.loader)

env.globals['include_script'] = render_script_func(env)

render_script_func 返回一个从环境中检索上下文并使用它来呈现我引用的文件的函数:

def render_script_func(env):
    def render_script(name):
        ctx = env.globals['context']
        tmpl = env.get_template(name)
        raw = tmpl.render(ctx)            
        return json.dumps(raw)
    return render_script

现在,在渲染之前,只需将渲染上下文添加到全局 context 对象:

template = env.get_template(template_name)
template.environment.globals["context"] = ctx
renderedData = template.render(ctx)

当模板使用{{ include_script("path/to/script") }} 时,脚本会被渲染,然后被 json 编码。

还是觉得有点不对劲,不过就这样吧。

【讨论】:

    【解决方案2】:

    鉴于(不完整的)示例,您似乎正在搜索 filter 标记。

    首先以实际可运行的形式编写脚本,并根据json.dumps() 定义json 过滤器:

    import json
    import jinja2
    
    loader = jinja2.FileSystemLoader('templates')
    env = jinja2.Environment(loader=loader)
    env.filters['json'] = json.dumps
    template = env.get_template('test.json')
    print(
        template.render({
            'service_name': 'worker',
            'context_name': 'googlesellerratings',
        })
    )
    

    缺少 PowerShell 脚本,如果在 JSON (") 中按原样使用会导致问题:

    echo "{{service_name}}"
    

    现在test.json 模板的解决方案:

    {
      "nestedScript" : {% filter json %}{% include "scripts/script.ps1" %}{% endfilter %}
    }
    

    最后是打印结果:

    {
      "nestedScript" : "echo \"worker\""
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 2022-08-15
      • 2010-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      相关资源
      最近更新 更多