如何直接从文件系统加载jinja模板

Jua*_*mas 46 python templates jinja2

我对python缺乏经验,所以当我在pocoo.org上阅读jinja API文档时,我误入歧途.它写道:

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

事实证明,这并不是那么简单,因为你必须在其中创建/安装包含模板的python包,这会带来许多不必要的复杂性,特别是如果你无意分发你的代码.您可以在此处此处参考有关此主题的SO问题,但答案含糊不清且不满意.

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

Jua*_*mas 71

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

./index.py
./template.html
Run Code Online (Sandbox Code Playgroud)

这个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)
Run Code Online (Sandbox Code Playgroud)

事实证明,jinja2 API文档确实有一个讨论所有内置加载器的部分,所以不要立即注意到它是一种尴尬.但引言的措辞PackageLoader似乎是默认的,"最简单"的方法.对于蟒蛇的新手来说,这可能导致一场疯狂的追逐.

  • 有点荒谬,你无法从一行中的文件加载模板,例如`jinja2.load_template('template.html')` (67认同)
  • **重要的安全风险!** 你几乎肯定想调用 `jinja2.Environment(loader=templateLoader, autoescape=True)`。或者参阅 [api 文档](https://jinja.palletsprojects.com/en/2.10.x/api/) 了解更多信息。刚刚发现我遵循这个答案最终遇到了一个重大的 XSS 漏洞:/ (14认同)
  • 我总是有一个包装器,我只在应用程序中称呼Jinja2,将所有这些详细信息放在其中,然后像这样称呼它:`Jinja2.render(template_name,data)` (3认同)

Cas*_*Cas 55

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

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

  • 不幸的是,这不允许设置自定义过滤器。由于自定义过滤器尚不存在,模板加载在初始化期间会生成错误。这样,您只能在初始化后访问环境(包括过滤器)。 (2认同)

bca*_*oll 28

这是一个班轮:

template = Template(open('template_file.j2').read())
Run Code Online (Sandbox Code Playgroud)

然后您可以在另一行或在一行中渲染模板:

rendered = Template(open('template_file.j2').read()).render(var="TEXT")
Run Code Online (Sandbox Code Playgroud)

  • 但幸运的是,如果您不使用继承,并且只是不想发送一些简单的电子邮件,那么这很简单并且足够了..:) (8认同)
  • 遗憾的是,如果存在模板继承,这将会中断,因为 Jinja 将无法找到引用的模板。 (2认同)
  • @NikhilShinday 无法关闭打开以供阅读的文件([`open`](https://docs.python.org/3/library/functions.html#open) 的默认模式)绝对不会导致文件腐败。 (2认同)
  • 我不清楚这对 Cas 的回答有何影响。 (2认同)

Sai*_*ish 12

如果使用 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')
Run Code Online (Sandbox Code Playgroud)

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

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

  • `Path(p)` 是多余的。 (6认同)