欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

从零开始的django开发生活之阅读计数统计和显示(14)

程序员文章站 2022-04-24 09:48:17
...

十四、阅读计数统计和显示

下面解决简单计数的另一个缺点,功能单一,无法统计某一天的阅读数

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 进入后台查看,并添加一条数据

从零开始的django开发生活之阅读计数统计和显示(14)
下面写具体实现方法,经过分析,这个明细统计完全可以独立存在,不受其他计数的影响,点进一篇博客时,这篇博客的阅读数加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模式下:

从零开始的django开发生活之阅读计数统计和显示(14)

可以看到一个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

从零开始的django开发生活之阅读计数统计和显示(14)
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;
}
相关标签: 网站制作