图表是可以直观展示数据差异的一种形式,在生活中也有很多地方会应用到图表,最近在做吉他谱网站后台时,就打算做一个近十天网站浏览量折线图的功能,在捣鼓了一番后,实现的效果是下图所示,十天之前的不显示,x轴显示日期,y轴显示对应的浏览量,这里的浏览量指的是PV(page view)即页面的浏览量,图表使用的插件是ECharts,为了帮助有同样需要的小伙伴,所以就将实现的过程跟大家分享一下吧。
因为这篇文章是为了和大家分享网站统计图表的实现过程,所以为了方便表达先假设一个数据表Sitedata表
。
有点类似于元数据表,不过这个表所属的对象只有一个,就是整个网站,这样设计表的原因是因为在后期动态添加网站属性会比较方便,而不用在表上添加新字段并迁移。
然后我们在初始化数据库后,要插入三条数据分别为:
datelog
记录一个日期用来判断是否为今天,初始值为数据库初始化时当天的日期,字符串形式;
todayviews
今日的浏览量,初始值为0,字符串形式;
viewslog
储存时间段内日期与浏览量关系的json,类似'{"2020-07-18":11,"2020-07-19":22,"2020-07-20":33}'
,初始值为{}
字符串形式。
代码部分
models.py
from datetime import date
class Sitedata(db.Model):
__tablename__='sitedata'
id=db.Column(db.Integer,primary_key=True)
key=db.Column(db.String(128))
value=db.Column(db.Text)
comment=db.Column(db.Text)
@staticmethod
def insert_data():
init_data={'datelog':[str(date.today()),'日期'],
'todayviews':['0','今日浏览数']
'viewlog':['{}','浏览统计']}
for d in init_data:
data=Sitedata.query.filter_by(key=d).first()
if data is None:
data=Sitedata(key=d)
data.value=init_data[d][0]
data.comment=init_data[d][1]
db.session.add(data)
db.session.commit()
在创建表之后,调用Sitedata.insert_data()
方法插入初始数据。
在这个项目中有两个蓝图一个是main
,这个蓝图中的路由是所有用户可访问,另一个是admin
,这个是管理蓝图,这里面的路由需要管理员登陆才能访问。
浏览量的计算通过flask中的before_request
装饰器来实现,每当用户访问一次main
蓝图中的路由时,执行被before_request
装饰的函数,这也是整个功能最主要的部分。这里我就直接上代码吧,通过注释解释。
main.py
from models import Sitedata
import datetime
import time
import json
def str2date(string,f="%Y-%m-%d"):#写一个将字符串形式的时间转换成日期对象的函数
year,month,day=time.strptime(string,f)[:3]
date=datetime.date(year,month,day)
return date
@main.before_request
def first():
today=datetime.date.today()#获得今天的日期
datelog=Sitedata.query.filter_by(key='datelog').first()#用来判断是否今天的日期
todayviews=Sitedata.query.filter_by(key='todayviews').first()#今天的浏览量
viewlog=Sitedata.query.filter_by(key='viewlog').first()#时间段中浏览量记录json
if datelog.value !=str(today):#若到了第二天
yesterday=datelog.value
yesterday_views=todayviews.value
viewlog_dict=json.loads(viewlog.value)#将json转换成dict的形式
wait_to_pop=[]
for d in viewlog_dict:
date=str2date(d)
if (today-date).days>10:#十天以上的记录删除
wait_to_pop.append(d)
for i in wait_to_pop:
viewlog_dict.pop(i)
viewlog_dict[yesterday]=int(yesterday_views)#在viewlog中添加昨天的浏览量记录
viewlog.value=json.dumps(viewlog_dict)
datelog.value=str(today)
todayviews.value='1' #第二天的第一次访问所以为1
db.session.add(viewlog)
db.session.add(datelog)
db.session.add(todayviews)
else:#还在今天
todayviews.value=str(int(todayviews.value)+1)
db.session.add(todayviews)
db.session.commit()
这个first()
函数会在用户每次请求main蓝图中的路由时判断储存在数据库中的datelog
是否为今天,如果还是今天,就在今天的浏览量todayviews
上加一;如果到了第二天就将数据库中日期与浏览量记录为昨天
与昨天的浏览量
,并添加到viewlog
中,并将viewlog
中十天以前的记录删除;然后重设数据库中日期datelog
为第二天,重设todayviews
为1(因为这也是一次请求,所以为1)。
上面就是在主蓝图中需要做的事了,而图表是显示在管理蓝图的主页中的,这一部分还是比较简单的,只是在数据库中取数据而已,所以我们接下来在admin
蓝图实现一下显示图表的代码吧!
admin.py
from models import Sitedata
import datetime
import time
import json
def str2date(string,f="%Y-%m-%d"):#将字符串形式的时间转换成日期对象的函数
year,month,day=time.strptime(string,f)[:3]
date=datetime.date(year,month,day)
return date
@admin.route('/',methods=['POST','GET'])
@login_required
def index():
viewlog=Sitedata.query.filter_by(key='viewlog').first()
date=json.loads(viewlog.value)
xob=list(date.keys())#获取键名即字符串形式的日期组成的list;字典是无序的,这里开始的代码是用来将dict分为两个按时间排序的list。
xlist=[]
for x in xob:
xlist.append(str2date(x))
xlist.sort()#按时间从早到晚排序,date对象是可以比大小的,所以这里可以sort方法
xob=[]
for x in xlist:
xob.append(str(x))
yob=[]
for x in xob:
yob.append(date[x])
return render_template('admin/index.html',xob=xob,yob=yob)
这里我使用的是一个非常好用的开源可视化库ECharts,简单配置就可满足我们的使用了,我们来看看前端部分的代码吧!
templates/admin/index.html
<div id='viewschart' style='width:100%;height:400px;'></div>
<script>
var myChart=echarts.init(document.getElementById('viewschart'));
var option={
title:{text:'浏览量统计'},
tooltip:{},
legend:{data:['浏览量']},
xAxis:{
data:{{ xob|safe }}
},
yAxis:{},
series:[{
name:'浏览量',
type:'line',
data:{{ yob|safe }}
}]
};
myChart.setOption(option);
</script>
接下来我们来测试一下吧
开始测试之前我们需要做一件事,就是调整电脑的系统时间,这里的时间也可以代表网站服务器时间,往前调整,我这里是调整到2020年7月1日,差不多是十几天前,这么做是为了测试实际效果,然后修改完后创建完表并插入初始数据。
运行flask项目,打开后台管理主页,因为还没有数据,所以图表为空。
顺便访问几个页面,然后设置系统时间到7月2日,再次访问几个页面后切换到7月3日,如此往复几天,然后回去看看效果。
接下来我们多循环几次上面的操作,看看超过十天会不会删除超过的部分。
可以看到十天以前的部分会被删除,所以就不会显示在这里啦。
以上就是一个简单的网站浏览统计折线图效果的实现啦,整个功能实际上只是在对三条数据进行操作:datelog
,todayviews
,viewlog
,理解了first()
函数中的代码后还是比较简单的;如果你有什么问题或者发现了一些错误欢迎在下面留言喔,我看到了会及时回复的。
看了一下之前写的,有一点问题稍微改改会更好,就是不建议将统计的代码放到before_request
那里,这样会把一些访问接口或者是爬虫给统计到,会影响数据准确性。可以把before_request
里面的代码放到一个独立的路由下面,然后在需要统计的页面用js动态调用就好。
回复 @hy: 抱歉,我这个在线上了,可能不方便给你源码,不过推荐你一本书《Flask web开发 基于python的web应用开发实战 第二版》,这本书可能会比较官方文档更适合入门。如果有问题的话,可以跟我说下,我看能帮上些什么忙。