首页 > 解决方案 > 如何从 Django Serializer 呈现默认值以用于图表目的?

问题描述

我正在使用 Django Rest 为我的前端聚合一些数据以进行渲染(通过 Chart.js)

假设我想要一张图表,其中 x 轴上的月份(1 月至 12 月)和total_costy 轴上的值。如果没有找到该月的值,我如何确保始终吐出所有 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')

标签: django-rest-frameworkchart.js

解决方案


正如您正确猜测的那样,最好在前端而不是后端处理。

您可以将 x 轴定义为时间笛卡尔轴,它通过包含对象和属性的对象data将数据集作为单个接受。给定名为 的数组中存在的基础数据,可以通过以下方式创建此类数据:xybaseDataArray.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>


推荐阅读