从零开始的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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值