Django and ChartJS

2020-06-17 09:51发布

问题:

I'm trying to understand if it it's possible to incorporate dynamic data into a Django Chart JS architecture. I went through a couple of tutorials and ultimately got Django to work with ChartJS and it's very good when I'm able to hard code values and then display the related graphs. What I'm ultimately trying to do is this same exercise with dynamic data from my database. I found this identical question in SO, https://stackoverflow.com/questions/47575896/dynamic-chart-using-django-and-chart-js#= but it wasn't answered by anyone. This is exactly what I'm trying to achieve. I've explore serializers a bit, do I need to serialize the data first? Thanks in advance for your thoughts and feedback.

Per the feedback, I have added context to the chart in question but the data is still not coming through. Here is my view:

class ChartView(LoginRequiredMixin, TemplateView):

    model = Myobject 
    template_name = 'director/chart.html'

      def get_context_data(self, **kwargs):
          context = super(ChartView, self).get_context_data(**kwargs)  
          myobject = Myobject.objects.filter(field__in=self.request.user.userprofile.field.all())
          print(myobject)
          context['myobject'] = myobject
          return context

I'm just getting a blank screen, no chart at all, suggesting that something is obviously amiss. Do I need to make additional changes to the Javascript in order to tell it about the object? My assumption is no, that I'm passing this information view the context_data.

I'm also using Ajax, so I'm not sure if that is a complicating factor. Here is my javascript.

<script>
var endpoint = '{% url "myobject: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: 'pie',
            data: {
                labels: [{% for i in myobject %}{{ i.labels }},{% endfor %}],
                datasets: [{
                    data: [{% for i in myobject %}{{ i.data }},{% endfor %}]
                    backgroundColor: [
                        'rgba(255, 99, 132, 0.2)',
                        'rgba(153, 102, 255, 0.2)',
                    ],
                    borderColor: [
                        'rgba(255,99,132,1)',
                        'rgba(153, 102, 255, 1)',
                    ],
                    borderWidth: 1
                }]
            }
        })
    },
    error: function(error_data){
        console.log("error")
        console.log(error_data)
    }
})
</script>

回答1:

You don't necessarily need to use serializers to render dynamic data in Chart.js (although you can if you would like). You can just iterate through your Django context variables like normal in the appropriate locations. Below is a line chart example. I would play around with this example, but this should show you how to easily render dynamic data with Django context variables.

...
<canvas id="funchart" width="75" height="50"></canvas>                      

<script type="text/javascript">  
     var a = document.getElementById('funchart').getContext('2d');
     var myLineChart = new Chart(a, {
               type: 'line',
               data: {
                   labels:[{% for i in myobject %}{{ i.labels }},{% endfor %}],
                   datasets: [{
                        label:'My Dot',
                        data: [{% for i in myobject %}{{ i.data }},{% endfor %}]
                             }]
                      },
               options:{
                   scales: {
                       xAxes: [{
                           display:true
                              }],
                       yAxes: [{
                           ticks: {
                               beginAtZero:true
                                   }
                               }]
                            }
                        }
                      });
</script>


回答2:

so i have been working the same stuff here, i think your label not showing up because the label on chart.js only wants a string, so try this on your labels:

labels: [{% for i in book %}"{{ i.id }}",{% endfor %}]


回答3:

My code below is what ultimately solved the problem on how to get dynamic user data. I am still trying to figure out how to get the labels to work properly. This solution allows the labels to display with ID numbers, which isn't optimal, but I opened a separate SO for the label issue.

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