简体   繁体   中英

Send json string from python app to javascript in jinja template

I'm trying to send a list from python using Flask on a web server to a client with jinja and javascript. This should be simple using json. This is my python code:

@app.route("/demo")
def demo():
    basket = [{"fruit": "apple", "amount": 3}, {"fruit": "pear", "amount": 1}, {"fruit": "kiwi", "amount": 2}]
    return render_template("demo.html", basket=json.dumps(basket))

This is a simplified code, in the final program the list will be the result of a database query. The jinja template is as follows:

 {% extends "layout.html" %} {% block title %} Demo {% endblock %} {% block main %} <script> console.log('{{ basket }}'); object = JSON.parse('{{ basket }}') </script> {% endblock %}

However, javascript returns a parsing error:

[{"fruit": "apple", "amount": 3}, {"fruit": "pear", "amount": 1}, {"fruit": "kiwi", "amount": 2}] demo:1 Uncaught SyntaxError: Unexpected token & in JSON at position 2 at JSON.parse () at demo:54

It seems that the double quote " is somehow translated to the HTML code &#34 for the " character. Subsequently JSON.parse cannot handle that. Tried breaking up the list in two arrays 'fruit' and 'amount', same error. I'm guessing that the client doesn't know that I'm sending json and that I should set content-type to application/json. Is that right, and if it is, how and where should I do this?

UPDATE after Makozaki's answer: Passing 'basket' as a python object (instead of a json object) combined with a jinja for loop works, but only if you rebuild arrays of single elements:

<script>
    fruit = [];
    {% for item in basket %}
        fruit.push('{{ item["fruit"] }}')
    {% endfor %}
    console.log(fruit)
</script>

Trying to push items consisting of 'fruit' and 'amount' will again contain all the escaped characters. And it seems silly that you would have to rebuild an array that is passed in its entirety as an object.

Turning off autoescape works as well, but in an unexpected way:

<script>
    {% autoescape false %}
        object = {{ basket }};
    {% endautoescape %}
</script>

This returns exactly the object that is passed. But the funny thing is: you have to omit the single quotes before and after the double curly braces! (as opposed to the previous example)

Thanks for the inspiration!

I'm sure you will not just print json string on your page. If this is for some simple purposes then why don't you use basket python object instead of json dump string. You can always iterate over your list using jinja for loop and use values from your list however you want.

Yet still if you want to solve escaping problem you could try forcibly turn autoescaping off with jinja tag.

{% autoescape false %}
    Autoescaping is inactive within this block
{% endautoescape %}

UPDATE: I remembered there was a buildin tojson filter in flask. Take a look at JSON Support , there is an example for your use case:

<script type=text/javascript>
    doSomethingWith({{ basket|tojson|safe }});
</script>

Regarding for loop I was wondering if you could use it for page generation without the need of javascript, eg. if you would want to list your items on page then you could use it like this:

<ul>
    {% for item in basket %}
    <li>Fruit: {{item.fruit}} number: {{item.amount}}</li>
    {% endfor %}
</ul>

But it was a wild guess from my side and I wasn't very specific about the purpose of the hint.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM