从零开始的django开发生活之阅读计数统计和显示(14)
十四、阅读计数统计和显示
下面解决简单计数的另一个缺点,功能单一,无法统计某一天的阅读数
1、统计明细
制作一个折线图,记录每天的阅读数
首先在read_statistics添加模型
from django.utils import timezone
class ReadDetail(models.Model):
date = models.DateField(default=timezone.now)
read_num = models.IntegerField(default=0)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
其次执行数据迁移
python manage.py makemigrations
python manage.py migrate
然后定制后台:
from .models import ReadNum, ReadDetail
@admin.register(ReadDetail)
class ReadNumAdmin(admin.ModelAdmin):
list_display = ('date', 'read_num', 'content_object')
最后启动服务器 python manage.py runserver
进入后台查看,并添加一条数据
下面写具体实现方法,经过分析,这个明细统计完全可以独立存在,不受其他计数的影响,点进一篇博客时,这篇博客的阅读数加1,同时那一天的明细也加1,只不过我们要多传入一个参数判断日期是否匹配
在read_statistics/utils.py中对read_statistics_once_read方法改进:
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from .models import ReadNum
def read_statistics_once_read(request, obj):
ct = ContentType.objects.get_for_model(obj)
key = "%s_%s_read" % (ct.model, obj.pk)
if not request.COOKIES.get(key):
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)
readnum.read_num += 1
readnum.save()
date = timezone.now().date()
if ReadDtail.objects.filter(content_type=ct, object_id=obj.pk, date=date).count():
readdteail = ReadDtail.objects.get(content_type=ct, object_id=obj.pk, date=date)
else:
readdetail = ReadDtail(content_type=ct, object_id=obj.pk, date=date)
readdetail.read_num += 1
readdetail.save()
return key
点击任意一篇博客进入之后再进入后台既可以查看到readdetail增加了一条记录
下面对代码简化:
shell模式下:
可以看到一个get_or_create方法,此方法在django文档也有
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)
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
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
2、获取前七日阅读数据
在read_statistics/utils中加一个方法,此方法返回前七日阅读数
import datetime
from django.db.models import Sum
def get_seven_days_read_data(content_type):
today = timezone.now().date()
read_nums = []
for i in range(7, 0, -1):
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_nums.append(result['read_num_sum'] or 0)# 存在数据返回,不存在返回0
return read_nums
aggregate是聚合方法,在这里可用于求和。
在首页使用此方法,打开mysite/views对home方法修改,使他能传递前七日数据给home.html
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)
read_nums = get_seven_days_read_data(blog_content_type)
context = {}
context['read_nums'] = read_nums
return render_to_response('home.html', context)
home.html加p标签展示,即可以查看
3、折线图展示历史阅读数
首先前端把时间传递过来:
utils.py
def get_seven_days_read_data(content_type):
today = timezone.now().date()
read_nums = []
dates = []
for i in range(7, 0, -1):
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_nums.append(result['read_num_sum'] or 0)
return dates, read_nums
views.py
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)
这里我们用highcharts实现,具体操作和使用的一些属性可以去官网查看:
在home.html引入 <script src="http://cdn.highcharts.com.cn/highcharts/highcharts.js"></script>
body中写入:
<!-- 图表容器 DOM -->
<div id="container"></div>
<script>
// 图表配置
var options = {
chart: {
type: 'line' //指定图表的类型,默认是折线图(line)
},
title: {
text: null // 标题
},
xAxis: {
categories: {{ dates|safe }}, // x 轴分类
tickmarkPlacement: 'on',
},
yAxis: {
title: {
text: null // y 轴标题
},
labels: {
enabled: false
},
gridLineDashStyle: 'Dash',
},
series: [{ // 数据列
name: '阅读量', // 数据列名
data: {{ read_nums }} // 数据
}],
legend: {
enabled: false
},
credits: {
enabled: false
},
plotOptions: {
line: {
dataLabels: {
enabled: true
}
}
}
};
// 图表初始化函数
var chart = Highcharts.chart('container', options);
</script>
{% endblock %}
home.css
h3.home-content{
font-size: 200%;
text-align: center;
margin-top: 4em;
margin-bottom: 2em;
/*position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);*/
}
div#container{
margin:0 auto;
height: 20em;
min-width: 20em;
max-width: 30em;
}
上一篇: perl学习笔记 - 输入与输出
下一篇: 通过keil控制台实现命令输入与显示