Reputation: 26668
Is there a way to overload how jinja evaluates all variable expressions?
I want to change how the templating system evaluates all variables, in {{ variable }}
expressions, and in {% if variable %}
type statements as well (I'd like to make it load them from a specific location in a specific way, by name).
For instance, if someone puts {{ this.is.a.test }}
in a template, I want to use jmespath (https://github.com/jmespath/jmespath.py) to load the variable from a known dictionary in the context, instead of the normal route. It would pick "hello" from this dictionary:
{
"this": {
"is": {
"a": {
"test": "hello"
}
}
}
}
This would also evaluate to true: {% if this.is.a.test == "hello" %}
Is this something that is possible?
Upvotes: 0
Views: 215
Reputation: 42497
Just pass your dict in as the context
and it will work out of the box.
>>> from jinja2 import Environment
>>> env = Environment()
>>> template = env.from_string('{{ this.is.a.test }}')
>>> context = {
... "this": {
... "is": {
... "a": {
... "test": "hello"
... }
... }
... }
... }
>>> print(template.render(**context))
hello
There are two factors which make this work. First, as Jinja's documentation explains:
You can use a dot (
.
) to access attributes of a variable in addition to the standard Python__getitem__
“subscript” syntax ([]
).The following lines do the same thing:
{{ foo.bar }} {{ foo['bar'] }}
The second is the use of **
when passing in a dictionary expands the first level to keywords and values. In other words, the following two lines are exactly the same:
foo(**{'bar': 'baz'})
foo(bar='baz')
Of course, Jinja's Template.render method simply accepts keywords as root level variables, so that gives you what you want.
Upvotes: 1