Reputation: 1932
I have a python list generated by my views.py in Django, and I would like to pass it to javascript in my HTML template. I cannot seem to get it into javscript as an array... I need to evaluate if the list/array contains certain numbers, but it is coming over as a string.
I am passing the list to my HTML template like this:
def get_context_data(self, **kwargs):
context = super(dashboardView, self).get_context_data(**kwargs)
mylist = [10,22,33,45]
context['mylist'] = mylist
return context
When I use:
<h1 id = "list"> {{mylist}}</h1>
it shows up on the browser as it shows up as [10,22,33,45]
Then in my template I am using javascript I have:
var mylist = document.getElementById("list").innerHTML;
for(i = 0; i < mylist.length; i++){
console.log(mylist[i])
};
this returns in the console:
'
[
1
0
,
2
2
........
I want:
10
22
33
45
I have tried to convert to JSON in python, and parse it in javascript, but can't seem to convert this string to an array, or keep getting errors. Any ideas for the best method here?
Upvotes: 20
Views: 22199
Reputation: 6382
If you are absolutely certain your list is safe, (by that I mean it never, ever includes anything entered by a user), it is very simple.
In your view:
context={"my_list": ["item1", "item2"]}
In your template:
{{ my_list|safe }}
Renders as:
['item1', 'item2']
For example:
{{ my_list|safe }}.forEach(item => {
console.log(item)
})
Impressively, if you pass a string with an apostrophe, Django automatically changes the quote types, so
context = {"my_list": ["item1", "it'em2"]}
renders as (note the double-quotes):
['item1', "it'em2"]
so
{{ my_list|safe }}.forEach
still works (tested on Django 3.2.6).
Even this works:
context = {"my_list": ["item1", "it'em\"2"]}
renders as:
['item1', 'it\'em"2']
so
{{ my_list|safe }}.forEach
still works.
However, as I said at the top, if your list might include input from a user, I still wouldn't trust this approach.
==
EDIT: Now this is the highest answer, I wanted to add a safer approach to make it easier to be fully safe. This is interesting from django-argonauts, although I'm not a security expert so couldn't confirm the approach:
@register.filter(is_safe=True)
def jsonify(json_object):
"""
Output the json encoding of its argument.
This will escape all the HTML/XML special characters with their unicode
escapes, so it is safe to be output anywhere except for inside a tag
attribute.
If the output needs to be put in an attribute, entitize the output of this
filter.
"""
json_str = json.dumps(json_object)
# Escape all the XML/HTML special characters.
escapes = ["<", ">", "&"]
for c in escapes:
json_str = json_str.replace(c, r"\u%04x" % ord(c))
# now it's safe to use mark_safe
return mark_safe(json_str)
Then in the template:
{% load jsonify %}
{{ value|jsonify }}
Upvotes: 25
Reputation: 720
Django has the json_script
template tag that addresses XSS vulnerabilities by escaping the <
, >
, and &
characters.
Upvotes: 3
Reputation: 89
In views you can make your object as a JSON object:
import json
mylistraw = [10,22,33,45]
mylist = json.dumps(mylistraw)
context = {''mylistjson': mylist}
Now you can use your object in JavaScript:
var mylist = JSON.parse("{{mylistjson}}")
Upvotes: 7
Reputation: 2267
You can simply use tojson
tag to convert python list to js array.
It will be like -
var mylist = {{mylist|tojson}};
for(i = 0; i < mylist.length; i++){
console.log(mylist[i])
};
Try it and let me know if any problem occurs.
Upvotes: 3
Reputation: 8525
In your case, a simple way is to send the list as string ','.join(mylist)
. And then in your templates, you could simply use split(',')
in js
.
views
mylist = [10,22,33,45]
context['mylist'] = ','.join([str(i) for i in mylist])
html & js
var mylist = document.getElementById("list").innerHTML;
mylist = mylist.split(',')
for(i = 0; i < mylist.length; i++){
console.log(mylist[i])
};
Or in case your js is in the template as well
var mylist = '{{mylist}}'.split(',');
for(i = 0; i < mylist.length; i++){
console.log(mylist[i])
};
Upvotes: 1
Reputation: 1
Set the list value in JavaScript and not HTML.
<script>
var mylist = {{mylist}};
for(i = 0; i < mylist.length; i++){
console.log(mylist[i])
};
<\ script>
You need to do this in your HTML template file and not in an external JS file.
Upvotes: -1