Import a Python module into a Jinja template?

PythonJinja2Python Import

Python Problem Overview


Is it possible to import a Python module into a Jinja template so I can use its functions?

For example, I have a format.py file that contains methods for formatting dates and times. In a Jinja macro, can I do something like the following?

{% from 'dates/format.py' import timesince %}

{% macro time(mytime) %}
<a title="{{ mytime }}">{{ timesince(mytime) }}</a>
{% endmacro %}

Because format.py is not a template, the code above gives me this error:

UndefinedError: the template 'dates/format.py' (imported on line 2 in 'dates/macros.html') does not export the requested name 'timesince'

...but I was wondering if there was another way to achieve this.

Python Solutions


Solution 1 - Python

Within the template, no, you cannot import python code.

The way to do this is to register the function as a jinja2 custom filter, like this:

In your python file:

from dates.format import timesince

environment = jinja2.Environment(whatever)
environment.filters['timesince'] = timesince
# render template here

In your template:

{% macro time(mytime) %}
<a title="{{ mytime }}">{{ mytime|timesince }}</a>
{% endmacro %}

Solution 2 - Python

Just pass the function into the template, like so

from dates.format import timesince
your_template.render(timesince)

and in the template, just call it like any other function,

{% macro time(mytime) %}
    <a title="{{ mytime }}">{{ timesince(mytime) }}</a>
{% endmacro %}

Functions are first-class citizens in python, so you can pass them around just like anything else. You could even pass in a whole module if you wanted.

Solution 3 - Python

A template doesn't know import, but you can teach it with the importlib:

import importlib
my_template.render( imp0rt = importlib.import_module )  # can't use 'import', because it's reserved

(you can also name it "import" by passing the argument with a dict)

kwargs = { 'import' : importlib.import_module }
my_template.render( **kwargs )

then in the jinja-template, you can import any module:

{% set time = imp0rt( 'time' ) %}
{{ time.time() }}

Solution 4 - Python

You can export all of the symbols available in a module by providing the modules _dict_ as a parameter to the jinja template render method. The following will make available functions and types of _builtin_, inspect and types module to the template.

import __builtin__
import inspect
import types
  
env=RelEnvironment()
template = env.get_template(templatefile)

export_dict={}
export_dict.update(__builtin__.__dict__)
export_dict.update(types.__dict__)
export_dict.update(inspect.__dict__)

result=template.render(**export_dict)

Within template, to use a function of the exported modules similar to the following:

{%- for element in getmembers(object) -%}
{# Use the getmembers function from inspect module on an object #}
{% endfor %}

Solution 5 - Python

You can pass module to render function like this:

from src.constants import proto

wls = {"workloads": [{"name": "test1", "p": "UDP"}, {"name": "test2", "p": "TCP_NONTLS"}]}

env = Environment(
        loader=PackageLoader("src", "templates")
    )
template = env.get_template("lds.yaml.j2")
print(template.render(wls,proto=proto))

In jinja template you can now use proto:

{% if workload.p == proto.udp -%}

Solution 6 - Python

If you're using Flask, you can add imports to the Jinja context using a Flask context processor. For example, here's how you can make the modules datetime, email.utils, and os.path available in all templates:

app = Flask(__name__)

import email.utils, datetime, os.path
@app.context_processor
def add_imports():
    # Note: we only define the top-level module names!
    return dict(email=email, datetime=datetime, os=os)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt NorrisView Question on Stackoverflow
Solution 1 - PythonWoobleView Answer on Stackoverflow
Solution 2 - PythonnightpoolView Answer on Stackoverflow
Solution 3 - PythonSkandixView Answer on Stackoverflow
Solution 4 - PythonSimon BlackView Answer on Stackoverflow
Solution 5 - PythonZiliView Answer on Stackoverflow
Solution 6 - Pythonntc2View Answer on Stackoverflow