20、阅读计数统计和显示
1、简单计数方法的缺点
- 1、后台编辑博客可能影响数据
- 2、功能单一,无法统计某一天的阅读数
本节想要实现的效果如下:
2、统计需要记录明细
例如:
阅读量120 —> 2月1号 阅读量20、 2月2号 阅读量60、2月3号 阅读量40
1、模型models
修改read_statistics\models.py代码如下:
数据库同步:
2、admin
修改admin.p如下:
启动服务器,刷新页面
添加一条记录
接下来我们要考虑一个问题,这个数据我们怎么加 什么时候加 怎么去统计单天或者对应博客阅读数量,这里可能有一种思路,就是记录每条每次打开博客详情,每次都有一个日期时间,最后把它统计汇总填到我们刚刚的模型。这个方法可行,但麻烦。
另外还有一种,在utils.py里既然有一个阅读数量添加的判断处理,那么也可以在这个地方,我们当天打开第一篇博客,那么我们就可以加上一条明细
修改utils.py如下:
# # C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\read_statistics\utils.py
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
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) # 模型名称,主键值
# 对应views.py中判断cookie是否存在:if not request.COOKIES.get('blog_%s_read' % blog_pk),和设置cookie的方法: response.set_cookie('blog_%s_read' % blog_pk, 'true')
if not request.COOKIES.get(key): # 当不存在这个键值的时候,我们才进行阅读加1的操作
# ct = ContentType.objects.get_for_model(Blog)
if ReadNum.objects.filter(content_type=ct, object_id=obj.pk).count():
# 存在记录
readnum = ReadNum.objects.get(content_type=ct, object_id=obj.pk)
else:
# 不存在对应的记录
readnum = ReadNum(content_type=ct, object_id=obj.pk)
# 计数加1
readnum.read_num +=1
readnum.save()
date = timezone.now().date()
if ReadDetail.objects.filter(content_type=ct, object_id=obj.pk, date=date).count():
readDetail = ReadDetail.objects.get(content_type=ct, object_id=obj.pk, date=date)
else:
readDetail = ReadDetail(content_type=ct, object_id=obj.pk, date=date)
readDetail.read_num += 1
readDetail.save()
return key
下面讲更简单的方法:
上面的逻辑判断实际上是一个处理逻辑,我们获取我们想要的记录,如果不存在就创建。这种django提供了一个叫做get_or_create
的方法(获取某内容,如果获取不到,就创建),我们通过shell 或者查看django官方文档都能找到
可以修改utils.py如下:
# # C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\read_statistics\utils.py
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
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) # 模型名称,主键值
# 对应views.py中判断cookie是否存在:if not request.COOKIES.get('blog_%s_read' % blog_pk),和设置cookie的方法: response.set_cookie('blog_%s_read' % blog_pk, 'true')
if not request.COOKIES.get(key):
# 总阅读数 +1
# 返回结果:第一个是我们所需要对象,第二个表示是否创建(如果是创建的,为true;如果是获取到的,为false
readnum, created = ReadNum.objects.get_or_create(content_type=ct, object_id=obj.pk)
readnum.read_num +=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
接下来,我们要展示什么数据、如何把数据展示出来
第一步,要展示什么数据
这里,我们先获取前面七天的阅读数据
修改utils.py如下:【range(-6, -1, -1) 】
import datetime
from django.db.models import Sum
def get_seven_days_read_data(content_type): # 我们要做成一个通用的统计方法,所以这里传入content_type类型这个参数
today = timezone.now().date() # 获取当天日期
read_nums = []
# for i in range(7, 0, -1):
for i in range(6, -1, -1):
date = today - datetime.timedelta(days=i) # timedelta:差值
read_details = ReadDetail.objects.filter(content_type=content_type, date=date)
result = read_details.aggregate(read_num_sum=Sum('read_num')) # 对read_num字段进行求和,取名为read_num_sum
read_nums.append(result['read_num_sum'])
return read_nums
其中的aggregate方法在shell中展示如下:
然后我们想要在前端页面的首页中显示这个数据,那么可以修改mysite/views.py如下:
from django.shortcuts import render_to_response
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)
context = {}
context['dates'] = dates
context['read_nums'] = read_nums
return render_to_response('home.html', context)
接下来我们改一下对应的模板页面,修改home.html如下:
刷新页面的首页,效果如下
想要将None显示为0
修改utils.py如下:
接下来,我们想要用更好看的方式显示出来,这里我们想要用图表比较好
3、使用图表显示数据
- 后台 + 前端
- 后台提供数据,前端使用数据
我们使用的是 Highcharts ,将以下示例代码直接复制到home.html
然后对应的修改home.html如下:
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\home.html -->
<!-- 首页的模板页面 -->
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}
我的网站 | 首页
{% endblock %}
{% block nav_home_active %}active{% endblock %}
{% block header_extends %}
<link rel="stylesheet" type="text/css" href="{% static 'home.css' %}">
<!-- 引入 highcharts.js -->
<script src="http://cdn.highcharts.com.cn/highcharts/highcharts.js"></script>
{% endblock %}
{% block content %}
<h3 class="home-content">欢迎访问我的网站,随便看</h3>
<!-- <p>{{ read_nums }}</p> -->
<!-- 图表容器 DOM -->
<div id="container" style="width: 600px;height:400px;"></div>
<script>
// 图表配置
var options = {
chart: {
type: 'line' //指定图表的类型,默认是折线图(line)
},
title: {
text: null // 标题、不需要则设置为null
},
xAxis: {
categories: {{ dates|safe }}, // x 轴分类
tickmarkPlacement: 'on',
title: { text: '前7日阅读量变化' },
},
yAxis: {
title: { text: null }, // y 轴标题
labels:{ enabled: false }, //去掉左侧的坐标轴显示内容
gridLineDashStyle: 'Dash', //坐标横格线设置为虚线
},
series: [{ // 数据列
name: '阅读量', // 数据列名
data: {{ read_nums }} // 数据
}],
plotOptions: { //数据标签(dataLables)。从官方文档中复制代码过来
line: {
dataLabels: {
enabled: true
}
}
},
legend: { enabled: false }, //图例。通过设置 legend.enabled = true | false 来打开或关闭图例。https://www.highcharts.com.cn/docs/basic-legend
credits: { enabled: false }, //图表版权信息。显示在图表右下方的包含链接的文字,默认的文字是 Highcharts,链接是Highcharts官网地址。通过指定credits.enabled=false即可不显示该信息。
};
// 图表初始化函数
var chart = Highcharts.chart('container', options);
</script>
{% endblock %}
我们需要拿到日期数组,所以也需要返回date,修改utils.py如下:
修改views.py如下:
接下来,我们调整页面布局,修改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;
刷新页面