Search code examples
javascriptpythontemplatesbottle

Python Bottle: Assigning a python variable to Javascript variable


I am using Bottle web framework to render webpages. I am using bottle template engine to pass the variables from Python and then process them accordingly in the template file, which has embedded Python code.

Now the problem comes when I use javascript within my template. If I try to access my Python variable inside the javascript function, it fails with TypeError: unhashable type: 'list'

I am calling my template in my python file:

list_vals = [['Mushrooms', 3, 5], ['Onions', 1, 4], ['Olives', 1, 5], ['Zucchini', 1, 2]]    
return bottle.template(os.path.join(os.path.dirname(__file__), 'templates', 'pizzaStats.html'), vals=list_vals)

In my template file I am using the vals variable currently just to print inside the javascript, as shown below (just the script part of the template is shown):

<script type="text/javascript">

  // Load the Visualization API and the piechart package.
  google.load('visualization', '1.0', {'packages':['corechart']});

  // Set a callback to run when the Google Visualization API is loaded.
  google.setOnLoadCallback(drawChart);

  // Callback that creates and populates a data table,
  // instantiates the pie chart, passes in the data and
  // draws it.
  function drawChart() {

    // Create the data table.
    var data = new google.visualization.DataTable();
    %print ({{ vals }})
    var graphdata = {{ vals }}; 
    data.addColumn('string', 'Topping');
    data.addColumn('number', 'Slices');
    data.addColumn('number', 'pieces');
    data.addRows(graphdata);

    // Set chart options
    // to smoothen the lines - 'curveType':'function'
    var options = {'title':'How Much Pizza I Ate Last Night',
                   'width':400,
                   'height':300};

    // Instantiate and draw our chart, passing in some options.
    var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
    chart.draw(data, options);
  }
</script>

Even if I change the type of the variable from list to dict type, it still complains. TypeError: unhashable type: 'dict' The error is coming from the print() but if I remove the print() nothing happens and no graph is drawn, meaning the variable is not correctly assigned.

The end goal is to assign this variable to a javascript variable which will then plot the graph using Google APIs. What is the correct way to assign a Python variable to a javascript variable inside the bottle template? Thanks.


Solution

  • I think the problem is in the template side, when you render the vals argument. The rendered vals must be valid JavaScript code. By default, bottle auto-escapes HTML special characters, being single and double quotes among them. So, when you pass the Python list_vals list to the template function, it is evaluated to a string like this:

    "[['Mushrooms', 3, 5], ['Onions', 1, 4], ['Olives', 1, 5], ['Zucchini', 1, 2]]"
    

    and automatically escaped by bottle afterwords like this:

    [[&#039;Mushrooms&#039;, 3, 5], [&#039;Onions&#039;, 1, 4], [&#039;Olives&#039;, 1, 5], [&#039;Zucchini&#039;, 1, 2]]
    

    producing an invalid JavaScript code.

    The quick solution could be just disabling the bottle auto-escaping simply adding an exclamation mark to the template vals parameter:

    var graphdata = {{!vals}};