【问题标题】:How to load jinja template directly from filesystem如何直接从文件系统加载 jinja 模板
【发布时间】:2016-12-03 05:04:09
【问题描述】:

jinja API document at pocoo.org 声明:

配置 Jinja2 为您的应用程序加载模板的最简单方法大致如下所示:
from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('yourapplication', 'templates'))
这将创建一个具有默认设置的模板环境和一个在 yourapplication python 包内的 templates 文件夹中查找模板的加载器。

事实证明,这并不是那么简单,因为您必须制作/安装一个包含模板的 python 包,这会引入很多不必要的复杂性,尤其是在您不打算分发代码的情况下。可以参考herehere这个话题的SO问题,但是答案很模糊,不满意。

显然,一个天真的新手想要做的只是直接从文件系统加载模板,而不是作为包中的资源。 这是怎么做到的?

【问题讨论】:

    标签: python templates jinja2


    【解决方案1】:

    方法如下:使用FileSystemLoader 而不是PackageLoader。我在网上找到了例子herehere。假设您在与模板相同的目录中有一个 python 文件:

    ./index.py
    ./template.html
    

    这个 index.py 会找到模板并渲染它:

    #!/usr/bin/python
    import jinja2
    
    templateLoader = jinja2.FileSystemLoader(searchpath="./")
    templateEnv = jinja2.Environment(loader=templateLoader)
    TEMPLATE_FILE = "template.html"
    template = templateEnv.get_template(TEMPLATE_FILE)
    outputText = template.render()  # this is where to put args to the template renderer
    
    print(outputText)
    

    事实证明,jinja2 API 文档确实有一个section which discusses all the built-in loaders,所以没有马上注意到这一点有点尴尬。但是介绍的措辞使得PackageLoader 似乎是默认的“最简单”的方法。对于 python 的新手来说,这可能会导致一场大乱斗。

    【讨论】:

    • 有点可笑,您不能在一行中从文件中加载模板,例如jinja2.load_template('template.html')
    • 我总是有一个 Wrapper,我只是在我的应用程序中调用 Jinja2,我把所有这些冗长的地方都放在里面,然后这样称呼它:Jinja2.render(template_name, data)
    • 重要的安全风险!您几乎肯定想致电jinja2.Environment(loader=templateLoader, autoescape=True)。或查看api docs 了解更多信息。刚刚发现我遵循这个答案最终遇到了一个主要的 XSS 漏洞:/
    • 顶部的两个链接都已损坏。
    【解决方案2】:

    更简单的方法是直接调用jinj2.Template构造函数,使用open加载文件:

    from jinja2 import Template
    with open('template.html.jinja2') as file_:
        template = Template(file_.read())
    template.render(name='John')
    

    【讨论】:

    • 不幸的是,这不允许设置自定义过滤器。由于自定义过滤器尚不存在,因此模板加载在初始化期间会产生错误。这样你就只能在初始化后访问环境(包括过滤器)。
    【解决方案3】:

    这是一个班轮:

    from jinja2 import Template
    
    with open('template_file.j2') as f:
        template = Template(f.read())
    

    然后你可以在另一行渲染模板,或者在一行中渲染:

    with open('template_file.j2') as f:
        rendered = Template(f.read()).render(var="TEXT")
    

    【讨论】:

    • 遗憾的是,如果存在模板继承,这将中断,因为 Jinja 将无法找到引用的模板。
    • 但幸运的是,如果您不使用继承,并且只是不想发送一些简单的电子邮件,这很简单而且足够了.. :)
    • 这一行的另一个主要缺点是您不会关闭文件。在最坏的情况下,这会导致文件损坏。强烈建议使用 python 上下文并将其设置为两行而不是一行!
    【解决方案4】:

    如果使用 Python 3.4+ 和 Jinja2 - v2.11+ -- 我们可以结合 python 的 pathlib 和 Filesystem 来简化流程

    from pathlib import Path
    ...
    
    p = Path(__file__).parent.parent / 'templates' # sample relative path
    env = Environment(
        loader=FileSystemLoader(Path(p)))
    template = env.get_template('your_file.jinja2')
    

    我不习惯直接使用Template(file),因为 Jinja 的模板继承处理可能效果不佳。

    Pathlib 支持仅在 Jinja 最新版本 - v2.11+ 中添加

    【讨论】:

      【解决方案5】:
      from jinja2 import Environment, select_autoescape, FileSystemLoader
      
      env = Environment(loader=FileSystemLoader(
      searchpath=folder_contain_list_html), autoescape=select_autoescape(['html', 'xml']))
      
      template = env.get_template('file_name_detail_template')
      
      body_html = template.render(**args)
      
      send_email(body_html)
      

      【讨论】:

      • 格式化您的代码,提供一些上下文并解释为什么您的答案比公认的更好。
      猜你喜欢
      • 2017-04-20
      • 2013-01-29
      • 2012-03-14
      • 1970-01-01
      • 1970-01-01
      • 2014-03-27
      • 1970-01-01
      • 2012-03-20
      • 1970-01-01
      相关资源
      最近更新 更多