Jinja2 variable (string) not being printed if surrounded by {{ delimiter }} - python

I have a macro in jinja2 that was working perfectly up until I tried to pass a string to it that looks something like this /test/{{ vehicle.id }}. The string printed to the page is /test/.
The string is coming from a database, so I'm a little confused what's happening. It's like jinja is trying to parse the string and replace the values (which is actually what I'm trying to accomplish), but it's failing and ripping the expression out instead. I tried passing the vehicle dict to the macro as well to see if it would 'just work', but no dice. I thought if maybe I had vehicle available to the context it would work without much effort on my part.
Here's some simple sample code:
# Assume db_values.url is set to '/test/{{ vehicle.id }}'
{% macro banner(db_values, vehicle={}) %}
{% endmacro %}
And where I'm calling it:
# Assume vehicle = { 'id': '1' }
{{ vehicle.id }}
{{ db_values }}
<div class="banner-link">
{{ banner(db_values, vehicle) }}
</div>
And this is what's being outputted to the page:
1
{u'url': u'/test/'}
<div class="banner-link">
</div>
Hitting mongodb directly in terminal responds with:
{ 'url': 'test/{{ vehicle.id }}' }
Anybody else run into something like this before? Basically what I'm trying to do is allow somebody in an admin interface to use tokens in the url that are replaced at runtime based on the context of the page. Seems simple enough, but jinja keeps stripping it.

Okay, I solved this on my own. The reason my database value had the {{ vehicle.id }} syntax in it is because I wanted to jinja to parse it. So when jinja wasn't parsing it (probably because of a context issue), I took to a custom filter and I'm happily on my way.
Here's the gist of it:
Jinja2 Filter
from jinja2 import Environment
def replace_tokens(url, vehicle):
if url is not None:
url = Environment().from_string(url).render({ 'vehicle': vehicle })
return url
Macro
# Assume db_values.url is set to '/test/{{ vehicle.id }}'
{% macro banner(db_values, vehicle={}) %}
{% endmacro %}

Related

How to ignore special character in argument of render_template in Flask and HTML [duplicate]

I'm building an admin for Flask and SQLAlchemy, and I want to pass the HTML for the different inputs to my view using render_template. The templating framework seems to escape the HTML automatically, so all <"'> characters are converted to HTML entities. How can I disable that so that the HTML renders correctly?
To turn off autoescaping when rendering a value, use the |safe filter.
{{ something|safe }}
Only do this on data you trust, since rendering untrusted data without escaping is a cross-site scripting vulnerability.
MarkupSafe provides Jinja's autoescaping behavior. You can import Markup and use it to declare a value HTML safe from the code:
from markupsafe import Markup
value = Markup('<strong>The HTML String</strong>')
Pass that to the templates and you don't have to use the |safe filter on it.
From the Jinja docs section HTML Escaping:
When automatic escaping is enabled everything is escaped by default
except for values explicitly marked as safe. Those can either be
marked by the application or in the template by using the |safe
filter.
Example:
<div class="info">
{{data.email_content|safe}}
</div>
When you have a lot of variables that don't need escaping, you can use an autoescape override block:
{% autoescape false %}
{{ something }}
{{ something_else }}
<b>{{ something_important }}</b>
{% endautoescape %}
For handling line-breaks specifically, I tried a number of options before finally settling for this:
{% set list1 = data.split('\n') %}
{% for item in list1 %}
{{ item }}
{% if not loop.last %}
<br/>
{% endif %}
{% endfor %}
The nice thing about this approach is that it's compatible with the auto-escaping, leaving everything nice and safe. It can also be combined with filters, like urlize.
Of course it's similar to Helge's answer, but doesn't need a macro (relying instead on Jinja's built-in split function) and also doesn't add an unnecesssary <br/> after the last item.
Some people seem to turn autoescape off which carries security risks to manipulate the string display.
If you only want to insert some linebreaks into a string and convert the linebreaks into <br />, then you could take a jinja macro like:
{% macro linebreaks_for_string( the_string ) -%}
{% if the_string %}
{% for line in the_string.split('\n') %}
<br />
{{ line }}
{% endfor %}
{% else %}
{{ the_string }}
{% endif %}
{%- endmacro %}
and in your template just call this with
{{ linebreaks_for_string( my_string_in_a_variable ) }}
Use the safe filter in your template, and then sanitize the HTML with the bleach library in your view. Using bleach, you can whitelist the HTML tags that you need to use.
This is the safest, as far as I know. I tried both the safe filter and the Markup class, and both ways allowed me to execute unwanted JavaScript. Not very safe!

