Django搭建個人博客:根據瀏覽量對最熱文章排序

有了瀏覽量之後,文章受歡迎的程度就有了評價標準。隨之而來的就有根據瀏覽量對文章進行排序的需求,即顯示**“最熱文章”**。

現在你已經很熟悉MTV模式,不需要我囉嗦也能完成任務:

  • 文章的模型已經有了,不需要寫Model了
  • 寫一個視圖函數article_list_by_views(),取出按瀏覽排序後的文章對象
  • 將文章對象傳遞到模板,並進行渲染

很簡單,但也隱藏着問題:最熱文章列表和之前的普通文章列表相比,大部分功能其實都是相同的,僅僅是排序不同而已。

萬一哪天需要根據文章標題排序呢?萬一還需要用戶id排序、標籤排序、收藏排序…不僅如此,就連路由urls.py都要跟着膨脹。代碼會越來越臃腫且不可維護。

**重複的代碼是萬惡之源。**因此這裏挑戰一下,不創建新的視圖/路由,而是將排序功能融合到已有的視圖/路由中。

視圖

根據以上需求,重寫article_list()

article/views.py

...
# 重寫文章列表
def article_list(request):
    # 根據GET請求中查詢條件
    # 返回不同排序的對象數組
    if request.GET.get('order') == 'total_views':
        article_list = ArticlePost.objects.all().order_by('-total_views')
        order = 'total_views'
    else:
        article_list = ArticlePost.objects.all()
        order = 'normal'

    paginator = Paginator(article_list, 3)
    page = request.GET.get('page')
    articles = paginator.get_page(page)
    
    # 修改此行
    context = { 'articles': articles, 'order': order }
    
    return render(request, 'article/list.html', context)

重點知識如下:

  • 前面用過GET請求傳遞單個參數。它也是可以傳遞多個參數的,如?a=1&b=2,參數間用&隔開
  • 視圖根據GET參數order的值,判斷取出的文章如何排序
  • order_by()方法指定對象如何進行排序。模型中有total_views這個整數字段,因此‘total_views’爲正序,‘-total_views’爲逆序
  • 爲什麼把新變量order也傳遞到模板中?因爲文章需要翻頁!order給模板一個標識,提醒模板下一頁應該如何排序

這樣一來,排序所需要的參數都可以通過查詢獲得,連urls.py都不用改寫了。

模板

接下來修改文章列表模板:優化入口,並且正確分頁:

templates/article/list.html

...

<div class="container">
    <nav aria-label="breadcrumb">
        <ol class="breadcrumb">
            <li class="breadcrumb-item">
                <a href="{% url 'article:article_list' %}">
                    最新
                </a>
            </li>
            <li class="breadcrumb-item">
                <a href="{% url 'article:article_list' %}?order=total_views">
                    最熱
                </a>
            </li>
        </ol>
    </nav>
    
    <div class="row mt-2">
        {% for article in articles %}
        ...
        {% endfor %}
    </div>

<!-- 頁碼導航 -->
...
<a href="?page=1&order={{ order }}" class="btn btn-success">&laquo; 1</a>
...
<a href="?page={{ articles.previous_page_number }}&order={{ order }}" 
   class="btn btn-secondary">...</a>
...
    {% if articles.has_next %}
<a href="?page={{ articles.next_page_number }}&order={{ order }}"
   class="btn btn-secondary">{{ articles.next_page_number }}</a>
...
<a href="?page={{ articles.paginator.num_pages }}&order={{ order }}"
   class="btn btn-success">{{ articles.paginator.num_pages }} &raquo;</a>
...

  • 新增了Bootstrap中的麪包屑導航樣式breadcrumb
  • 頁碼導航中,所有的分頁鏈接都新增了order參數

測試

啓動服務器,點擊“最熱”:

工作得很好!切換頁碼,留意地址欄中是如何變化的。

還剩一個小瑕疵:用戶點擊“最熱”按鈕後,此按鈕最好能夠變爲灰色,並且不可點擊。這個精益求精的機會就留給讀者去優化吧。

header.html中有一個小改動:"寫文章"的入口被挪到用戶下拉菜單中了。

總結

本章已經摸到一個高級的編程領域門檻了:代碼複用。將類似功能的代碼合併到了一起,並且讓後續的功能擴展變得很容易。只需要在視圖中寫幾個elif語句就搞定了。

在讀者以後的編程中,也要儘量優化代碼結構,達到事半功倍的效果。

至此,博客雖小,功能卻相當完整了。繼續努力!

轉載請註明出處。

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