0

I have a very similar problem to this question, Python datastructures into js datastructures using Django templates (lists and dicts) but with the next step - how do the variable names in python that are strings become javascript objects?

So in python I have this:

data = [{'year': 2006, 'books': 54, 'author': 'fred'},
    {'year': 2007, 'books': 43, 'author': 'sue'},
    {'year': 2008, 'books': 41, 'author': 'bill'},
    {'year': 2009, 'books': 44, 'author': 'alex'},
    {'year': 2010, 'books': 35, 'author': 'fred'}]

which I can output into my javascript via {{ data | safe }}

but I would like my javascript to look like this:

var data = [{year: 2006, books: 54, author: 'fred'},
    {year: 2007, books: 43, author: 'sue'},
    {year: 2008, books: 41, author: 'bill'},
    {year: 2009, books: 44, author: 'alex'},
    {year: 2010, books: 35, author: 'fred'}];

whereas it comes out at the moment like this:

var data = [{'year': 2006, 'books': 54, 'author': 'fred'},
    {'year': 2007, 'books': 43, 'author': 'sue'},
    {'year': 2008, 'books': 41, 'author': 'bill'},
    {'year': 2009, 'books': 44, 'author': 'alex'},
    {'year': 2010, 'books': 35, 'author': 'fred'}];

Is there anyway to do this?

Many thanks, Mark

Community
  • 1
  • 1
Mark
  • 208
  • 2
  • 9
  • http://stackoverflow.com/questions/19451017/jinja2-json-python3-and-closure-compiler may help – vaultah Apr 13 '14 at 15:06
  • I think `JSON.parse(data)` would be fine for your need. – Suman Bogati Apr 13 '14 at 15:08
  • In general it's pretty easy to communicate these data structures -- `JSON.stringify`/`JSON.parse` on the client side, `json.dumps`/`json.loads` on the server. – Two-Bit Alchemist Apr 13 '14 at 15:09
  • Thanks for your guidence! I think I may have the incorrect syntax as I tried your suggestions such as JSON.parse in this fiddle but it doesn't work: http://jsfiddle.net/Bh8et/1/ I also have tried lots of solutions with JSON.stringify before asking, but couldn't see how this creates the un-string vars. – Mark Apr 13 '14 at 15:21

2 Answers2

2

The tojson filter included with Flask takes care of producing a valid Javascript subset that is also HTML safe:

var data = {{ data|tojson|safe }};

If you are not using Flask, then register a custom filter like:

import json

def tojson(obj):
    """Produce HTML-safe JSON"""
    return (json.dumps(obj)
                .replace(u'<', u'\\u003c')
                .replace(u'>', u'\\u003e')
                .replace(u'&', u'\\u0026')
                .replace(u"'", u'\\u0027'))
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @traceur: JSON is a full subset of JavaScript *except* for two codepoints that JSON allows but JS disallows. The default `json.dumps()` setup *escapes* these two codepoints. – Martijn Pieters Apr 13 '14 at 15:22
  • @traceur: Why use a template then? You wouldn't ever use a closure compiler on a template, at best only on the *output* of a template. – Martijn Pieters Apr 13 '14 at 15:28
  • Many thanks, I thought maybe a filter would be the way as that was suggested before, but wasn't using Flask. However, I've registered this filter and reloaded, and the data is still including strings - I used {{ dataChart|tojson|safe }} in the template which becomes this when rendered: [{"medium": "organic", "visits": 2059.0}, {"medium": "(none)", "visits": 379.0}, {"medium": "referral", "visits": 346.0}] – Mark Apr 13 '14 at 15:41
  • @Mark: JavaScript *allows* for keys to be enclosed in quotes as strings. `{"medium": "referral"}` is the same thing as `{medium: "referral"}`. It is perfectly fine to have those quotes. – Martijn Pieters Apr 13 '14 at 16:13
  • @MartijnPieters but for some reason it didn't work in ChartJS http://chartjs.devexpress.com with quotes, I thought it should do to, but it refused and so this hunt for unquoted. Maybe its some way its set up with the library. – Mark Apr 13 '14 at 16:21
  • @Mark: how weird, see [What is the difference between object keys with quotes and without quotes?](http://stackoverflow.com/q/4348478), there should be no difference. – Martijn Pieters Apr 13 '14 at 16:24
  • @Mark: pasting either in the console makes no difference in the resulting structure. – Martijn Pieters Apr 13 '14 at 16:26
  • For the answer below, trying with your filter but without eval = blank chart, with the eval I get the chart. A mystery but a happy ending :D – Mark Apr 13 '14 at 16:31
  • Well, glad to have been of *some* help then! – Martijn Pieters Apr 13 '14 at 16:32
1

The solution was a combo of Martijn Pieters and traceur, thanks a lot :D

So working version of code is:

In Python:

data = [{'year': 2006, 'books': 54, 'author': 'fred'},
{'year': 2007, 'books': 43, 'author': 'sue'},
{'year': 2008, 'books': 41, 'author': 'bill'},
{'year': 2009, 'books': 44, 'author': 'alex'},
{'year': 2010, 'books': 35, 'author': 'fred'}]

....rest of code....

variables = {
    'data' : data
    }
template = JINJA_ENVIRONMENT.get_template('main.html')
self.response.write(template.render(variables))

Additional to above, I had to register a new filter for JSON for jinja2:

JINJA_ENVIRONMENT = jinja2.Environment(
  loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
  autoescape=True,
  extensions=['jinja2.ext.autoescape'])

def tojson(obj):
 """Produce HTML-safe JSON"""
  return (json.dumps(obj)
            .replace(u'<', u'\\u003c')
            .replace(u'>', u'\\u003e')
            .replace(u'&', u'\\u0026')
            .replace(u"'", u'\\u0027'))

JINJA_ENVIRONMENT.filters['tojson'] = tojson

...then in the HTML needed to call this filter to place it in the javascript, but also eval as per traceur's comment. (I don't really know why)

<script type="text/javascript">
  dataSource = eval('({{ data|tojson|safe }})')
  console.log(dataSource)
  ....do stuff with dataSource....
</script>

dataSource is now a js object, which is in correct format for my ChartJS visulisation.

Thanks a lot!

Mark
  • 208
  • 2
  • 9