问题
So I spent the weekend testing and searching SO and finally got Django and Chart.js working. Kind of. It renders the graph but the data is not correct. When I loop through the object, the results are not what I would expect. Maybe I'm blind from staring at this all weekend. Would appreciate any pointers.
Here are my views...
class ChartView(LoginRequiredMixin, TemplateView):
template_name = 'Books/chart.html'
def get_context_data(self, **kwargs):
context = super(ChartView, self).get_context_data(**kwargs)
qs1 = Class.objects.filter(id__in=self.request.user.userprofile.class.all()).order_by('id')
qs2 = Books.objects.filter(class__in=self.request.user.userprofile.books.all()).distinct()
context['qs1'] = qs1
context['qs2'] = qs2
return context
class ChartData(LoginRequiredMixin,APIView):
model = Books
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
qs_count = Books.objects.filter(class__in=self.request.user.userprofile.class.all()).count()
labels = []
default_items = []
data = {
"labels": labels,
"default": default_items,
}
return Response(data)
Here's my HTML with the Javascript...
{% extends 'base5.html' %}
{% block body_block %}
<div class="box6">
<h1 class="title">Number of Books By Class</h1>
<canvas id="myChart"></canvas>
<div>
<script>
var endpoint = '{% url "Books:chart_data" %}'
var defaultData = [];
var labels = [];
$.ajax({
method: "GET",
credentials: 'same-origin',
url: endpoint,
success: function(data){
labels = data.labels
defaultData = data.default
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [{% for i in qs1 %}{{ i.id }},{% endfor %}],
datasets: [{
label: "# of Books",
data: [{% for j in qs2 %}
{{ j.id }},
{% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
}
})
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
</script>
{% endblock %}
Here are the models.
class Books(models.Model):
book_name = models.CharField(max_length=80,null=True)
description = models.TextField(max_length=264,unique=False)
class = models.ForeignKey(Class,on_delete=models.DO_NOTHING,related_name='classes')
class Class(models.Model):
class_name = models.CharField(max_length=264,unique=True)
teacher = models.ForeignKey(User,null=True,
on_delete=models.CASCADE,related_name="teacher_name")
I feel like my looping logic in qs2 is where the problem is. It is not properly looping through qs2, as it is returning results, but not the proper ones. I'm only trying to get the books out of the the user that match the class, and it's not working. Also, I can only get the "ID" to display on the graph, not the actual foreign key name. I can't figure out how to get the actual foreign key name to display either. Appreciate any help or pointers as to what I'm doing incorrectly. I'm so close!
回答1:
Try this:
def get_context_data(self, **kwargs):
context = super(ChartView, self).get_context_data(**kwargs)
qs1 = Class.objects.filter(id__in=self.request.user.userprofile.class.all()).order_by('id')
class_names = [ cls.class_name for cls in qs1]
books_count = [ Books.objects.filter(class=cls).count() for cls in qs1 ]
context['qs1'] = class_names
context['qs2'] = books_count
return context
Here i want both the Class
and Books
queryset to be ordered by class because the order is crucial. Here in the context i inject the Class
names and Books
count directly in the context.
Use This srcipt in the template
:
<script>
var labels = "{{ qs1 }}";
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: Array.from(labels),
datasets: [{
label: "# of Books",
data: [{% for j in qs2 %}
{{ j }},
{% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
}
})
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
</script>
There is no need for ajax request you already got the data from the context
I hope this will work.
回答2:
After working all day with Yusef BH, came to the following solution regarding rendering the data correctly. Of note is that the labels are still not coming through. I have opened up a separate SO issue for the labels. Here is the code that allowed me to display the items correctly on the graph.
My HTML
{% extends 'base5.html' %}
{% block body_block %}
<div class="box6">
<h1 class="title">Number of Books By Author</h1>
<canvas id="myChart"></canvas>
<div>
<script>
var endpoint = '{% url "Books:chart_data" %}'
var defaultData = [];
var labels = [];
array = {{ procedures3 }}
$.ajax({
method: "GET",
credentials: 'same-origin',
url: endpoint,
success: function(data){
defaultData = data.default
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [{% for i in book %}{{ i.id }},{% endfor %}],
datasets: [{
label: "# of Procedures",
data: [{% for j in book_count %}
{{ j }},
{% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
}
})
},
error: function(error_data){
console.log("error")
console.log(error_data)
},
})
</script>
{% endblock %}
Views.py
ChartView
class ChartData(LoginRequiredMixin,APIView):
model = Author
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
default_items = []
labels = []
data = {
"labels": labels,
"default": default_items,
}
return Response(data)
The ChartView
class ChartView(LoginRequiredMixin, TemplateView): template_name = 'Book/chart.html'
def get_context_data(self, **kwargs):
context = super(ChartView, self).get_context_data(**kwargs)
book = Author.objects.filter(id__in=self.request.user.userprofile.author.all()).order_by('id')
books_count = [ Book.objects.filter(author=cls).count() for cls in book ]
context['book'] = book
context['book_count'] = books_count
return context
来源:https://stackoverflow.com/questions/51026703/django-and-chart-js-not-rendering-graph-correctly