django-rest-framework - 如何从 Django Serializer 呈现默认值以用于图表目的?
问题描述
我正在使用 Django Rest 为我的前端聚合一些数据以进行渲染(通过 Chart.js)
假设我想要一张图表,其中 x 轴上的月份(1 月至 12 月)和total_cost
y 轴上的值。如果没有找到该月的值,我如何确保始终吐出所有 12 个月并为 y 轴提供“0”?
例如,来自 Django rest 的这个序列化数据缺少 11 月和 12 月的值,但我仍然需要 Chart JS 的这些标签才能正确呈现
[
{
"month": "2020-01-01",
"total_cost": "199.00"
},
{
"month": "2020-02-01",
"total_cost": "222.00"
},
{
"month": "2020-03-01",
"total_cost": "399.00"
},
{
"month": "2020-04-01",
"total_cost": "414.00"
},
{
"month": "2020-05-01",
"total_cost": "555.00"
},
{
"month": "2020-06-01",
"total_cost": "615.00"
},
{
"month": "2020-07-01",
"total_cost": "700.00"
},
{
"month": "2020-08-01",
"total_cost": "913.00"
},
{
"month": "2020-09-01",
"total_cost": "552.00"
},
{
"month": "2020-10-01",
"total_cost": "1000.00"
}
]
也许这是前端而不是后端的问题?
如果有帮助,我的 django 查询如下所示:
queryset = Expense.object.annotate(month=TruncMonth('expense_date'))
.values('month')
.annotate(total_cost=Sum('cost'))
.values('month', 'total_cost')
.order_by('month')
解决方案
正如您正确猜测的那样,最好在前端而不是后端处理。
您可以将 x 轴定义为时间笛卡尔轴,它通过包含对象和属性的对象data
将数据集作为单个点接受。给定名为 的数组中存在的基础数据,可以通过以下方式创建此类数据:x
y
baseData
Array.map()
baseData.map(o => ({ x: o.month, y: Number(o.total_cost) }))
为确保所有 12 个月都包含在图表中,您还必须在 x 轴上定义ticks.min
和选项。ticks.max
ticks: {
min: '2020-01',
max: '2020-12'
}
请看一下下面的可运行代码,看看它是如何工作的。
请注意,Chart.js 在内部使用Moment.js来实现时间轴的功能。因此,您应该使用在单个文件中包含 Moment.js 的 Chart.js捆绑版本。
const baseData = [
{ "month": "2020-01-01", "total_cost": "199.00" },
{ "month": "2020-02-01", "total_cost": "222.00" },
{ "month": "2020-03-01", "total_cost": "399.00" },
{ "month": "2020-04-01", "total_cost": "414.00" },
{ "month": "2020-05-01", "total_cost": "555.00" },
{ "month": "2020-06-01", "total_cost": "615.00" },
{ "month": "2020-07-01", "total_cost": "700.00" },
{ "month": "2020-08-01", "total_cost": "913.00" },
{ "month": "2020-09-01", "total_cost": "552.00" },
{ "month": "2020-10-01", "total_cost": "1000.00" }
];
new Chart(document.getElementById('myChart'), {
type: 'line',
data: {
datasets: [{
label: 'My Dataset',
data: baseData.map(o => ({ x: o.month, y: Number(o.total_cost) })),
fill: false,
backgroundColor: 'green',
borderColor: 'green'
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'month',
tooltipFormat: 'MMM YYYY'
},
ticks: {
min: '2020-01',
max: '2020-12'
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 200
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="90"></canvas>
推荐阅读
- spring-boot - 在 Openapi 3.0 Spring Boot RESTful API 中验证 URL 参数?
- kubernetes - 使用 Google Kubernetes Engine CPU 调整 Celery 并发性
- c# - 与委托的事件设置
- javascript - 用下划线(Javascript 或 Typescript)替换字符串中不是字母/数字/下划线的符号?
- c# - “重置连接”是什么意思?System.Data.SqlClient.SqlException (0x80131904)
- deep-learning - 网络值通过线性层变为 0
- azure-devops - 如何在 Visual Studio-Test Explorer 中拥有机器人框架测试用例
- c - 如何在 OS161 中添加 open syscall 的两种变体?
- android - Android设置layout_weight,但跳过最后一个填充?
- python - django 中 request.method 的问题,它无法识别 POST,而是将 GET 显示为请求方法