tornado: pass string data to javascript code in a rendered page - python

I would like to pass dictionary data from Python into an index.html. (I'm using tornado here, but am open to other small frameworks that allow it.)
I first serialize the data with json.dumps, and this
def start_server():
data = {"a": 1, "b": 3}
string_data = json.dumps(data)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), "web")
self.render(os.path.join(path, 'index.html'), data=string_data)
return
app = tornado.web.Application([(r"/", IndexHandler)])
app.listen(8000)
tornado.ioloop.IOLoop.current().start()
return
together with
<script>
console.log("{{data}}");
obj = JSON.parse("{{data}}");
console.log(obj);
</script>
in the index.html gives me
{"a": 1, "b": 3}
Needless to say that JSON.parse fails with those &quots.
Any hint on what's going wrong here?

You should probably try {% raw data %}. However, note that since you use the string inside a Javascript quoted string, 'data' itself should contain something suitable for that: and json.dumps() output is not valid - you'd need to escape it appropriately - either in the code that calls .render() or in the template itself (the latter is preferable). Maybe this:
obj = JSON.parse({% raw json_encode(data) %});
(using the fact that json_encode() of a string value will output "escaped-data")

Related

Issue with displaying non-English characters in flask application in bootstrap table [duplicate]

I am trying to pass data as JSON from a Flask route to a Jinja template rendering JavaScript. I want to iterate over the data using JavaScript. The browser shows SyntaxError: Unexpected token '&'. Expected a property name. when JSON.parse is called on the rendered data. How do I use rendered JSON data in JavaScript?
var obj = JSON.parse({{ data }})
for (i in obj){
document.write(obj[i].text + "<br />");
}
def get_nodes(node):
d = {}
if node == "Root":
d["text"] = node
else:
d["text"] = node.name
getchildren = get_children(node)
if getchildren:
d["nodes"] = [get_nodes(child) for child in getchildren]
return d
tree = get_nodes("Root")
return render_template("folder.html", data=tree)
If I just put {{ data }} in the HTML part, what I see looks correct.
{'text': 'Root', 'nodes': [{'text': u'Prosjekt3'}, {'text': u'Prosjekt4', 'nodes': [{'text': u'mappe8'}]}]}
Flask's Jinja environment automatically escapes data rendered in HTML templates. This is to avoid security issues if the dev tries to render untrusted user input.
Since you are passing a Python object to be treated as JSON, Flask provides the tojson filter which automatically dumps the data to JSON and marks it safe.
return render_template('tree.html', tree=tree)
var tree = {{ tree|tojson }};
When you just look at the data rendered in HTML, it looks correct because the browser displays the escaped symbols as the real symbols (although in this case you're seeing the string representation of a Python dict, not JSON, so there's still some issues like u markers).
Previous versions of Flask didn't mark the dumped data safe, so you might come across examples like {{ tree|tojson|safe }}, which isn't required anymore.
If you're not rendering JSON (or you already dumped the JSON to a string), you can tell Jinja that data is safe to render without escaping by using the safe filter.
# already dumped to json, so tojson would double-encode it
return render_template('tree.html', tree=json.dumps(tree))
var tree = {{ tree|safe }};
You can also wrap the string in Markup before rendering it, it's equivalent to the safe filter.
# already dumped and marked safe
return render_template('tree.html', tree=Markup(json.dumps(tree)))
var tree = {{ tree }};
If you're not passing this data to JavaScript, but using it in Jinja instead, you don't need JSON. Pass the actual Python data, don't call tojson on it, and use it as you would any other data in the template.
return render_template('tree.html', tree=tree)
{% for item in tree %}
<li>{{ item }}</li>
{% endfor %}
I could archive it using the following code sample.
<script>
console.log(JSON.parse({{json|safe}}))
</script>
The problem is that your server returns not JSON, but rendered HTML, which escapes some of the symbols with & notation.
Instead of using
return render_template("folder.html", data=tree)
try
return flask.jsonify(**tree)

Passing a variable from HTML to Flask through a button, changes the type to string

I need to pass a variable var from a HTML-page to flask, and have tried the code below, but the problem is that the request.form changes vars type from a dict to a string. I used json.loads(item) to change it back but the variables dict contains a datetime value which gives an error of
json.decoder.JSONDecodeError: Expecting value: line 1 column 95 (char 94).
I rather not have to deal with that it changes the type from the beginning, anyone with a better idea of passing variables from HTML to Flask?
In my_bookings.html :
<form action="#" method="POST">
<input name="cancel_var" value="{{var}}" type=hidden>
<button type="submit"> Cancel var </button>
</form>
In app.py:
#app.route('/my_bookings', methods=['GET', 'POST'])
def my_bookings():
if request.method == 'POST':
var = request.form['cancel_var']
cancel_var = json.loads(var) # This gives a json.decoder error because of one value is datetime-object
To clarify, the var is a dict and contains:
var = {"number": 3, "date": datetime.datetime(2020, 5, 14, 0, 0)}
and comes back as a <class 'str'> to the Flask, but I want it to stay as a dict.
thats not really how it works .... but i guess you could do something crazy
import cPickle,base64
def my_endpoint():
if request.method == "POST":
my_data = request.form['cancel_var']
my_data = base64.b64decode(my_data) # convert back to binary
# note that pickle can be dangerous and this is really probably
# not a good idea if someone might submit malicious code
my_data = cPickle.loads(my_data) # back to python objects
print("GOT DATA:",repr(my_data))
my_var = cPickle.dumps(var) # serialize to a string
my_var = base64.b64encode(my_var) # ensure ascii character set
return render('my_html.html',var=my_var)
but thats generally a pretty bad idea ... you could serialize to json instead of pickle (which is safer and faster) but json wont serialize your datetime thing
probably what you should do is not this....
instead you should just save the data to the users session and check it when they submit
def my_endpoint():
if request.method == "POST":
print("GOT DATA:",request.session['cancel_var'])
request.session['cancel_var'] = var
return render('my_html.html',var="you dont need this")
or save it in the users cookies or a database or even in a file on disk... or maybe not at all as im not sure what you are trying to accomplish

