How to pass variable (list) to JavaScript in Django? - javascript

I am trying to create a chart Using Chartjs and Django,
i have a problem when i am trying to pass the data from views.py to js code.
so,this is my code in views.py..
def home(request):
labels = ["A", "B", "C", "D"]
data = [1,2,3,4]
return render(request, 'home.html',{'labels': labels
,'data': data,})
and this is my part of code in home.html ..
<script>
var labels = {{labels}};
var data = {{data}};
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: labels,
datasets: [{
label:"chartLabel",
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data:data,
}]
},
// Configuration options go here
options: {}
});
</script>
put when i use these tow lines in js ..
var labels = ["A", "B", "C", "D"];
var data = [1,2,3,4];
instead of this tow my code works fine.
var labels = {{labels}};
var data = {{data}};
and this is my page source

For a dict or list, best to use JSON, because that renders a Javascript data structure (the JS in JSON refers to Javascript)
import json
return render(request, 'home.html', {
'labels': json.dumps(labels),
'data': json.dumps(data)
})
Then in the Django template, the output of the json.dumps() call is a valid JS object.
var labels = {{labels}};
var data = {{data}};

You'll need to render your data as if it were a string so that the output is valid javascript that the browser can interpret:
var data = {{ str(data) }};
var labels = {{ str(labels) }};
The above expressions convert the array into a string representation of the array, so [1, 2, 3] would be rendered as '[1,2,3]' and ["a", "b", "c"] would be rendered as '["a","b","c"]'.
A quick way to check if this is working right would be to right click and view the page source, then scroll down to this javascript and verify that it looks like valid variable declarations. If it doesn't seem to be working, edit your question with the rendered javascript you see while inspecting the page source.

I have found the most reliable way to render any data, is to use the safe django template filter, so it doesn't try and encode any special fields.
return render(request,
'home.html',
{'labels': json.dumps(labels),'data': json.dumps(data)}
)
Then render using using the safe template filter. This
<script>
var labels = {{labels | safe}};
var data = {{data | safe}};
...
</script>

Related

Using Django, send a Python Dictionary to a HTML Page and convert it to Javascript arrays in Javascript Script

I have been trying to send a Python Dictionary to a HTML Page and use that dictionary in Javascript to add a Graph on my website, using Django
The form takes a Image Upload, and the code is as follows,
<div class=" mx-5 font-weight-bold">
Uplaod Image
</div>
<input class=" " type="file" name="filePath">
<input type="submit" class="btn btn-success" value="Submit">
This image is then sent to views.py where it is processed and a resultant image, as well as a dictionary is generated from that image. And then again, a HTML page is rendered where the dictionary as well as the resultant image is sent in context variable. The code is as follows,
def predictImage(request):
fileObj = request.FILES['filePath']
fs = FileSystemStorage()
filePathName = fs.save(fileObj.name, fileObj)
filePathName = fs.url(filePathName)
testimage = '.'+filePathName
img_result, resultant_array, total_objects = detect_image(testimage)
cv2.imwrite("media/results/" + fileObj.name, img=img_result)
context = {'filePathName':"media/results/"+fileObj.name, 'predictedLabel': dict(resultant_array), 'total_objects': total_objects}
#context = {}
return render(request, 'index.html', context)
Now, I want to convert the Dictionary items and keys into two different Javascript arrays, which are then to be used to plot a Graph on the HTML page. The template code of the Javascript is as follows,
<script>
// const value = JSON.parse(document.getElementById('data_values').textContent);
// alert(value);
var xArray = [];
var yArray = [];
var xArray = ["Italy", "France", "Spain", "USA", "Argentina"]; // xArray needs to have Python Dictionary's keys
var yArray = [55, 49, 44, 24, 15]; // yArray needs to have Python Dictionary's values
var layout = { title: "Distribution of Labels" };
var data = [{ labels: xArray, values: yArray, hole: .5, type: "pie" }];
Plotly.newPlot("myPlot", data, layout);
</script>
I have tried a lot of different things to access my Python Dictionary in the Javascript Script and then convert that to Javascript arrays, but I still have not managed to do it. I also tried different Stackoverflow posts etc but nothing could really properly guide me on this. I am quite new to Django as well so I am not much aware of the syntax as well.
From Django-doc json_script
{{ value|json_script:"hello-data" }}
inside your Javascript
<script>
const data = JSON.parse(document.getElementById('hello-data').textContent);
var xArray = Object.keys(data) // return list of keys
var yArray = Object.values(data) // return list of values
</script>
can you take a try this,
views.py
# context data
context = {'filePathName':"media/results/"+fileObj.name, 'predictedLabel': dict(resultant_array), 'total_objects': total_objects,
"data": {"Italy":11, "France":22, "Spain":22, "USA":23, "Argentina":12}}
template.html
<script>
// const data = JSON.parse();
// alert(value);
var data = JSON.parse("{{data|safe}}".replaceAll("'", '"'));
var xArray = [];
var yArray = [];
var xArray = Object.keys(data); // xArray needs to have Python Dictionary's keys
var yArray = Object.values(data) // yArray needs to have Python Dictionary's values
var layout = { title: "Distribution of Labels" };
var data = [{ labels: xArray, values: yArray, hole: .5, type: "pie" }];
Plotly.newPlot("myPlot", data, layout);
</script>
html
<input type="hidden" id="dictionary" value="{{ dictionary }}" />
JS
var dictionary = JSON.parse($('#dictionary').val());

