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/introduction/
✶ 主網域:http://www.mysite.com/
✶ 將進行對應的字串:tutorial/django/introduction/

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

✶ 例如:如果 Project app 對應了 tutorial/django/, 那麼 Handling app 就會對應 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 組態檔中增加兩個 URL mapping:

blog/urls.py
...
from django.contrib import admin
from django.urls import path, include, re_path
from main import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('main/', include('main.urls', namespace='main')),
    re_path('.*', views.main),
]
from ... import ...:匯入 include, re_pathmain.views 模組
urlpatterns:Django 利用 Python 的串列 (List) 資料結構來儲存各個 URL 的對應
# 變數名稱必須是 urlpatterns
# 每個 URL 對應利用 path()re_path() 函式來設定
✶ URL mapping 項目
# path('admin/', ...):如果 URL 格式為 admin/...,則使用 admin.site.urls 模組進進一步比對 URL,此為 Django 內建管理者模組
# path('main/’, ...):如果 URL 格式為 main/..., 則匯入 main.urls 模組進一步比對 URL,並將此 URL 格式的名稱空間 (Namespace) 命名為 main,以供其他程式使用 (Namespace 的意義稍後解釋)
# re_path('.*', ...):使用常規表示式 (Regular expression, re) 的路徑格式,點號 (.) 表示任何字元,星號 (*) 表示其左方的字元可以出現 0 或多次, 因此 '.*' 可對應任何字串 (包括空字串)。此項目的機制是當所有的 URL 對應都失敗的話, 就由 main.views.main 函式處理,不要顯示「找不到網頁」之錯誤訊息,因此此項目應該放在最後一個

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

main/urls.py
from django.urls import path
from main import views


app_name = 'main'
urlpatterns = [
    path('', views.main, name='main'),
]
from ...:匯入所需模組
app_name = 'main':指明此 app 的名稱為 'main'
urlpatterns ...:利用串列來設定各個 URL 的對應
# 串列變數名稱必須是 urlpatterns
# 每個 URL 對應均利用 path() 函式來設定 (目前只有一個),並有三個參數:
- 第 1 個參數是 URL 格式:'' 表示空字串,亦即經過專案直屬 app 的 urls 比對之後,剩下空字串
- 第 2 個參數 views.main:此 URL 請求將由 main.views 模組裡的 main() 函式來處理
- 第 3 個參數 name='main':將此 URL 對應命名為 main,以供其他程式使用
✶ URL mapping:當使用者輸入了 main/ URL Request, main/ 字串符合 blog.urls 裡的 'main/' 格式,因此 Django 將剩餘字串 (空字串) 送到 main.urls 對應,空字串符合 '' 格式,因此由 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 名稱,亦可使用其他名稱)。request 的內容包括使用者提出 HTTP 請求的相關資訊, 例如使用者名稱、所使用的瀏覽器、作業系統、請求的時間、請求所使用的方法等
'''Show ...''':函式註解
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/main/, 結果:

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

▸ 如果在瀏覽器輸入 localhost:8000/, localhost:8000/whatever/, 或 localhost:8000/whatever/whatever/ 等等:

✶ 這些 URL 只能對應 '.*' 格式,因此直接呼叫 main.views.main() 函式處理, 其結果同上

即使在 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 程式, 完成頁面顯示「Hello world!」的功能

上一章       下一章