Chart.js是一个很酷的开源JavaScript库,可以帮助你渲染HTML5图表。它是响应式的,有8种不同的图表类型。
在本教程中,我们将探讨一下如何让Django与Chart.js对话,并根据从模型中提取的数据渲染一些简单的图表。
安装
在本教程中,你所要做的就是将Chart.js库添加到你的HTML页面中:
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
你可以从Chart.js官方网站下载并在本地使用,也可以通过上面的URL从CDN使用。
场景示例
我将使用我在教程《如何用Django ORM创建Group By查询》中使用的相同例子,这是对本教程的一个很好的补充,因为实际上使用图表工作的棘手部分是转换数据,使其能够适应柱状图/折线图/等。
我们将使用下面的两个模型,Country
和City
:
class Country(models.Model):
name = models.CharField(max_length=30)
class City(models.Model):
name = models.CharField(max_length=30)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
population = models.PositiveIntegerField()
例子1:饼状图
在第一个例子中,我们只打算检索人口最多的前5个城市,并将其呈现为饼图。 在这个策略中,我们将把图表数据作为视图上下文的一部分返回,并使用Django模板语言将结果注入JavaScript代码中。
views.py
from django.shortcuts import render
from mysite.core.models import City
def pie_chart(request):
labels = []
data = []
queryset = City.objects.order_by('-population')[:5]
for city in queryset:
labels.append(city.name)
data.append(city.population)
return render(request, 'pie_chart.html', {
'labels': labels,
'data': data,
})
基本上在上面的视图中,我们正在迭代City
queryset并建立一个labels
和一个data
的列表。在这种情况下,data
是保存在City
模型中的人口数。
对于urls.py
,只是一个简单的路由。
urls.py
from django.urls import path
from mysite.core import views
urlpatterns = [
path('pie-chart/', views.pie_chart, name='pie-chart'),
]
现在是模板。我从Chart.js的饼图文档中得到了一个基本的片段。
pie_chart.html
{% extends 'base.html' %}
{% block content %}
<div id="container" style="width: 75%;">
<canvas id="pie-chart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
<script>
var config = {
type: 'pie',
data: {
datasets: [{
data: {{ data|safe }},
backgroundColor: [
'#696969', '#808080', '#A9A9A9', '#C0C0C0', '#D3D3D3'
],
label: 'Population'
}],
labels: {{ labels|safe }}
},
options: {
responsive: true
}
};
window.onload = function() {
var ctx = document.getElementById('pie-chart').getContext('2d');
window.myPie = new Chart(ctx, config);
};
</script>
{% endblock %}
在上面的例子中,base.html
模板并不重要,但你可以在我在这篇文章末尾分享的代码例子中看到它。
这种策略并不理想,但效果不错。不好的地方是,我们使用Django模板语言来干扰JavaScript逻辑。当我们把 {{ data|safe}}
的时候,我们直接在JavaScript代码中注入了一个来自服务器的变量。
上面的代码看起来是这样的:
例2:带Ajax的条形图
正如标题所说,我们现在要用一个异步调用来渲染一个条形图。
views.py
from django.shortcuts import render
from django.db.models import Sum
from django.http import JsonResponse
from mysite.core.models import City
def home(request):
return render(request, 'home.html')
def population_chart(request):
labels = []
data = []
queryset = City.objects.values('country__name').annotate(country_population=Sum('population')).order_by('-country_population')
for entry in queryset:
labels.append(entry['country__name'])
data.append(entry['country_population'])
return JsonResponse(data={
'labels': labels,
'data': data,
})
所以这里我们使用两个视图。home
视图将是加载图表的主页面。另一个视图population_chart
,它的唯一职责是汇总数据,并返回一个带有标签和数据的JSON响应。
如果你想知道这个查询集在做什么,它正在按国家对城市进行分组,并汇总每个国家的总人口。其结果将是一个国家+总人口的列表。要了解更多关于这种查询的信息,请看这篇文章。如何使用Django ORM创建Group By查询
urls.py
from django.urls import path
from mysite.core import views
urlpatterns = [
path('', views.home, name='home'),
path('population-chart/', views.population_chart, name='population-chart'),
]
home.html
{% extends 'base.html' %}
{% block content %}
<div id="container" style="width: 75%;">
<canvas id="population-chart" data-url="{% url 'population-chart' %}"></canvas>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
<script>
$(function () {
var $populationChart = $("#population-chart");
$.ajax({
url: $populationChart.data("url"),
success: function (data) {
var ctx = $populationChart[0].getContext("2d");
new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'Population',
backgroundColor: 'blue',
data: data.data
}]
},
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Population Bar Chart'
}
}
});
}
});
});
</script>
{% endblock %}
现在我们有了一个更好的关注点分离。看一下图表容器。
<canvas id="population-chart" data-url="{% url 'population-chart' %}"></canvas>
我们添加了一个对持有图表渲染逻辑的URL的引用。后来我们用它来执行Ajax调用。
var $populationChart = $("#population-chart");
$.ajax({
url: $populationChart.data("url"),
success: function (data) {
// ...
}
});
在success
回调里面,然后我们最后使用JsonResponse
数据执行Chart.js相关的代码:
结论
我希望这个教程能帮助你开始使用Chart.js来处理图表。不久前,我发表了另一篇关于同一主题的教程,但使用的是Highcharts库。其方法基本相同。 如何将Highcharts.js与Django集成。