"eval" statement in Jinja2 template
Question:
I’m trying to convert some old Smarty templates to Jinja2.
Smarty uses an eval
statement in the templates to render a templated string from the current context.
Is there an eval
equivalent in Jinja2 ? Or what is a good workaround for this case ?
Answers:
Use the @jinja2.contextfilter decorator to make a Custom Filter for rendering variables:
from flask import render_template_string
from jinja2 import contextfilter
from markupsafe import Markup
@contextfilter
def dangerous_render(context, value):
Markup(render_template_string(value, **context)).format()
Then in your template.html file:
{{ myvar|dangerous_render }}
I was looking for a similar eval use case and bumped into a different stack overflow post.
This worked for me
routes.py
def index():
html = "<b>actual eval string</b>"
return render_template('index.html', html_str = html)
index.html
<html>
<head>
<title>eval jinja</title>
</head>
<body>
{{ html_str | safe }}
</body>
</html>
Reference : Passing HTML to template using Flask/Jinja2
If you are using jinja version 3.0, contextfilter has deprecated and removed in Jinja 3.1. Use pass_context() instead. Refer here for more details pertaining this.
from jinja2 import pass_context, Template
from markupsafe import Markup
@pass_context
def foo(context, value):
return Markup(Template(value).render(context)).render()
then in your template
{{ myvar|foo }}
Based on the answers from Alan Hamlett and Hilario Nengare, I implemented the following "eval" filter for Jinja2 (>=3.0). I found that the case of undefined input should also be handled, plus I added the ability to specify additional variables as input for the expression:
import jinja2
@jinja2.pass_context
def filter_eval(context, input, **vars):
if input == jinja2.Undefined:
return input
return jinja2.Template(input).render(context, **vars)
Usage, when adding filter_eval() as filter "eval":
-
Template source:
{% set rack_str = 'Rack {{ rack }}' %}
{{ rack_str | eval(rack='A') }}
-
Rendered template:
Rack A
I’m trying to convert some old Smarty templates to Jinja2.
Smarty uses an eval
statement in the templates to render a templated string from the current context.
Is there an eval
equivalent in Jinja2 ? Or what is a good workaround for this case ?
Use the @jinja2.contextfilter decorator to make a Custom Filter for rendering variables:
from flask import render_template_string
from jinja2 import contextfilter
from markupsafe import Markup
@contextfilter
def dangerous_render(context, value):
Markup(render_template_string(value, **context)).format()
Then in your template.html file:
{{ myvar|dangerous_render }}
I was looking for a similar eval use case and bumped into a different stack overflow post.
This worked for me
routes.py
def index():
html = "<b>actual eval string</b>"
return render_template('index.html', html_str = html)
index.html
<html>
<head>
<title>eval jinja</title>
</head>
<body>
{{ html_str | safe }}
</body>
</html>
Reference : Passing HTML to template using Flask/Jinja2
If you are using jinja version 3.0, contextfilter has deprecated and removed in Jinja 3.1. Use pass_context() instead. Refer here for more details pertaining this.
from jinja2 import pass_context, Template
from markupsafe import Markup
@pass_context
def foo(context, value):
return Markup(Template(value).render(context)).render()
then in your template
{{ myvar|foo }}
Based on the answers from Alan Hamlett and Hilario Nengare, I implemented the following "eval" filter for Jinja2 (>=3.0). I found that the case of undefined input should also be handled, plus I added the ability to specify additional variables as input for the expression:
import jinja2
@jinja2.pass_context
def filter_eval(context, input, **vars):
if input == jinja2.Undefined:
return input
return jinja2.Template(input).render(context, **vars)
Usage, when adding filter_eval() as filter "eval":
-
Template source:
{% set rack_str = 'Rack {{ rack }}' %} {{ rack_str | eval(rack='A') }}
-
Rendered template:
Rack A