ChatGPT解决这个技术问题 Extra ChatGPT

How to load jinja template directly from filesystem

The jinja API document at pocoo.org states:

The simplest way to configure Jinja2 to load templates for your application looks roughly like this:

from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('yourapplication', 'templates'))

This will create a template environment with the default settings and a loader that looks up the templates in the templates folder inside the yourapplication python package.

As it turns out, this isn't so simple because you have to make/install a python package with your templates in it, which introduces a lot of needless complexity, especially if you have no intention of distributing your code. You can refer to SO questions on the topic here and here, but the answers are vague and unsatisfying.

What a naive newbie wants to do, obviously, is just load the template directly from the filesystem, not as a resource in a package. How is this done?


C
Chris Seymour

Here's how: use a FileSystemLoader instead of a PackageLoader. I found examples on the web here and here. Let's say you have a python file in the same dir as your template:

./index.py
./template.html

This index.py will find the template and render it:

#!/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)

It turns out, the jinja2 API doc does have a section which discusses all the built-in loaders, so it's kind of embarrassing not to have noticed that right away. But the introduction is worded such that PackageLoader seems to be the default, "simplest" method. For newcomers to python, this can lead to a wild goose chase.


Sort of ridiculous you can't load a template from a file in one line e.g. jinja2.load_template('template.html')
I always have a Wrapper that I just call Jinja2 in my applications where I put all this verbosity, then call it like: Jinja2.render(template_name, data)
Important security risk! You almost certainly want to call jinja2.Environment(loader=templateLoader, autoescape=True). Or see the api docs for more info. Just found out I ended up with a major XSS vulnerability from following this answer :/
Both links at top are broken.
C
Cas

A simpler way is to directly call the jinj2.Template constructor and use open to load the file:

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

Unfortunately this does not allow setting up custom filters. The template loading generates an error during initialization because the custom filter doesn't exist yet. And this way you only have access to the environment (to include the filter) after initialization.
M
Martin Thoma

Here is the one liner:

from jinja2 import Template

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

Then you can render the template on another line, or for all in one line:

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

Sadly this will break if there is template inheritance, as Jinja won't be able to find the referenced templates.
But luckily this is simple and enough if you don't use inheritance, and just wan't to send some simple email for example.. :)
The other major downside to this one liner is that you don't close the file. At worst, this leads to file corruption. Would highly recommend using a python context and making it two lines rather than one!
@NikhilShinday Failing to close a file that is open for reading (the default mode of open) will absolutely never lead to file corruption.
S
Sairam Krish

If using Python 3.4+ and Jinja2 - v2.11+ -- we can combine python's pathlib and Filesystem to simplify the flow

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')

I am not comfortable with using directly Template(file) since Jinja's template inheritance processing may not work well.

Pathlib support is only added in latest version of Jinja - v2.11+


Path(p) is redundant.
S
Shaido
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)

Format your code, provide some context and explain why your answer is better than the accepted one.