I have an array in Django views.py and I want to send it to HTML and display a piechart, but
failed, I've tried many other methods and read many tutorials, in most of the case, they have
a field in models that store some number, and they display those number. In my case, I need to
calculate the subtotal of tasks that are in different states. I'm not sure how to output those
data to chart.js with proper labels or any other piechart if there's any recommendation?

views.py
def visualisation(request, project_id):
project = Project.objects.get(id=project_id)
counts_data = Todo.objects.aggregate(
to_do_count=Count('id', filter=Q(status='to_do')),
in_progress_count=Count('id', filter=Q(status='in_progress')),
done_count=Count('id', filter=Q(status='done'))
)
return render(request, 'todo_lists/progress.html', {"counts_data": counts_data})
html
<script>
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [1,2,3],
datasets: [{
label: '# of Votes',
data:{{counts_data}},
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive:false
}
});
});
</script>
You need to have the data in a structured manner for chart.js
Chart JS Data Structures https://www.chartjs.org/docs/latest/general/data-structures.html
Simply you could follow the Primitive structure as shown below or you could follow the Object structure with custom properties (need to do further data formatting and parsing).
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
// labels format ['label1', 'label2', 'label3', ]
// you can choose to have a static labels if you are sure that
// there is always a specific number of labels
labels: [{% for label in counts_data %} '{{ label }}', {% endfor %}],
datasets: [{
label: '# of Votes',
// data format [value1, value2, value3, ]
data: [{% for label, value in counts_data.items() %} {{ value }}, {% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: false
}
});
});
In your views, Todo.objects.aggregate(...) should return something like this (Values are provided as an example):
{'to_do_count': 3, 'in_progress_count': 6, 'done_count': 1}
counts_data = Todo.objects.aggregate(
to_do_count=Count('id', filter=Q(status='to_do')),
in_progress_count=Count('id', filter=Q(status='in_progress')),
done_count=Count('id', filter=Q(status='done'))
)
# counts_data = {'to_do_count': 3, 'in_progress_count': 6, 'done_count': 1}
This dictionary is then passed to the context with the key named as counts_data. Using this key name loop through the dictionary to create labels and data
labels: [{% for label in counts_data %} '{{ label }}', {% endfor %}], rendered as labels: [ 'to_do_count', 'in_progress_count', 'done_count', ],
data: [{% for label, value in counts_data.items() %} {{ value }}, {% endfor %}], rendered as data: [ 3, 6, 1, ],
<script>
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [1,2,3],
datasets: [{
label: '# of Votes',
data:counts_data,
success: function (data){
$('#todocount').html(counts_data.to_do_count);
$('#progress_count').html(counts_data.in_progress_count);
$('#progress_done').html(counts_data.done_count);
}
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive:false
}
});
});
</script>