MattG
MattG

Reputation: 1932

Getting a list from Django into Javascript as an array

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

Answers (6)

Chris
Chris

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

arcanemachine
arcanemachine

Reputation: 720

Django has the json_script template tag that addresses XSS vulnerabilities by escaping the <, >, and & characters.

Django json_script docs here

Upvotes: 3

Strategy Guru
Strategy Guru

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

Pankaj Sharma
Pankaj Sharma

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

Lemayzeur
Lemayzeur

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

Mohamed Dem Diarra
Mohamed Dem Diarra

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

Related Questions