本部分內容參考B站UP再敲一行代碼的Django2教程[1]
第十六課 博客閱讀計數統計和顯示在上一節課中我們學習了如何對博客閱讀量進行統計,還有一個問題沒有解決:沒有具體到某一天的統計數據(雖然訪問量很低,但是可以通過這個需求了解如何進行統計)。本文將解決這個問題,然後對最近七天訪問量進行展示。
1. 統計最近七天博客閱讀數首先我們在read_count/models.py中新建一個ReadDetail類,用於獲得博客的閱讀量。這裡比之前的ReadNum類多增加一個date欄位,默認值為當前時間(數據類型為datetime格式)。然後進行資料庫遷移操作。
from django.utils import timezone
...
class ReadDetail(models.Model):
read_num = models.IntegerField(default=0)
date = models.DateField(default=timezone.now)
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')在read_count/admin.py中註冊模型:
from .models import ReadNum, ReadDetail
...
@admin.register(ReadDetail)
class ReadDetailAdmin(admin.ModelAdmin):
list_display = ('date', 'read_num', 'content_object')打開網頁後臺,如下圖所示:
然後我們以第一篇為例進行設置:
那麼怎麼記錄當天的所有記錄呢?比較好的辦法是我們可以參照read_count/utlis.py中的寫法,當天打開則當天添加一條記錄
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from .models import ReadNum, ReadDetail
def read_count_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):
...
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可以試一下:訪問第一條博客,會發現總閱讀數+1,同時刷新後臺,可以看到該文章當日訪問量+1
這部分代碼的邏輯是:獲取想要的記錄,如果不存在則創建。Django中給我們提供了類似的接口get_or_create,傳入參數,如果沒有記錄就新建記錄,返回元組。
使用這個函數可以改寫read_count_once_read方法
def read_count_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我們在這裡寫一個方法:根據當前日期,往前推6天,獲得最近七天每天的閱讀總量。
>>> from django.db.models import Sum
>>> from read_count.models import ReadDetail
>>> rds = ReadDetail.objects.all()
>>> dir(rds)
[..., 'aggregate', ...]
>>>rds.aggregate(read_num_sum=Sum('read_num'))
{'read_num_sum': 22}
>>>我們使用filter獲得每天的閱讀量,然後使用aggregate對read_sum欄位進行加總,返回的是一個字典。定義一個get_seven_days_read_data,為了read_count應用更加廣泛,這裡傳入一個content_type參數。為了後面畫圖顯示,我們還傳入了一個字符型的時間列表。
def get_seven_days_read_data(content_type):
today = timezone.now.date()
dates = []
read_nums = []
for i in range(6, -1, -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)
dates.append(date.strftime('%Y/%m/%d'))
return dates, read_nums
2. 顯示閱讀量我們選擇在首頁顯示閱讀量,在全局的views.py中修改home方法,傳入dates和read_nums欄位
from django.shortcuts import render
from django.contrib.contenttypes.models import ContentType
from read_count.utils import get_seven_days_read_data
from blog.models import Blog
def home(request):
content_type = ContentType.objects.get_for_model(Blog)
dates, read_nums = get_seven_days_read_data(content_type=content_type)
context = {}
context['dates'] = dates
context['read_nums'] = read_nums
return render(request, "home.html", context)然後在home.html中引用模版標籤
{% extends "base.html" %}
{% load static %}
{% block title %}
我的網站|首頁
{% endblock %}
{% block header_extends %}
<link rel="stylesheet" type="text/css" href="{% static 'home.css' %}">
{% endblock %}
{% block nav_home_active %}active{% endblock %}}
{% block content%}
<h3 class="home-content">歡迎來到祖安!</h3>
{{ read_nums }}
{% endblock %}刷新首頁可以看到列表顯示的read_nums。
在前端使用數據時,可以使用第三方插件。教程中使用的是Highcharts,我們先嘗試使用這個。打開官方文檔(有中文文檔),然後點擊文檔教程-使用教程,可以看到有提供一個實例,我們複製實例中的js代碼到home.html中。
{% extends "base.html" %}
{% load static %}
{% block title %}
我的網站|首頁
{% endblock %}
{% block header_extends %}
<link rel="stylesheet" type="text/css" href="{% static 'home.css' %}">
{% endblock %}
{% block nav_home_active %}active{% endblock %}}
{% block content%}
<h3 class="home-content">歡迎來到祖安!</h3>
{{ read_nums }}
<div id="container" style="width: 600px;height:400px;"></div>
<script src="http://cdn.highcharts.com.cn/highcharts/highcharts.js"></script>
<script>
// 圖表配置
var options = {
chart: {
type: 'bar' //指定圖表的類型,默認是折線圖(line)
},
title: {
text: '我的第一個圖表' // 標題
},
xAxis: {
categories: ['蘋果', '香蕉', '橙子'] // x 軸分類
},
yAxis: {
title: {
text: '吃水果個數' // y 軸標題
}
},
series: [{ // 數據列
name: '小明', // 數據列名
data: [1, 0, 4] // 數據
}, {
name: '小紅',
data: [5, 7, 3]
}]
};
// 圖表初始化函數
var chart = Highcharts.chart('container', options);
</script>
{% endblock %}刷新後首頁顯示如下:
我們可以著手修改這一部分js代碼以適應我們的顯示圖表。
{% block content%}
<h3 class="home-content">歡迎來到祖安!</h3>
<div id="container" style="width: 600px;height:400px;"></div>
<script src="http://code.highcharts.com/highcharts.src.js"></script>
<script>
// 圖表配置
Highcharts.chart
('container',
{
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 }} // 數據
}],
plotOptions: {
line: {
dataLabels: {
enabled: true
}
}
},
legend: { enabled: false },
credits: { enabled: false },
});
</script>
{% endblock %}顯示效果如下:
圖表能夠正確顯示。我們再調整一下首頁部分的CSS。打開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;
}最終首頁效果如下:
以上就是本文的全部內容。博客閱讀數這部分內容較多,原視頻是三節課,我這裡整合成了兩節課。在使用Highcharts時也有遇到一些問題,希望能給後來者提供幫助。下一節課將繼續討論熱門博客排行及緩存提速。
參考資料[1]Django2教程: https://space.bilibili.com/252028233