Flask to Dygraph - how to pass data?

If I have a simple Python time data series like this:
graphdata = []
graphdata.append( [(datetime.date(2008, 5, 7)),75])
graphdata.append([(datetime.date(2008, 5, 8)), 85])
graphdata.append([(datetime.date(2008, 5, 10)), 60])
How can I pass the data to a Flask page running Dygraph?
Do I need to use GViz?
Any examples would be helpful.
Thanks
Bill
No need to pass the data as a list containing datetime objects. Dygraphs reads CSV format with ease. So just pass the data as one long CSV string. For your case, first formulate that string containing your data:
graphdata = ''
graphdata = graphdata + '2008-05-07, 75\n'
graphdata = graphdata + '2008-05-08, 85\n'
graphdata = graphdata + '2008-05-10, 60\n'
Now, let's say this you wish to render this data on your index page, then do this in your views.py:
#app.route('/')
def index():
return render_template('index.html',graphdata)
Finally, this data is received by your index.html and rendered using the following code:
<div id="graphdiv"></div>
<script type="text/javascript">
g = new Dygraph(
// containing div
document.getElementById("graphdiv"),
// CSV or path to a CSV file.
{{ graphdata }}
);
</script>
Make sure that dygraph.js is included in your Flask app.

Print complex python variable in javascript

I am trying to print in console.log() my series variable but no success so far.
def multiple_series(res):
matrix = dict(res)
all_cat_keys = set(key[0] for key in matrix)
categories = sorted(all_cat_keys)
all_series_keys = set(key[1] for key in matrix)
series = [
{
'name': series_key,
'data': [
[cat_key, matrix.get((cat_key, series_key), 0)]
for cat_key in categories
],
}
for series_key in all_series_keys
]
return series
I've tried using json.dumps() and the well known console.log({{ series }}) but I get nothing.
I'd like to print the content of name and data. Can anyone help me ? I don't have much experience using JS. Thanks
console.log({{ series }}) can not work because {{ series }} gets evaluated to text. Therefore JS thinks it's a JS object.
Add quotes around the object to treat it as text and it should work:
console.log("{{ series }}");
Iam not sure about your input data - but you are building the series list the wrong way. You should build you series list like that:
def multiple_series(res):
matrix = dict(res)
all_cat_keys = set(key[0] for key in matrix)
categories = sorted(all_cat_keys)
all_series_keys = set(key[1] for key in matrix)
series = []
for series_key in all_series_keys:
dict_to_add = {'name': series_key}
data_information = []
for cat_key in categories:
data_information.append((cat_key, matrix.get((cat_key, series_key), 0)))
dict_to_add['data'] = data_information
series.append(dict_to_add)
return series

Get JavaScript array from Django view

