Django -- 從平凡到超凡

第 9 章    在頁面顯示資料

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

∗ 顯示部落格文章

▸ 目前進入部落格頁面僅顯示「部落格 -- 歡迎蒞臨」等字樣,現在改為顯示部落格文章,修改 views 程式:

article/views.py
from django.shortcuts import render

from article.models import Article


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

▸ 修改範本:在 content 區塊加入內容

article/templates/article/article.html
...
{% block content %}
<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 %}
{% endblock %}
{% 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>簡單學習Django</h3>
  <p>發表時間:...</p>
  <div class="articleContent">
  <p>簡單學習Django<br>
     簡單學習Django<br>
     簡單學習Django<br>
     ...
  <p>
  <div>
  <hr>

∗ 加上 CSS 設定,讓文章呈現邊框及背景

▸ 首先在 base.html 中新增名為 css 之範本區塊,讓各個 App 決定是否加入各別的 CSS 連結

main/templates/main/base.html
...
<head>
<title>部落格</title>
<meta charset="utf-8">
<link rel="stylesheet" href="/static/main/css/main.css">
{% block css %}{% endblock %}
</head>
...

▸ 新增 CSS 檔案 (先建立以下目錄: article/static, article/static/article, article/static/article/css)

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

▸ 在 article.html 加上 CSS 連結:

article/templates/article/article.html
{% extends 'main/base.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'article/css/article.css' %}">
{% endblock %}
{% block heading %}歡迎蒞臨{% endblock %}
{% block content %}
...
{% endblock %}
✶ 只要在範本中有靜態檔案連結者,均需要加上 {% load static %}
✶ 新增 css 範本區塊,內容為 CSS 檔案之連結

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

article CSS

∗ 僅顯示文章部份內容

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

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

▸ 註:另有

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

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

∗ 取出文章留言

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

article/views.py
...
from article.models import Article, Comment


def article(request):
    '''
    Render the article page
    '''
    articles = Article.objects.all()
    articles = {article:Comment.objects.filter(article=article) for article in Article.objects.all()}
    context = {'articles':articles}
    return render(request, 'article/article.html', context)
✶ 匯入 Comment model
✶ 將 articles 變數改為一個字典 (Dictionary),其中每個項目的鍵 (Key) 就是文章物件,而其對應值 (Value) 就是所屬的留言查詢集 (Queryset):
articles = {
  article1: [comment1-1, comment1-2, comment1-3, ...],
  article2: [comment2-1, comment2-2, comment2-3, ...],
  ...
}
✶ 迴圈:每一篇文章迴圈產生一組字典項目
✶ 註:Python 3.6 開始,字典項目依照輸入的順序排序,因此文章還是會依照日期順序來顯示

∗ 頁面顯示文章及留言

article/templates/article/article.html

...
{% block content %}
<br>
{% for article in articles %}
  ...
{% endfor %}
{% for article, comments in articles.items %}
  <h3>{{ article.title }}</h3>
  <p>發表時間:{{ article.pubDateTime|date:'Y-m-d H:i' }}</p>
  <div class="articleContent">{{ article.content|linebreaks|truncatechars_html:30 }}</div>
  {% for comment in comments %}
    <div class="commentDiv">
      <span class="comment">{{ comment.content }}</span>
      <br>
      <span class="commentTime">{{ comment.pubDateTime|date:'m月d日 H:i' }}</span>
    </div>
  {% endfor %}
  <hr>
{% endfor %}
{% endblock %}

▸ 利用 2 層巢狀迴圈顯示文章及留言,外層迴圈的每一個項目是文章,內層迴圈的每一個項目文章的所屬留言

▸ 以迴圈處理字典的範本指令格式如下:

{% for key, value in <dict>.items %}
  {{ key }}: {{ value }}
{% endfor %}
因此,取用文章及留言的迴圈語法為 {% for article, comments in articles.items %}

▸ 每個留言設定 commentDiv, comment, commentTime 等 CSS 類別, 留言字體設定較小,日期設為灰色:

article/static/article/css/article.css
.articleContent {
  ...
}

.commentDiv {
  margin-top: 1em;
}

.comment {
  font-size: 0.8em;
}

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

∗ 上推專案到 Github

... Commit message: Chapter 9 finished Commit and Push

▸ 練習