博客阅读数的统计三部曲(三)——图表展示

图表展示阅读数

  • 统计某一天的阅读数,从而实现一周阅读数的统计展示

[TOC]

1.创建ReadDetail模型类

首先在read_statistics应用下面models.py创建一个ReadDetail模型类,用于记录阅读详情,基本字段类似ReadNum类模型

image.png

代码片段,如下:

read_statistics/models.py

+ from django.utils import timezone

class ReadDetail(models.Model):
    '''阅读详情-每日阅读数'''
+    date=models.DateField(default=timezone.now,verbose_name='阅读时间')
    read_num=models.IntegerField(default=0,verbose_name='阅读数')
    content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    class Meta:
        verbose_name='阅读详情'
        verbose_name_plural=verbose_name

2.同步模型到数据库

1. python manage.py makemigrations
2. python manage.py migrate

3.添加应用到admin.py

添加ReadDetail模型到Django管理后台,打开read_statistics应用下面admin.py,做如下操作:


image.png

代码片段如下:

read_statistics/admin.py

from django.contrib import admin
+from .models import ReadNum,ReadDetail

class ReadNumAdmin(admin.ModelAdmin):
    list_display=('id','read_num','content_object')

+class ReadDetailAdmin(admin.ModelAdmin):
+    list_display=('id','date','read_num','content_object')

admin.site.register(ReadNum,ReadNumAdmin)
+admin.site.register(ReadDetail,ReadDetailAdmin)

添加完成后,可以启动服务,登录Django自带的管理后台,看下是都添加成功,成功后如下图所示:

image.png
image.png

4.utils.py里面添加当日文章阅读数量统计

在read_statistics应用下面utils.py里面做当日文章阅读数的判断统计,具体说明详见代码中的说明:

image.png

代码片段:

read_statistics/utils.py

+from django.utils import timezone
from django.contrib.contenttypes.models import ContentType
from .models import ReadNum,ReadDetail

def read_statistics_once_read(request,obj):
    ct=ContentType.objects.get_for_model(obj)
    key="%s_%s_read" % (ct.model,obj.pk)
    # 获取cookie:根据获取cookie的key值'blog_%s_readed' % blog_pk,判断是否存在,不存在则阅读数+1
    if not request.COOKIES.get(key):
        # 阅读总数
        if ReadNum.objects.filter(content_type=ct,object_id=obj.pk).count():
            # 记录已经存在,则获取并阅读数+1,保存
            readnum=ReadNum.objects.get(content_type=ct,object_id=obj.pk)
        else:
            # 对应记录不存在,则创建并阅读数+1,保存(这样就会在阅读数管理页面点击后保存对应文章以及阅读数)
            readnum=ReadNum(content_type=ct,object_id=obj.pk)
        readnum.read_num += 1    #点击该篇文章,阅读数自增1
        readnum.save()


+        date=timezone.now().date()
        # 按照日期的阅读数
+        if ReadDetail.objects.filter(content_type=ct,object_id=obj.pk,date=date).count():
            # 记录已经存在,则获取并阅读数+1,保存
            +readDetail=ReadDetail.objects.get(content_type=ct,object_id=obj.pk,date=date)
+        else:
            # 对应记录不存在,则创建并阅读数+1,保存(这样就会在阅读详情管理页面点击后保存对应文章以及阅读数)            +readDetail=ReadDetail(content_type=ct,object_id=obj.pk,date=date)
+        readDetail.read_num += 1
+        readDetail.save()
    return key

下面查看Django管理页面阅读详情,则会根据上面的判断进行数据改变

image.png

** 根据Django官网get_or_create()方法,对utils.py里面方法进行整理简化**

- 打开Django的官网文章

打开Django的官网文档,搜索get_or_create(),找到对应文档说明:

Django2.0文档-get_or_creat()

image.png

- 整理优化utils.py

修改utils.py里面read_statistics_once_read()方法的判断,使用Django官网提供的get_or_creat()方法进行判断

get_or_create()方法说明:
get_or_create()方法会返回一个元组,自动判断对象是否存在,存在则+1,找不到不存在则创建,后面的created参数是标记该对象是否是创建,如果创建则为True

使用 get_or_create()方法可与一步完成判断,即可将原有的判断代码进行如下修改:

read_statistics/utils.py 修改


image.png

read_statistics/utils.py 最终优化后


image.png

read_statistics/utils.py 代码:

from django.utils import timezone
from django.contrib.contenttypes.models import ContentType
from .models import ReadNum,ReadDetail

def read_statistics_once_read(request,obj):
    ct=ContentType.objects.get_for_model(obj)
    key="%s_%s_read" % (ct.model,obj.pk)

    # 获取cookie:根据获取cookie的key值'blog_%s_readed' % blog_pk,判断是否存在,不存在则阅读数+1
    if not request.COOKIES.get(key):

        # 阅读总数+1
        readnum, created = ReadNum.objects.get_or_create(content_type=ct,object_id=obj.pk)
        readnum.read_num += 1    #点击该篇文章,阅读数自增1
        readnum.save()

        # 当天阅读数+1    
        date=timezone.now().date()
        readDetail, created = ReadDetail.objects.get_or_create(content_type=ct,object_id=obj.pk,date=date)
        readDetail.read_num += 1
        readDetail.save()
    return key

5.获取7天的阅读数据

在utils.py里面新建根据传入的类型参数来获取前7天get_seven_days_read_data()函数