Assign a session variable in Jinja2 / flask in front end html page

Hello I have a problem with a select/option html where you can select the page number, so page 1 of 100, 2 of 200 etc... and then goes to page 1, 2, 3 ...
Everything works in the following code apart from the fact that inside the select button, after clicking on the page you want to go, after refreshing the page, it goes back to page 1, it always shows: page 1 of 100, even if actually in the url the page number is correct. I should use a session variable, but the problem is that I'm struggling to understand how to use it with Flask/Jinja2 directly in the html page. Someone can help?
using {% set session['page'] = page %} and then {{ session['page'] }} it gives me syntax error:
TemplateSyntaxError: expected token 'end of statement block', got '['
{% set session['page'] = page %}
<select onchange="window.location.href=this.value">
{%- for page in range (1,(form.total_PAGE.data | int) + 1 ) %}
<option value="{{ page }}">{{ session['page'] }}/{{ form.total_PAGE.data }}</option>
{%- endfor %}
</select>
In general, you cannot assign to an object atribute using set, neither using obj['attr'] or obj.attr syntax (see the documentation). However, you can enable the expression-statement extension and then set the attribute using dict update like this:
{% do session.update({'page': page}) %}
But as already stated in the comment, this doesn't really make sense and can be solved more cleanly using other approaches.
I have tested what mentioned by Tomáš Linhart but not worked for me as I did not update Expression statement extension and modify default what worked to assign a session variable in jinja2 flask is:
{% if session.update({session_var_name: []}) %}{% endif %}

Flask html not rendered when using Jinja2 templating tag

I'm using the (awesome) Flask framework to build a website and I now have a problem with html not being rendered properly. I've got a line in my template with an if-else depending on whether the public variable is True:
{{ theInfo if public else '<span style="background-color: green;">this info is hidden</span>' }}
Unfortunately, this simply displays the html in the browser, instead of rendering it. Do I need to somehow let Jinja know that its html should be rendered?
All tips are welcome!
By default Jinja escapes the passed data. Therefore you need to explicitly tell Jinja that data is safe to use:
{{ theInfo if public else '<span style="background-color: green;">this info is hidden</span>' | safe }}
If you want to display different html based on a value you need to first send this value in your call to render_template
python
def view():
variablename = True
return flask.render_template('page.html', public=variablename)
To check this value you add an if statement inside curly brackets, see code below
html
{% if public %}
<p>Public is true!</p>
{% else %}
<span ..../>
{% endif %}
A good first step is to go through the tutorial by Miguel Grinberg. http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

populate google chart datatable with arrayToDataTable in django template

I have a list of tuples passed to the template.
I want to populate a datatable with it.
Here is the code.
Does anyone know what is wrong with it? Currently nothing shows on the webpage.
Thank you.
var dt=new google.visualization.arrayToDataTable([
['Name','LastGPA','CurGPA','IntervalA','IntervalB','Major'],
{% for d in data %}
[{{d.0}},{{d.1}},{{d.2}},{{d.3}},{{d.4}},{{d.5}}]
{% if not forloop.last %},{% endif %}
{% endfor %}
]);
summary_table.draw(dt);
Here's a helper module for using the Visualization API with Django queries. You might find it easier to work with passing JSON, rather than building it in the template.

How to return raw html in a Flask app bypassing template transformations

I have just started building my first Flask app, which currently simply returns output of inspect for my objects inside table tags. The problem is that instead of the html I expect, a template engine messes layout up creating new tags (I guess it parses dict's curly brackets).
From your question I don't really understand, why and where this inspect is ran, but it is possible to escape output like this:
{{ object | e }}
Or you can escape things inside template by using 'foo' or {% raw %}:
{{ '{{' }}
{% raw %}
{% %}
{% endraw %}

Categories