图表是可以直观展示数据差异的一种形式,在生活中也有很多地方会应用到图表,最近在做吉他谱网站后台时,就打算做一个近十天网站浏览量折线图的功能,在捣鼓了一番后,实现的效果是下图所示,十天之前的不显示,x轴显示日期,y轴显示对应的浏览量,这里的浏览量指的是PV(page view)即页面的浏览量,图表使用的插件是ECharts,为了帮助有同样需要的小伙伴,所以就将实现的过程跟大家分享一下吧。

Flask使用ECharts实现网站浏览量统计图功能

实现过程

数据库部分

因为这篇文章是为了和大家分享网站统计图表的实现过程,所以为了方便表达先假设一个数据表Sitedata表

Flask使用ECharts实现网站浏览量统计图功能

有点类似于元数据表,不过这个表所属的对象只有一个,就是整个网站,这样设计表的原因是因为在后期动态添加网站属性会比较方便,而不用在表上添加新字段并迁移。

然后我们在初始化数据库后,要插入三条数据分别为:

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使用ECharts实现网站浏览量统计图功能

运行flask项目,打开后台管理主页,因为还没有数据,所以图表为空。

Flask使用ECharts实现网站浏览量统计图功能

顺便访问几个页面,然后设置系统时间到7月2日,再次访问几个页面后切换到7月3日,如此往复几天,然后回去看看效果。

Flask使用ECharts实现网站浏览量统计图功能

接下来我们多循环几次上面的操作,看看超过十天会不会删除超过的部分。

Flask使用ECharts实现网站浏览量统计图功能

可以看到十天以前的部分会被删除,所以就不会显示在这里啦。

其他

以上就是一个简单的网站浏览统计折线图效果的实现啦,整个功能实际上只是在对三条数据进行操作:datelog,todayviews,viewlog,理解了first()函数中的代码后还是比较简单的;如果你有什么问题或者发现了一些错误欢迎在下面留言喔,我看到了会及时回复的。

评论

Felix 管理员

看了一下之前写的,有一点问题稍微改改会更好,就是不建议将统计的代码放到before_request那里,这样会把一些访问接口或者是爬虫给统计到,会影响数据准确性。可以把before_request里面的代码放到一个独立的路由下面,然后在需要统计的页面用js动态调用就好。

回复

Felix 管理员

回复 @hy: 抱歉,我这个在线上了,可能不方便给你源码,不过推荐你一本书《Flask web开发 基于python的web应用开发实战 第二版》,这本书可能会比较官方文档更适合入门。如果有问题的话,可以跟我说下,我看能帮上些什么忙。

回复

hy

你好,请问可以发我一份源码吗,最近正在研究flask的相关内容,万分感谢!

回复

  • 最新随笔

  • 中秋经典BGM:滴滴滴
  • 猫确实喜欢在各种犄角旮旯里睡觉
  • 尝试让DALLE生成一些连续的精灵图,让gpt帮忙生成一些提示词,如果能稳定输出的话就很强大了。
    让gpt帮忙生成的DALLE提示词
    "Generate a pixel art sprite sheet of a character walking in four directions (north, south, east, west) in a retro video game style."
    "Create a series of pixel art frames showing a character performing different actions like walking, running, jumping, and attacking in a classic 2D game aesthetic."
  • 路过别人山庄的门口,被一条大黑狗边叫边追过来,幸好骑电动车,不然还不一定跑得过,哈哈哈哈哈哈哈哈哈哈。
  • 最近两周也没咋出去玩,主要也是觉得没啥好玩的(笑哭)。看完布莱恩阿瑟的《复杂经济学》后,里面那个酒吧问题勾起我的兴趣,最近空了就花了些时间实现个python版本,顺便搞了篇博文,很享受这种新知识能和已有知识碰撞的感觉。(配张前段时间拍的图片,梧桐山门口前面那条路,挺漂亮的)
  • 盐田港夜景
  • 为啥这猫总喜欢喝杯子里的水
  • 确实开始冷了,在树林里至少要比人类聚集区低个几度,进出入口就能很明显感觉到。看看深圳水库的风景,貌似后面的视野更开阔。