Django第十七課

2021-03-02 多肉羅羅

本部分內容參考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

相關焦點

  • Django第二十八課
    本部分內容參考B站UP再敲一行代碼的Django2教程[1]⚠️:多圖預警第二十八課 自定義用戶模型在上節課登錄功能中,我們提到了個人資料。這節課我們繼續講述關於個人資料中的用戶自定義內容。這裡大概有兩種方法:一是繼承django的用戶模型;二是使用新的模型拓展關聯User(🌟🌟🌟🌟🌟)。1. 繼承Django的用戶模型我們之前使用的User是在django.contrib.auth.models中引用的,我們可以查看這部分源碼,分析這個User是如何創建的。
  • Django第二十六課
    本部分內容參考B站UP再敲一行代碼的Django2教程[1]第二十六課 實現點讚功能這節課繼續講述實現點讚功能。1. import modelsfrom django.contrib.contenttypes.fields import GenericForeignKeyfrom django.contrib.contenttypes.models import ContentTypefrom django.contrib.auth.models import User#
  • Django第十八課
    本部分內容參考B站UP再敲一行代碼的Django2教程[1]第十八課-熱門博客閱讀及緩存提速在上節課中,我們討論了閱讀計數統計和顯示的問題,我們可以對這個進一步挖掘,統計當日熱門閱讀博客、昨日熱門閱讀博客以及最近七天熱門閱讀博客。
  • Django分頁完整示例
    在django中可以使用兩種方法進行分頁,第一種方法是使用基於函數的視圖,第二種方法是使用基於類的視圖。現在,首先,需要使用此命令創建一個新的django項目。我稱這個項目為MyProjectdjango-admin startproject ProjectName首先,需要將目錄更改為已創建的項目,然後需要創建一個App,我將其稱為MyApp。
  • Python+django網頁設計入門(12):使用Bootstrap和jQuery
    前導課程:Python+django網頁設計入門(11):在線考試與自動評分Python+django網頁設計入門(10):分頁顯示Python+django網頁設計入門(9):自定義反爬蟲功能Python+django網頁設計入門(8):網站項目文件夾布局Python+django網頁設計入門
  • Django&DataTables應用
    如何把資料庫中的數據以表格的形式展示到前端,實現有很多方法,最近用jquery的datatables插件來實現發現還是比較簡單的,今天我們來看一個例子,來說明這個插件的使用,基本原理是view函數從資料庫中讀出數據,jquery通過ajax獲取數據並在前端展示出來,我們先定義一個models.py,如下:from django.db
  • 一個完整的Django入門指南
    要做到這一點,打開settings.py並嘗試找到INSTALLED_APPS變量:INSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions
  • python程式設計師嘔心瀝血整理 Django 優秀資源大全
    django-templated-email, star:291 - 一個 Django 模板,能很容易地發送模板型郵件,可以使用 django 模板,或事務型郵件提供商(如 mailchimp, silverpop 等)。django-yubin, star:22 - django-mailer2 + django-mailviews,及其它功能。
  • Python Django之路與您同行
    主要在這裡寫下自己的學習筆記、軟體測試思考及讀書感悟等,後續可能會系統的介紹一些python、django、移動端自動化測試、接口自動化測試、性能測試等。歡迎您的光臨!要想深入測試,必須了解功能邏輯,對數據流及網站架構比較清楚,這點也說過多次,真的很重要,必須要體現在工作當中,養成習慣,絕對不要對自己測試過的功能模塊其中的技術實現不清楚。這樣測試路會不好走!!!
  • django-admin和manage.py用法
    記錄要點:django-admin和manage.py 能做同樣的事情 像我們常用的python manage.py runserver,用django-admin也可以操作:django-admim runserver 注意: django-admin需要提前提前配置好DJANGO_SETTINGS_MODULE環境變量
  • Django 2.0 項目實戰: 擴展Django自帶User模型,實現用戶註冊與登錄
    INSTALLED_APPS = [    'reg.apps.RegConfig',    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages
  • Django官方為什麼沒有標準項目結構
    startproject的完整格式為django-admin startproject name [directory],可以在後面追加一個目錄參數:...\> django-admin startproject helloworld hello-world就可以了。根目錄是hello-world,裡面的project是helloworld。
  • Django實現分頁功能
    Paginator 可以叫它為分頁器,實際上它也是一個 Python 類,要使用它的時候我們可以用如下方式進行引入:from django.core.paginator import Paginator這個類被定義在 django.core.paginator 模塊中,它的構造函數如下所示:class Paginator
  • 向Django Admin添加圖表
    幸運的是,django後臺管理應用程式是可擴展的,通過一些調整,我們可以將交互式Javascript圖表添加到後臺管理中。問題我想獲得findwork.dev上電子郵件訂閱用戶隨時間變化的圖表預覽。就電子郵件用戶而言,該網站是在增長還是停滯不前?上個月我們有多少訂閱用戶?哪個星期我們得到的訂閱用戶最多?所有用戶都在驗證他們的電子郵件嗎?
  • Python之Django文件上傳
    DOCTYPE html><html><head><meta charset="UTF-8"> <title>kahn django上傳文件</title></head><body><form method="post" action="/uploadFiles/" enctype="multipart
  • django 自帶 user 欄位擴展及頭像上傳
    import adminfrom django.contrib.auth.admin import UserAdminfrom django.contrib.auth.models import Userclass ProfileInline(admin.StackInlin):    model = UserProfile    can_delete
  • Python——用 Django 寫 restful api 接口
    models.py (https://code.ziqiangxuetang.com/django/django-models.html)—— 與資料庫操作相關,存入或讀取數據時用到這個,當然用不到資料庫的時候 你可以不使用。
  • Python基礎教程——秒懂django操作資料庫
    Mariadb資料庫,簡單易用、性能高Python和django提供了完善的操作資料庫及事務的方法,首先明確一點,這很簡單,一點也不複雜,下面你會看到,10行代碼就搞定了。現在,先上結論:如果我們只是很簡單的操作一下資料庫,我們推薦使用mysqlclient這個第三方庫如果對資料庫的操作要做一些處理,資料庫又會變動,或者業務需求比較複雜,那就推薦使用django簡易操作代碼實在太簡單,如下所示:
  • 如何使用Django發送電子郵件和附件
    from django.urls import path, include from test_email.views import ( simple_email, email_with_template, email_with_attachment, email_with_custom_attachment_file_name, bulk_email
  • 最淺顯易懂的Django系列教程(1)-URL與視圖
    在用戶輸入了某個url,請求到我們的網站的時候,django會從項目的urls.py文件中尋找對應的視圖。在urls.py文件中有一個urlpatterns變量,以後django就會從這個變量中讀取所有的匹配規則。匹配規則需要使用django.urls.path函數進行包裹,這個函數會根據傳入的參數返回URLPattern或者是URLResolver的對象。