I am using Django with the Google Charts API. I need to construct a JavaScript array to render a bar chart showing the # of objects created in a given day.
The expected array printed to the template should look like:
...
function drawStuff() {
var data = new google.visualization.arrayToDataTable([
['Date', '# of records'],
['2015-03-07', 3], // Expected format: ['Date', # of objects]
['2015-03-08', 8],
]);
...
views.py:
class LogsView(TemplateView):
template_name = 'logs.html'
def ValuesQuerySetToDict(self, vqs):
return [ [item['date_created'], item['created_count'] ] for item in vqs]
def render_chart_data(self, **kwargs):
queryset = LogEntry.objects.filter(user=self.request.user).extra(
{'date_created': 'date(created)'}
).values('date_created').annotate(created_count=Count('id'))
modified_dict = self.ValuesQuerySetToDict(queryset)
return json.dumps(modified_dict)
def get_context_data(self, **kwargs):
context = super(
LogsView, self
).get_context_data(**kwargs)
context['chart_data'] = self.render_chart_data()
The following is rendered to my django template (I bypassed sending it to JavaScript for now to see what was returned...
When I believe I need to return a JavaScript array like the following:
["2015-02-18", 3],
["2015-02-19", 12],
["2015-02-21", 1],
And feed that to the drawStuff function which will render the barchart.
Alternate Method
I followed the this thread on StackOverflow and modified the render_chart_data to use django serializer like this but I am getting an error: " 'dict' object has no attribute '_meta'
Thanks to all who offered assistance on this.
Two things needed to changed; the ValuesQuerySetToDict function needed to be rewritten as follows:
def ValuesQuerySetToDict(self, vqs):
list_vals = [ ['Date', '# of records'] ]
for item in vqs:
list_vals.append(
# convert datetime object to string otherwise JSON serialization error
[ str(item['date_created']), item['created_count'] ]
)
return list_vals
And the render_chart_data function needed to be rewritten as follows:
def render_chart_data(self, **kwargs):
queryset = LogEntry.objects.filter(user=self.request.user).extra(
{'date_created': 'date(created)'}
).values('date_created').annotate(created_count=Count('id')).order_by('created-date')
modified_list = list(self.ValuesQuerySetToDict(queryset))
json_data = json.dumps(modified_list)
return json_data
Finally, {{ chart_data }} needed to be passed to to the drawStuff function, like so:
function drawStuff() {
var data = new google.visualization.arrayToDataTable(
{{ chart_data|safe }}
);
I've posted views.py and logs.html here.
In your queryset, render created_count as string and not as integer. Json's do not behave well with Integers.
In your JS function drawStuff, chart_data should be parsed as json. See below:
var json_string = '{{chart_data}}';
var json = JSON.parse(json_string);
var data = new google.visualization.arrayToDataTable(json)

Adding another data series in plot

I currently have a PHP file which returns:
[[38,38],[38,113],[38,188],[38,263],[38,338],[38,413],[38,488],[113,38],[113,113],[113,188],[113,263],[113,338],[113,413],[113,488],[188,38],[188,113],[188,188],[188,263],[188,338],[188,413],[188,488],[263,38],[263,113],[263,188],[263,263],[263,338],[263,413],[263,488],[338,38],[338,113],[338,188],[338,263],[338,338],[338,413],[338,488],[413,38],[413,113],[413,188],[413,263],[413,338],[413,413],[413,488],[488,38],[488,113],[488,188],[488,263],[488,338],[488,413],[488,488],[75,75],[75,150],[75,225],[75,300],[75,375],[75,450],[150,75],[150,150],[150,225],[150,300],[150,375],[150,450],[225,75],[225,150],[225,225],[225,300],[225,375],[225,450],[300,75],[300,150],[300,225],[300,300],[300,375],[300,450],[375,75],[375,150],[375,225],[375,300],[375,375],[375,450],[450,75],[450,150],[450,225],[450,300],[450,375],[450,450]]
I use this in an AJAX call like
$.ajax({
url:'fetcher/allseedpositions.php',
async: false,
success:function(datasets){
seedPos = jQuery.parseJSON(datasets);
allNodePos = $.plot($("#allnodepositions"),[ seedPos ],optionsSeed);
}
})
to plot but now I want another series to be plotted also along with this, with different symbol.
I am confused on using JSON and I cannot add more properties.
You should be able to create a new array and push the next data set for display. http://jsfiddle.net/fZbVL/
var dataSet1 = [
[1,5],[4,7]
];
var dataSet2 = [
[1,2],[3,4]
];
var dataSet3 = [
[1,4],[4,6]
]
var data = []
data.push(dataSet1);
data.push(dataSet2);
data.push(dataSet3);
$.plot($("#placeholder"),
data);

Categories

Resources