Django最近一年按月统计数据

最近用到Echart等统计图,接口数据接收的是日、月等固定周期的数据总数,本人后台使用的Django,想走捷径,在网上查了很多资料,经测试,基本都是无效的。这里就记录下自己写这个接口的整个流程。

准备数据

填充数据

数据先要准备好,你可以使用faker,本人只是临时测试这个接口,直接使用了mysql的查询插入语句进行了数据填充,mysql查询插入语句如下:

1
insert into data(create_time, name, phone, city) select create_time, name, phone, city from wechat_formsmodel

修改数据时间

因为按时间统计我这里复制过来的数据时间大都相同,到了这一步只能用随机函数修改下我们的时间字段内容,代码如下:

1
update data set create_time=concat('201', floor(1+rand()*9), '-', floor(1+rand()*12), '-', floor(1+rand()*28), ' ', floor(rand()*24),':',floor(rand()*59),':',floor(rand()*59))

将时间随机修改为2011年到2019年

rand()随机一个0到1的小数,floor去除小数。这里有两个坑:月份和日期不能为零,故前面我都加了1;月份中2月会有28天,所以插入的时候如果2月分配的随机日期为28以上会报错停止运行,故日期都是1号到28号。

此时数据准备完毕。``

准备view视图

初步筛选数据

先筛选出近一年的数据:

1
2
3
4
5
6
7
8
import datetime
from dateutil.relativedelta import relativedelta
# 一年前的今天
start = datetime.datetime.now() - relativedelta(months=12)
# 当前时间
now = datetime.datetime.now()
# 获取近一年内数据
data = DatasModel.objects.filter(create_time__range=(start, now))

利用年月进行分组查询

使用sqlyearmonth进行分组查询

1
2
3
from django.db.models import Count
res = data.extra(select={'year': 'year(create_time)', 'month': 'month(create_time)'}).values('year', 'month').annotate(count=Count('create_time')).order_by()
print(res)

预览下数据

1
<SoftDeleteQuerySet [{'year': 2018, 'month': 9, 'count': 349}, {'year': 2018, 'month': 10, 'count': 522}, {'year': 2018, 'month': 11, 'count': 545}, {'year': 2019, 'month': 4, 'count': 549}, {'year': 2018, 'month': 12, 'count': 556}, {'year': 2019, 'month': 1, 'count': 477}, {'year': 2019, 'month': 8, 'count': 550}, {'year': 2019, 'month': 3, 'count': 555}, {'year': 2019, 'month': 6, 'count': 565}, {'year': 2019, 'month': 7, 'count': 536}, {'year': 2019, 'month': 5, 'count': 533}, {'year': 2019, 'month': 2, 'count': 539}, {'year': 2019, 'month': 9, 'count': 7}]>

因为我是随机修改的,所以时间都是错乱的,程序正常运行时间会正常录入不会出现这种问题,尽然我这里出现这种问题了,本来就要整理数据格式,所以顺手修改下顺序。

整理格式

1
2
3
4
5
6
7
8
9
10
# 接收整理好的数据格式
res_data=[]
for item in res:
# 原始年份和日期都是整数型,月份小于10我要前置0,保持两位数
month = str(item.get('month')) if item.get('month')>9 else '0'+str(item.get('month'))
res_data.append({
'date': str(item.get('year'))+'-'+month,
'count':item.get('count')
})
print(res_data)

预览下整理后的格式:

1
[{'date': '2018-09', 'count': 349}, {'date': '2018-10', 'count': 522}, {'date': '2018-11', 'count': 545}, {'date': '2019-04', 'count': 549}, {'date': '2018-12', 'count': 556}, {'date': '2019-01', 'count': 477}, {'date': '2019-08', 'count': 550}, {'date': '2019-03', 'count': 555}, {'date': '2019-06', 'count': 565}, {'date': '2019-07', 'count': 536}, {'date': '2019-05', 'count': 533}, {'date': '2019-02', 'count': 539}, {'date': '2019-09', 'count': 7}]

整理排序(正式上线可省略该步骤)

格式达到了我们想要的,在整理下顺序吧,按时间排序,python列表为我们准备了sort排序方法

1
2
3
4
5
# 按日期排序
def sortList(item):
return item.get('date')
res_data.sort(key=sortList)
print(res_data)

因为我们列表里嵌套的是字典,所以我们只能用函数指定列表用字典中的哪个键进行排序

预览排序后的效果:

1
[{'date': '2018-09', 'count': 349}, {'date': '2018-10', 'count': 522}, {'date': '2018-11', 'count': 545}, {'date': '2018-12', 'count': 556}, {'date': '2019-01', 'count': 477}, {'date': '2019-02', 'count': 539}, {'date': '2019-03', 'count': 555}, {'date': '2019-04', 'count': 549}, {'date': '2019-05', 'count': 533}, {'date': '2019-06', 'count': 565}, {'date': '2019-07', 'count': 536}, {'date': '2019-08', 'count': 550}, {'date': '2019-09', 'count': 7}]

完整代码

这个就是我们最后需要的格式,直接响应给前端就能用了,最后附上view完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def test(request):
from django.db.models import Count
import datetime
from dateutil.relativedelta import relativedelta
# 一年前的今天
start = datetime.datetime.now() - relativedelta(months=12)
# 当前时间
now = datetime.datetime.now()
# 获取近一年内数据
data = FormsModel.objects.filter(create_time__range=(start, now))
res = data.extra(select={'year': 'year(create_time)', 'month': 'month(create_time)'}).values('year', 'month').annotate(count=Count('create_time')).order_by()
res_data=[]
for item in res:
month = str(item.get('month')) if item.get('month')>9 else '0'+str(item.get('month'))
res_data.append({
'date': str(item.get('year'))+'-'+month,
'count':item.get('count')
})
def sortList(item):
return item.get('date')
res_data.sort(key=sortList)
return JsonResponse(res_data)