Using JSON Object inside string.format()?

I have a Python3 script that takes an input HTML template and populates some data using this JSON and creates an output HTML.
Python Script -
with open('./jsonInp.json') as jsonFile:
jsonData = json.load(jsonFile)
inp_f = open('brandedTemplate.html', 'r+')
htmlInp = inp_f.read().format(links = jsonData['links'])
My JSON File -
{
"links" : {
"one" : "www.one.com",
"two" : "www.two.com",
}
}
Now using this in the input HTML like :
...
<a href={links.one}></a>
...
But this doesn't work. Neither does links['one'].
The JSON loading and everything works fine. I am also able to use arrays from .format function. Just can't find how to use this object anywhere. From type(jsonData['links']), I know its a Python dict.
Is there a way to use this in a html template?
Your jsonData variable is a python dict. To access values in the format mini language you need to use {my_dict[my_key]}. Note that the key is not enclosed in quotes.
To fix your example, the html input should be as follow:
...
<a href={links[one]}></a>
...
According to [Python]: Format examples, you should use (templates like):
<a href={links[one]}></a>
as html format specifier (since [Python]: json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) returns a dict).
Example:
>>> json_dict
{'links': {'one': 'www.one.com', 'two': 'www.two.com'}}
>>> href_text
'<a href={links[one]}></a>'
>>> href_text.format(links=json_dict["links"])
'<a href=www.one.com></a>'

Django AngularJS JSONResponse view in rendering json output

i am developing one of my site with the python django where i have been using angularjs in one of my page where i have given the user option to search (specific request). Here is my model..
class Request(models.Model):
description = models.TextField(blank=True,null=True)
category = models.ForeignKey(Category)
sub_category = models.ForeignKey(SubCategory)
In my views I am returning through the following code:
def some(code, x):
exec code
return x
def search_request(request):
page = request.GET.get('page')
term = request.GET.get('term')
i = 0
terms = "x = Request.objects.filter("
for t in term.split(" "):
i=i+1
if(len(term.split(" "))>i):
terms = terms +"Q(name__icontains='"+t+"')|"
else:
terms = terms +"Q(name__icontains='"+t+"'))"
junk = compile(terms,'<string>', 'exec')
spit = Request.objects.filter(name__icontains=term)
requests = some(junk,spit)
output = HttpResponse()
output['values']=[{'requests':r,'category':r.category,'subcategory':r.sub_category} for r in requests]
return JSONResponse(output['values'])
In my HTML code when I return using AngularJS:
$scope.search = function(){
$scope.results = $http.get("{% url 'search-requests-show' %}?term="+$scope.term).then(
function(result){
return result.data;
}
);
}
The result on the HTML Output comes as in {[{results}]}:
"[{'category': <Category: The New Category>, 'requests': <Request: Need a Table>, 'subcategory': <SubCategory: Testsdfsdfsad>}]"
The problem is that I am not being able to access using results.category because the output is in "string", so the ng-repeat="result in results" brings the result as
[ { ' c a .....
I am probably doing something wrong in view. If anybody has any suggestion then please answer.
JSONResponse is probably using standard python json encoder, which doesn't really encode the object for you, instead it outputs a string representation (repr) of it, hence the <Category: The New Category> output.
You might need to use some external serializer class to handle django objects, like:
http://web.archive.org/web/20120414135953/http://www.traddicts.org/webdevelopment/flexible-and-simple-json-serialization-for-django
If not, you should then normalize object into simple python types inside the view (dict, list, string.., the kind that json module has no problem encoding). So instead doing:
'category':r.category
you could do:
'category': {'name': r.category.name}
Also as a sidenote: using exec is super bad idea. Don't use it in production!
You should return json strings for Angular:
import json
def resource_view(request):
# something to do here
return HttpResponse(json.dumps(your_dictionary))
for better usage i recommend djangorestframework.
Off Topic:
$http.get("{% url 'search-requests-show' %}?term="+$scope.term);
you can pass 'param' object:
$http.get("{% url 'search-requests-show' %}", {param : {term:$scope.term}});

Python JSON encoder

I have a dict like this:
data = {"data":"http://abc/def"}
when I call json.dumps(data) I get this:
'{"data":"http://abc/def"}'
but I want this:
'{"data":"http:\/\/abc\/def"}'
because I use jquery to parse json but seems like it don't understand unescaped solidus, or is there any way to make jquery understand?
UPDATE
For example, here is my json data
{"data": ["http://abc.com/aaaaaaaa/bbbbbbbbb/cccccccccc/xyz.mp3"]}
Here is my success function
function showResult(result) {
$.each(result.data, function(i, item){
link = $('<a>').attr('href', item).text(item)
$("#result").append('<br>')
$("#result").append(link);
});
}
The result should be a hyperlink to
http://abc.com/aaaaaaaa/bbbbbbbbb/cccccccccc/xyz.mp3
But I got a hyperlink to
http://abc.com/aaaaaaaa/bbbbbbbbb/cccccccccc/xyz.mp3
If replace all '/' by '\/', everything is fine
Normally you don't escape forward slashes in JSON, but if you are certain this is your problem you can simply do this:
s = json.dumps(data)
s = s.replace("/", "\\/")

Categories

Resources