Django搭建個人博客:統計文章瀏覽量

文章瀏覽量是所有社交類網站所必備的數據,足以顯示其重要性了。

博主可以通過瀏覽量來評估某篇文章的受歡迎程度,讀者也能夠通過瀏覽量來篩選質量更高的文章。

然而,準確統計瀏覽量並不簡單:

  • 某些類型的請求不應該統計爲瀏覽量,比如作者自己的瀏覽或編輯文章之後的重定向請求;
  • 由於用戶衆多,瀏覽量的數據時刻都在快速更新,會給數據庫帶來很大的壓力。因此很多大型網站都會使用如Redis這樣的讀寫速度非常快的內存數據庫輔助存儲。

因爲我們的項目是博客網站,粗略統計就可以了,也沒有那麼大的用戶壓力,所以設計就簡單得多了。

模型

瀏覽量作爲每篇博文都有的數據,需要一個字段來存儲。

因此修改文章的模型:

article/models.py

...
class ArticlePost(models.Model):
    ...
    
    total_views = models.PositiveIntegerField(default=0)
    
    ...
  • PositiveIntegerField是用於存儲正整數的字段
  • default=0設定初始值從0開始

修改完數據庫別忘了要數據遷移,否則更改不會生效。

由於新字段設置了初始值,遷移會很順暢:

(env) E:\django_project\my_blog>python manage.py makemigrations
Migrations for 'article':
  article\migrations\0003_articlepost_total_views.py
    - Add field total_views to articlepost
Migrations for 'userprofile':
  userprofile\migrations\0002_auto_20181227_2041.py
    - Alter field avatar on profile
    - Alter field user on profile

(env) E:\django_project\my_blog>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, article, auth, contenttypes, sessions, userprofile
Running migrations:
  Applying article.0003_articlepost_total_views... OK
  Applying userprofile.0002_auto_20181227_2041... OK

列表模板

爲了方便觀察效果,這次先寫模板文件。

什麼地方需要顯示瀏覽量呢?很容易想到的就是文章列表了。修改文章列表的模板:

templates/article/list.html

...

<div class="card-footer">
    <!-- 已有代碼 -->
    <a href="{% url 'article:article_detail' article.id %}"
        class="btn btn-primary">
        閱讀本文
    </a>

    <!-- 顯示瀏覽量 -->
    <span>
        <small class="col align-self-end" style="color: gray;">
            瀏覽: {{ article.total_views }}
        </small>
    </span>

</div>

...

筆者將瀏覽量顯示在了**“閱讀本文”**的邊上。

有的同學覺得顯示在這裏不好看,請修改代碼,將其放到自己最滿意的地方。(順便熟悉一下Bootstrap!)

詳情模板

除了文章列表外,通常詳情頁面中也需要顯示瀏覽量。

除此之外,在前面的學習中爲了方便,沒有做任何權限管理,以至於任何用戶都可以對所有文章進行修改、刪除:

這樣是肯定不行的,必須修復這個嚴重的錯誤。

修改article/detail.html模板文件:

templates/article/detail.html

...
<!-- 文章詳情 -->
<div class="container">
    <div class="row">
        ...
        <div class="col-12 alert alert-success">
            <div>
                作者:{{ article.author }}
                {% if user == article.author %}
                    · <a href="#" onclick="confirm_delete()">刪除文章</a>
                    · <a href="{% url "article:article_update" article.id %}">
                        編輯文章
                    </a>
                {% endif %}
            </div>
            <div>
                瀏覽:{{ article.total_views }}
            </div>
        </div>
        ...
</div>
...

修改內容有:

  • 確認當前登錄用戶是文章的作者,才顯示“刪除文章、“編輯文章”兩個鏈接
  • 顯示瀏覽量

修改後的頁面如下:

上圖中由於文章作者和登錄用戶不一致,修改文章的鏈接沒有渲染出來了;如果登錄用戶是作者本人,它們又會正常顯示。

這樣的方法可以阻止大部分的“好用戶”非法修改數據。但是如果有“壞用戶”直接輸入url地址來使壞,該怎麼辦呢?所以光是靠前端頁面來鑑權是不夠的。

視圖

現在瀏覽量能夠正確顯示了,但是由於沒有進行任何處理,其數值會一直爲0。我們希望每當用戶訪問詳情頁面時,瀏覽量就加1。

修改article_detail()如下:

article/views.py

...
def article_detail(request, id):
    article = ArticlePost.objects.get(id=id)
    
    # 瀏覽量 +1
    article.total_views += 1
    article.save(update_fields=['total_views'])
    
    ...

update_fields=[]指定了數據庫只更新total_views字段,優化執行效率。

測試一下,可以正常對瀏覽量計數了:

視圖中鑑權

前面講了,光是在模板中鑑權是不夠的,必須在後端業務邏輯中再次驗證用戶身份。

修改article_update()更新文章的視圖:

article/views.py

...
# 提醒用戶登錄
@login_required(login_url='/userprofile/login/')
def article_update(request, id):
    # 已有代碼
    article = ArticlePost.objects.get(id=id)

    # 過濾非作者的用戶
    if request.user != article.author:
        return HttpResponse("抱歉,你無權修改這篇文章。")

    ...

視圖中進行了兩次鑑權:

  • login_required裝飾器過濾未登錄的用戶
  • if語句過濾已登錄、但非作者本人的用戶

通過在業務邏輯中再次驗證身份,完全阻止惡意用戶從中使壞了。

除了更新文章的視圖外,刪除文章也應該做類似的工作,請讀者自行修改並測試。

總結

本章完成了簡單的統計瀏覽量的功能,並且在前後端中對用戶的身份進行了驗證。

下一章學習與瀏覽量緊密相關的功能:查詢最熱文章

轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章