时间计算说明:
import datetime
today-datetime.timedelra(days-1) #昨天
today-datetime.timedelra(days-2) #前天 > .....
根据上面的规律可以依次找出之前的时间来,所以可以使用for循环来找出前7天的时间:
for i in range(7,0,-1):
# 获取前7天的数据
date=today-datetime.timedelra(days=i)

因为每天的阅读数是按照每篇文章来计数的,所以要计算一天的文章阅读数,就需要对这天的阅读数进行聚合计算


image.png
image.png

代码片段:read_statistics/utils.py

import datetime
from django.utils import timezone
from django.db.models import Sum

def get_seven_days_read_data(content_type):
    '''获取前7天阅读数据,根据传入类型获取相应类型前7天阅读数'''
    read_nums=[]
    today=timezone.now().date() #当天时间
    for i in range(7,0,-1):
        # 获取前7天的数据
        date=today-datetime.timedelta(days=i)
        read_details=ReadDetail.objects.filter(content_type=content_type,date=date)  #查询某天的阅读详情对象
        result=read_details.aggregate(read_num_sum=Sum('read_num'))  #根据read_num字段求和Sum('read_num'),并保存在read_num_sum变量中
        read_nums.append(result['read_num_sum'] or 0) #取出result中read_num_sum变量,添加到read_nums列表中;如果是正确取前面的,如果是没有数据,则取0
    return read_nums

6.对前7天阅读数进行显示

打开yhsite目录下面的views.py文件,进行如下操作:


image.png

代码:yhsite/views.py

from django.shortcuts import render
from django.contrib.contenttypes.models import ContentType
from read_statistics.utils import get_seven_days_read_data
from blog.models import Blog

def home(request):
    blog_content_type=ContentType.objects.get_for_model(Blog) #获取文件类型
    read_nums=get_seven_days_read_data(blog_content_type)     #查询该文件类型下前7天的阅读数

    return render(request,'home.html',{'read_nums':read_nums})

再打开模版下面,添加显示标签


image.png

启动服务器,打开首页进行查看:


image.png

显示数据为None,因为暂时还没有前7天的数据,需要对utils.py里面返回数据进行修改,添加若不存在数据则返回数据为0


image.png

修改后刷新页面,显示如下:


image.png

7.使用图表进行数据展示

后台提供数据,前台使用数据进行展示即可,这里我们前台数据展示使用Highcharts.js来完成图表的展示功能

由于在使用Highcharts.js过程中,还需要横坐标的数据,即前7天日期的数据,所以,需要在read_statistics/utils.py文件里get_seven_days_read_data()方法返回日期数据的列表dates

image.png

代码:read_statistics/utils.py

def get_seven_days_read_data(content_type):
    '''获取前7天阅读数据,根据传入类型获取相应类型前7天阅读数'''
    dates=[]         # 前7天的日期列表
    read_nums=[]     # 前7天日期的阅读数列表
    today=timezone.now().date() #当天时间
    for i in range(7,0,-1):
        # 获取前7天的数据
        date=today-datetime.timedelta(days=i)
        dates.append(date.strftime('%m/%d'))
        read_details=ReadDetail.objects.filter(content_type=content_type,date=date)  #查询某天的阅读详情对象
        result=read_details.aggregate(read_num_sum=Sum('read_num'))  #根据read_num字段求和Sum('read_num'),并保存在read_num_sum变量中
        read_nums.append(result['read_num_sum'] or 0) #取出result中read_num_sum变量,添加到read_nums列表中,如果当天没有数据显示0
    return dates,read_nums

再在yhsite/viwes.py里面添加dates的返回数据到前台home.html页面

image.png

代码:yhsite/views.py

from django.shortcuts import render
from django.contrib.contenttypes.models import ContentType
from read_statistics.utils import get_seven_days_read_data
from blog.models import Blog

def home(request):
    blog_content_type=ContentType.objects.get_for_model(Blog) #获取文件类型
    dates,read_nums=get_seven_days_read_data(blog_content_type)     #查询该文件类型下前7天的阅读数

    return render(request,'home.html',{'dates':dates,'read_nums':read_nums})

代码片段:home.html

<script src="http://cdn.hcharts.cn/highcharts/highcharts.js"></script>

<h3 class="home-content">欢迎访问我的网站,随便看</h3>
    <!-- 图表容器 DOM -->
    <div id="container"></div>
    <script>
        // 图表配置
        var options = {
            chart: { type: 'line' },
            title: { text: null },
            xAxis: {
                categories: {{ dates|safe }},   // x 轴分类
                tickmarkPlacement: 'on',
            },
            yAxis: {
                title: { text: null },
                labels:{ enabled: false },
                gridLineDashStyle: 'Dash',
            },
            series: [{                              // 数据列
                name: '阅读量',                     // 数据列名
                data: {{ read_nums }}               // 数据
            }],
            plotOptions: {
                line: {
                    dataLabels: {
                        enabled: true
                    }
                }
            },
            legend: { enabled: false },
            credits: { enabled: false },
        };
        // 图表初始化函数
        var chart = Highcharts.chart('container', options);
    </script>

打开网站首页,显示效果如下:


image.png

再对home.css进行调整,让页面显得美观一些

h3.home-content {
    font-size: 222%;
    text-align: center;
    margin-top: 4em;
    margin-bottom: 2em;
}

div#container {
    margin: 0 auto;
    height: 20em;
    min-width: 20em;
    max-width: 30em;
}

再次打开页面,展示最终效果如下所示:


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容