Django -- 從平凡到超凡

第 8 章    在頁面顯示資料

(1) 在部落格頁面顯示文章

∗ 顯示部落格文章

▸ 目前進入部落格頁面僅顯示「部落格說 -- Hello world!」等字樣,現在改為顯示部落格文章,修改 views 程式:

article/views.py
from django.shortcuts import render

from article.models import Article, Comment


def article(request):
    '''
    Render the article page
    '''
    articles = Article.objects.all()
    context = {'articles':articles}
    return render(request, 'article/article.html', context)
✶ 匯入 ArticleComment model
articles = ...:利用 ORM之 查詢 (Query) 指令取出所有資料
context = ...:利用範本變數 articles 將查詢結果傳至範本

▸ 修改範本:

article.html
  ...
  <body>

    {% include 'main/menu.html' %}
    <h2>部落格說--Hello world!</h2>
    <h2>歡迎來到我的部落格</h2>
    <br> 
    {% for article in articles %}
      <h3>{{ article.title }}</h3>
      <p>發表時間:{{ article.pubDateTime|date:'Y-m-d H:i' }}</p>
      <div class="articleContent">{{ article.content }}</div>
      <hr>
    {% endfor %}
    
  </body>
</html>
{% for article in articles %}:views 程式傳入 articles 串列,此迴圈針對每一筆資料進行處理,每次迴圈所使用的物件稱為 article
{{ article.title }}:顯示 articletitle 欄位內容
{{ article.pubDateTime|date:'Y-m-d H:i' }}: 顯示 pubDateTime 欄位內容
# | 符號稱為過濾器 (Filter),針對資料做進一步處理
# date: 設定資料之日期顯示格式
# Y-m-d:年月日 (4 碼西元年),以短橫線連結,後接一個空白
# H:i:時分(24 時制),中間加冒號
{{ article.content }}:顯示文章內容,並加上一個 articleContent 類別,方便之後的 CSS 樣式設定
✶ 測試:發現文章內容並未斷行 (HTML中,\n 並無效應)
article non-break
# 加上 linebreaks
<div class="articleContent">{{ article.content|linebreaks }}<div>
article break
✶ 再次測試並檢視原始碼:範本引擎將 \n 置換為 <br />, 並且將文章內容以 <p> 段落標籤包住,如下:
     <h3>如何像電腦科學家一樣思考</h3>
      <p>發表時間:...</p>
      <div class="articleContent">
      <p>如何像電腦科學家一樣思考<br />
         如何像電腦科學家一樣思考<br />
         如何像電腦科學家一樣思考<br />
         ...
      <p>
      <p>讚:7</p>
      <hr>

▸ 加上 CSS 設定,讓文章呈現邊框及背景:新增 article/static/article/css/article.css檔案

.articleContent {
  padding: 20px;
  background-color: #e9e9e9;
  border: thin solid gray;
  border-radius: 10px;
}

▸ 在 article.html 加上 CSS 連結:

...
<link rel="stylesheet" href="{% static 'main/css/main.css' %}">
<link rel="stylesheet" href="{% static 'article/css/article.css' %}">
</head>

▸ 測試 (可能需要重新啟動伺服器)

article CSS

∗ 僅顯示文章部份內容

▸ 由於文章內容可能很長,應先顯示部份內容,訪客有興趣的話再看全部內容:利用範本過濾器 truncate_html 截斷文章,只顯示部份內容

{{ article.content|linebreaks|truncatechars_html:30 }}
✶ 僅顯示 30 個字元 (包含 3 個句點),其餘截斷,而且保持 HTML 標籤正確配對
--> 測試:文章內容截斷,並以 3 個句點結束
article Truncate

▸ 註:另有

truncatechars 過濾器:不管 HTML 標籤配對
truncatewords_html 過濾器:不截斷英文單字

(2) 在每篇文章下方顯示所屬留言

∗ 在顯示文章時,一併顯示其所屬留言

▸ 在 views 程式中,同時取出文章與留言

article/views.py
def article(request):
    ...
    articles = Article.objects.all()
    context = {'articles':articles}
    itemList = []
    for article in articles:
        items = [article]
        items.extend(list(Comment.objects.filter(article=article)))
        itemList.append(items)
    context = {'itemList':itemList}
    return render(request, 'article/article.html', context)
✶ 規劃一個二維串列 itemList,其中每個一維串列的第一個項目是文章,其餘是該文章的留言:
[
  [article1, comment1-1, comment1-2, comment1-3, ...],
  [article2, comment2-1, comment2-2, comment2-3, ...],
  ...
]
✶ 在每一篇文章迴圈中:
# items = [article]:將文章放在一維串列 items 的第一個項目
# items.extend(...):利用查詢篩選器 (Query filter) 取出該篇文章的所有留言, 將查詢物件改為串列後再併入 items 串列
✶ 註:Python 附加串列的函式 (假設 a = [1, 2, 3])
# a.extend([4, 5]) --> [1, 2, 3, 4, 5]
# a.append([4, 5]) --> [1, 2, 3, [4, 5]]

∗ 頁面顯示文章及留言

article.html:

    ...
    <h1>歡迎來到我的部落格</h1>
    <br> 
    {% for article in articles %}
      ...
    {% endfor %}
{% for items in itemList %} {% for item in items %} {% if forloop.first %} <h3>{{ item.title }}</h3> <p>發表時間:{{ item.pubDateTime|date:'Y-m-d H:i' }}</p> <div class="articleContent">{{ item.content|linebreaks|truncatechars_html:30 }}</div> {% else %} <div class="commentDiv"> <span class="comment">{{ item.content }}</span><br> <span class="commentTime">{{ item.pubDateTime|date:'m月d日 H:i' }}</span> </div> {% endif %} {% endfor %} <hr> {% endfor %}
...

▸ 利用 2 層巢狀迴圈顯示文章及留言,外層迴圈的每一個項目稱為 items, 內層迴圈的每一個項目稱為 item

{% if forloop.first %} ... {% else %} ... {% endif %}:內層迴圈第一圈的項目是文章,其餘則是留言 (並加上 class="comment",以便之後做樣式設定)

▸ 加上 CSS:縮小留言字體,日期改為灰色

article.css
.articleContent {
  ...
}

.commentDiv {
  margin-top: 1em;
}

.comment {
  font-size: 0.8em;
}

.commentTime {
  font-size: 0.6em;
  color: #777777;
}
--> 測試
article with comment

(3) 小結

∗ 上推專案到 Github

▸ Right click project --> Team --> Commit --> Commit message: Chapter 8 finished --> Commit and Push

∗ 練習

▸ 在 bookstore 專案的 book app 中撰寫相關程式, 讓所有書籍資料在頁面顯示

上一章       下一章