Django -- 從平凡到超凡

第 5 章    部落格系統

(1) 系統功能與資料

∗ 從本章起,將循序建構 blog 系統,規劃功能如下:

▸ 首頁導航 (Navigation) 連結:「關於」、「部落格」、「註冊」、「登入」、「登出」

▸ 關於:有關網站的說明

▸ 管理者 (即部落客) 可以新增、修改、及刪除文章

▸ 訪客可閱讀文章,並可註冊成為會員

▸ 會員可以登入、登出、並針對文章留言及按讚

∗ 系統相關資料

▸ 系統主要資料為 部落格文章各篇文章的留言

--> 規劃兩個資料模型 (Model):Article (文章) 與 Comment (留言) 來儲存這些資料
Article 欄位及資料型態:
# title:文章標題 (字串)
# content:文章內容 (文字)
# pubDateTime:文章發表時間 (日期時間)
# likes:按讚使用者 (多對多關聯 User model)
Comment 欄位及資料型態:
# article: 留言所屬文章 (Article model 的外來鍵)
# user:留言使用者:(User model 的外來鍵)
# content:留言內容 (文字)
# pubDateTime:留言發表時間 (日期時間)

▸ 一個 Article 包含許多 Comment, 一個 Comment 僅屬於一個 Article

▸ 另外還用到 User model (使用者模型),此為 Django 內建

(2) HTTP request 的處理流程

∗ Django 處理 HTTP request 的流程如下:

http流程

  1. 使用者瀏覽器送出 HTTP request
  2. 依據專案直屬 app (Project app) 的 urls.py 裡的 URL 組態 (URL conf) 來對應, 然後將 Request 轉送給負責處理的應用程式 (Handling app)
  3. 依據 Handling app 的 urls.py 裡的 URL conf 來對應, 然後將 Request 轉送給負責處理的 view 程式
  4. Handling app 的 view 程式執行運算 (可能包含資料庫操作) 後,將結果 HTTP Response 物件回傳給使用者瀏覽器,最後瀏覽器依據 HTTP Response 的內容來顯示網頁

∗ URL 對應 (URL mapping)

▸ Project app:對應主網域之後的字串,例如以下 URL request:

http://www.mysite.com/tutorial/django/zh-hant/introduction/
✶ 主網域:http://www.mysite.com/
✶ 將進行對應的字串:tutorial/django/zh-hant/introduction/

▸ Handing app:對應 Prject app 處理後的剩餘字串

✶ 例如:如果 Project app 對應了 tutorial/django/, 那麼 Handling app 就會對應 zh-hant/introduction/

▸ 習慣上,Django 的 URL 字串結尾有一個斜線(/)

(3) 在專案裡建立一個新 app 並撰寫相關程式

∗ Django project 是由許多的 app (Application,應用程式) 所組成

▸ 可規劃每一個 app 負責某項功能,例如:選項清單中的某個功能選項

▸ 各個 Request 由其所對應的 app 來處理,例如下列 URL 格式

http://www.mysite.com/account/register/:註冊帳號
http://www.mysite.com/account/login/:登入帳號
http://www.mysite.com/news/:最新消息
http://www.mysite.com/news/newsCreate/:新增消息
--> 可規劃兩個 app:account (處理註冊及登入) 與 news (處理最新消息)

∗ 在 blog 專案中建立一個 main app

▸ 設定 app 的名稱為 main,主要功能為顯示首頁並置放與其他 app 共用的資源

▸ 建立 main app:Right click project --> Django --> Create Application --> Name of the django app to be created: main --> OK

建立 app 之 CLI

亦可利用 CLI 來建立 main app,指令如下:

▸ 每一個 Django app 的目錄架構都相同,以 main 為例:

main/
   migrations/
   __init__.py
   admin.py
   apps.py
   models.py
   tests.py
   views.py   
migrations/:資料庫遷移目錄,儲存此 app 的資料庫遷移程式
__init__.py:指明這是一個 Python 套件 (Package),因此其他程式可匯入
admin.py:內容包含可在 admin 介面檢視的資料表
apps.py:有關本 app 的相關設定
models.py:資料模型
tests.py:測試程式
views.py:處理 HTTP Request 的程式,可稱為「視圖」程式

▸ 新增 app 後需知會 Django:在 blog/settings.py 裡的 INSTALLED_APPS (已安裝的 app) 中登記:

...
INSTALLED_APPS = [
    'django.contrib.admin', 
    ...
    'django.contrib.staticfiles',
    'main',
]
...
--> Django 利用 Python 的串列 (List) 來儲存已建立的 app,包括 Django 預設的 app

∗ 規劃 URL mapping

▸ Request 的格式若為 http://<domainName>/main/, 就由 main view 來處理

✶ 註:之後教材的 URL Request 格式將省略 http://<domainName>/ 字串, 僅顯示網域之後的 URL 資料

▸ 在專案的 URL 組態檔中匯入 include 函式並設定兩個 URL mapping:

blog/urls.py
...
from django.conf.urls import url, include
from django.contrib import admin


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^main/', include('main.urls', namespace='main')),
    url(r'^.*', include('main.urls')),
]
from ... import ...:匯入套件或模組
urlpatterns:Django 利用 Python 的串列 (List) 資料結構來儲存各個 URL 的對應
# URL 格式使用常規表示式 (Regular expression) 來對應
# 串列變數名稱必須是 urlpatterns
# 每個 URL 對應均利用 url() 函式來設定,有兩個參數:
- 第 1 個參數是 URL 格式:
r (Raw string):表示為原始字串,亦即沒有逸出字元 (Escape character)
^ 表示字串開頭
∗ 因此 r'^admin/' 表示 URL 的格式為 admin/admin/... (亦即在 admin/ 之後可以接續任何字元)
- 第 2 個參數 include(...):匯入 app 的 URL 對應模組,亦有兩個參數:
* 負責處理的 app 的 URL 對應模組 (例如:'main.urls')
* namespace=...:命名此 URL mapping (此稱為「具名 URL」,Named URL)
✶ URL mapping
# url(r'^admin/' ...:如果 URL 格式為 admin/...,則使用 admin.site.urls 模組進進一步比對 URL,此為 Django 內建管理者模組
# url(r'^main/’ ...:如果 URL 格式為 main/..., 則匯入 main.urls 模組進一步比對 URL,並將此 URL 格式的名稱空間 (Namespace) 命名為 main,以供其他程式使用 (Namespace 的意義稍後解釋)
# url(r'^.*' ...:常規表示式的點號 (.) 表示任何字元,星號 (*) 表示其左方的字元可以出現 0 或多次, 因此 ^.* 可對應任何字串 (包括空字串),也就是說, 主網域之後跟著任何字串也都由 main() 函式處理,不要顯示「找不到網頁」之錯誤訊息, 而且對於這個對應我們不給名稱,因為程式不會使用到它

▸ 接下來建立 main app 的 urls.py: 右鍵點 main --> New --> File --> File name: urls.py --> Finish

main/urls.py
from django.conf.urls import url
from main import views


urlpatterns = [
    url(r'^$', views.main, name='main'),
]
from ...:匯入所需模組
urlpatterns ...:利用串列來設定各個 URL 的對應
# 串列變數名稱必須是 urlpatterns
# 每個 URL 對應均利用 url() 函式來設定 (目前只有一個),並有三個參數:
- 第 1 個參數是 URL 格式 (常規表示式):
r (Raw string):表示為原始字串, 亦即沒有逸出字元 (Escape character)
^ 表示字串開頭,$ 表示字串結尾, 因此 ^$ 表示空字串
- 第 2 個參數views.main:此 URL 請求將由視圖 views 裡的 main() 函式來處理
- 第 3 個參數name='main':將此 URL 對應命名為 main,以供其他程式使用
✶ URL mapping:當使用者輸入了 main/ URL Request, main/ 字串符合 blog.urls 裡的 r'^main/' 常規表示式,因此 Django 將剩餘字串 (空字串) 送到 main.urls 對應,空字串符合 r'^$' 常規表示式,因此由 main.views.main 來處理

∗ 接下來在 main/views.py 裡建立 main() 函式

main/views.py

from django.shortcuts import render
from django.http import HttpResponse


def main(request):
    '''
    Show 'Hello world!' in the main page
    '''
    return HttpResponse('Hello world!')

from ...:匯入回覆 HTTP 請求的套件 HttpResponse

def main(request):定義 view 的函式 main, 處理使用者的 HTTP 請求

# Django 會傳入 HTTP request 的資料,main() 函式以 request 參數帶入 (習慣上使用 request 名稱,亦可使用其他名稱)
'''Show ...''':函式註解
request 的內容包括使用者提出 HTTP 請求的相關資訊,例如使用者名稱、所使用的瀏覽器、作業系統、 請求的時間、請求所使用的方法、...

return HttpResponse(...):回覆一個 HttpResponse 物件, 其參數是一個字串 (本例為 Hello world!)

HttpResponse 物件
  1. Django 的 view 函式最後都需要回覆一個 HttpResponse 物件,此類函式包括:
    • HttpResponse():回覆字串或物件
    • render():回覆網頁
    • redirect():轉址
    • get_object_or_404():如果找不到資料就回覆 404 訊息
  2. 常見的 HTML 狀態碼 (Status code)
    • 200:請求成功
    • 302:轉址成功
    • 304:文件未修改
    • 404:找不到網頁
    • 500:伺服器錯誤
具名 URL (Named URL)

Namespace 的用途在於避免不同開發者使用相同的 URL mapping 名稱而造成衝突, 不同的開發者彼此依賴的程度應該越低越好,例如:

∗ 測試

▸ 確認伺服器已啟動

▸ 在瀏覽器輸入 localhost:8000/, localhost:8000/main/, localhost:8000/main/whatever/, localhost:8000/whatever/, 或是 localhost:8000/whatever/whatever/,結果:

helloWorld
✶ 以上這幾個 URL 格式都符合 r'^main/'r'^.*', 因此匯入 main.urls 進一步對應
✶ 經過 blog.urls 對應之後,剩下的字串為空字串,在 main.urls 裡符合 r'^$' 格式,因此由 main.view.main() 函式處理
main.views.main() 函式回覆一個 HttpResponse 物件, 內含字串 Hello world!,因此在使用者網頁顯示該字串

即使在 main/views.py 模組中寫好 def main() 函式,在 main/urls.py 裡的 views.main 還是會顯示紅色底線,這是 Eclipse 的問題 (畢竟我們所處的不是一個完美的世界! ;-),將 urls.py 編輯頁籤關閉, 然後再打開應該就 OK 了

(4) 小結

∗ 上推專案到 Github

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

∗ 練習

▸ 建立另一個新專案 bookstore,讓該專案亦能在頁面顯示「Hello world!」

∗ 建立新虛擬環境,啟動虛擬環境並在虛擬環境中安裝套件
∗ 在 Eclipse 中設定 Python 解譯器 (Interpreter)
∗ 建立新資料庫、資料庫使用者
∗ 建立新專案、在 settings.py 中完成相關設定
∗ 進行資料庫遷移、確認 Django 可以正常運作
∗ 建立新的 app main,並在專案的 urls.py 裡建立 URL 對應
∗ 在 main app 的 urls.py 建立 URL 對應、撰寫 view 程式、 撰寫 template 程式,完成頁面顯示「Hello world!」的功能

上一章       下一章