展开

文章目录

修改历史

修改历史记录

  1. 2021-03-01 10:13:51

使用装饰器统计网站流量

2020-10-14 11:32:42 Python 1711

简介

博客网站部署也有一段时间了,每次看访问量都只能去nginx的日志中查看,因此想到了通过数据库去记录网站的流量的方法,于是记录下来。

前提

在阅读本文之前,你需要知道Python装饰器的一些知识点,同时知道flask框架的基本用法。

简单的flask应用

我们用一个简单的flask应用来说明这个流量统计的实现过程。下面我们先下一个简单的flask应用。

整个应用的结构如下所示。

视图函数

首先我们构建三个视图函数,如下所示

@app.route('/')
@statistic_traffic(db, VisitStatistics)
def index():
    comments, likes, visits = get_data()
    return render_template("index.html", date=date, visits=visits, comments=comments, likes=likes)


@app.route('/comment/')
@statistic_traffic(db, CommentStatistics)
def comment():
    comments, likes, visits = get_data()
    return render_template("index.html", date=date, visits=visits, comments=comments, likes=likes)


@app.route('/like/')
@statistic_traffic(db, LikeStatistics)
def like():
    comments, likes, visits = get_data()
    return render_template("index.html", date=date, visits=visits, comments=comments, likes=likes)

三个视图分别对应的是主页、评论、点赞三个页面,简单起见,我们返回都是同一个index.html.

获取数据库实时数据

其中get_data()函数为获取数据库中实时的数据,具体实现如下所示。

def get_data():
    vst = VisitStatistics.query.filter_by(date=date).first()
    cmt = CommentStatistics.query.filter_by(date=date).first()
    love = LikeStatistics.query.filter_by(date=date).first()
    if vst is None:
        visits = 0
    else:
        visits = vst.times
    if cmt is None:
        comments = 0
    else:
        comments = cmt.times
    if love is None:
        likes = 0
    else:
        likes = love.times
    return comments, likes, visits

在get_data()函数中,我们使用了三个类分别是VisitStatisticsCommentStatisticsLikeStatistics,这三个类都是数据库模型类,通过ORM去操作数据库中的表,简化了我们写SQL语句的步骤。三个模型类的定义如下。

# 数据库模型
class VisitStatistics(db.Model):
    __tablename__ = 'visit_statistics'

    id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
    date = db.Column(db.Date, nullable=False)
    times = db.Column(db.INTEGER, default=1)


class CommentStatistics(db.Model):
    __tablename__ = 'comment_statistics'

    id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
    date = db.Column(db.Date, nullable=False)
    times = db.Column(db.INTEGER, default=1)


class LikeStatistics(db.Model):
    __tablename__ = 'like_statistics'

    id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
    date = db.Column(db.Date, nullable=False)
    times = db.Column(db.INTEGER, default=1)

统计

统计流量的主要思想是用户点击某一个连接(视图函数)我们在视图函数内部进行数据库统计数据更新。流程如下。

一般统计实现

为了统计流量,我们可以在每个视图函数下面写统计操作,如果我们视图函数比较少的话,那还好重复的内容不是很多,但是如果我们视图函数较多,那这样重复的工作量就比较多了,不太符合Python Zen Simple is better than complex.

# 一般的统计方法
@app.route('/')
def view1():
    statistic_traffic()
    ...


@app.route('/')
def view2():
    statistic_traffic()
    ...


@app.route('/')
def view3():
    statistic_traffic()
    ...

上面仅仅是统计一项内容,如果我们需要统计的项目比较多的话,那么代码更加复杂。

使用装饰器做统计

在Python中有东西叫做装饰器,其根本是闭包。在开发中装饰器在权限校验、日志记录等方面使用的比较多,它的使用方法如下

import time

def run_time(func):
    def wrap():
        st = time.time()
        result = func()
        print(time.time()-st)
        return result
    return wrap


@run_time
def test():
    time.sleep(3)

在上面代码中,函数run_time()就是一个装饰器了,我们可以通过它来装饰函数,使得函数增加一些特定的功能。在这里我们使用它装饰了test()函数,那么运行test()函数的时候,就会自动统计该函数的运行时间了。

有了上述基础,我们就可以使用装饰器来做流量统计了,代码如下所示。

def statistic_traffic(db, obj):
    """
    网站今日访问量、评论量、点赞量统计装饰器
    :param db: 数据库操作对象
    :param obj: 统计模型类别(VisitStatistics,CommentStatistics,LikeStatistics)
    :return:
    """
    def decorator(func):
        @wraps(func)
        def decorated_function(*args, **kwargs):
            td = datetime.date.today()
            vst = obj.query.filter_by(date=td).first()
            if vst is None:
                new_vst = obj(date=td, times=1)
                db.session.add(new_vst)
            else:
                vst.times += 1
            db.session.commit()
            return func(*args, **kwargs)
        return decorated_function
    return decorator

我们在装饰器中实现了上述流程中的流程,在我们要使用统计功能的时候我们将这个装饰器加在视图函数的上方,用户在点击该链接(视图函数)的时候,就自动实现了统计了。

效果

使用如下命令运行程序

python app.py

打开连接http://127.0.0.1:500,可以看到如下效果图。

当我们点击下面三个按钮,对应的内容也会出现变化,如下。

总结

  1. 由于为了实现效果,采用的代码结构非常的简单,而且也存在部分冗余代码;
  2. 装饰器神通广大,并不是这么一点点内容就能讲清楚;
  3. 欢迎各位评论区讨论,谢谢;
  4. 完结~撒花~
  5. 项目代码仓库https://github.com/weijiang1994/traffic/

5条评论


agys 用户

学习了。

话说备案麻烦不?我想整个论坛

Macv 博主 回复:agys

备案不麻烦,就准备点资料。