這周都在複習 Django, 我把心得整理在下面的筆記裡 :
今年中秋連假不烤肉, 窩在家繼續複習 Django 整理模板用法.
在上一篇測試中均使用 django.http.HttpResponse() 函式直接將 HTML 碼回應給用戶端, 但這不僅麻煩, 且不利於前後端分工. Django 內建的模板引擎可解決此問題, 前端設計師負責網頁模板設計, 後端工程師則可利用 django.shortcut.render() 函式將變數傳遞給指定的模板網頁顯示, 架構如下 :
網頁模板需要放在手動建立的特定資料夾下 (通常取名為 templates), 其位置有二 :
- 在上層專案目錄下 (專案模板) :
整個網站與旗下的 App 均可使用, 適用於單一 App 網站 (App 可移植性低). - 在 App 目錄下 (App 模板) :
每一個 App 都可以有自己的模板資料夾 (App 可移植性高).
當然也可以兩者均有, 專案 templates 用來存放網站首頁相關的模板; 而 App 的 templates 則用來存放該 App 相關的網頁模板. 在前一篇的測試最後, 得到一個可移植性佳的單一 App 網站, 其架構如下圖所示 :
mysite (上層專案目錄)
|____ manage.py (管理程式)
|____ mysite (下層專案目錄)
| |____ __init__.py (形成套件)
| |____ settings.py (專案設定檔)
| |____ urls.py (專案路由模組, 自動建立)
| |____ views.py (專案視圖模組, 手工添加)
| |____ wsgi.py (伺服器佈署設定檔)
| |____ asgi.py (伺服器佈署設定檔, 非同步)
|____ myapp1 (應用程式目錄)
|____ migrations (資料庫同步)
|____ __init__.py (形成套件)
|____ admin.py (註冊資料模型)
|____ apps.py (App 設定檔)
|____ models.py (資料模型定義)
|____ tests.py (測試用程式)
|____ views.py (App 視圖模組, 自動建立)
|____ urls.py (App 路由模組, 手工添加)
可見與網站首頁相關的回應由專案的控制器 (mysite 下的 urls.py 與 views.y) 負責, 而與 App 相關的回應則由 App 的控制器 (myapp1 下的 urls.py 與 views.y) 負責. 現在於上層 mysite 與 myapp1 下各自建立一個 templates 資料夾, 架構如下 :
mysite (上層專案目錄)
|____ manage.py (管理程式)
|____ mysite (下層專案目錄)
| |____ __init__.py (形成套件)
| |____ settings.py (專案設定檔)
| |____ urls.py (專案路由模組, 自動建立)
| |____ views.py (專案視圖模組, 手工添加)
| |____ wsgi.py (伺服器佈署設定檔)
| |____ asgi.py (伺服器佈署設定檔, 非同步)
|____ templates (專案的模板資料夾)
|____ myapp1 (應用程式目錄)
|____ migrations (資料庫同步)
|____ __init__.py (形成套件)
|____ admin.py (註冊資料模型)
|____ apps.py (App 設定檔)
|____ models.py (資料模型定義)
|____ tests.py (測試用程式)
|____ views.py (App 視圖模組, 自動建立)
|____ urls.py (App 路由模組, 手工添加)
|____ templates (App 的模板資料夾)
注意, 專案的網頁模板資料夾 templates 是放在上層專案目錄下, 與下層專案目錄, App 等位於同意層; 而 App 的 templates 則放在 App 目錄下.
一. App 目錄下的模板與控制器設定 :
此處使用模板網頁來改寫前一篇 App=myapp1 的兩個請求 (根目錄 myapp1/ 與打招呼 myapp1/helloworld), 如前所述, 為了能動態地傳遞變數, 將打招呼的請求 URL 改為 myapp1/hello.
首先在 myapp1/templates 下建立兩個網頁模板 myapp1_home.htm 與 hello.htm 來改寫上一篇測試中 myapp1/ 與 myapp1/hello 的請求處理. myapp1_home.htm 是 myapp1 的首頁, 內容如下 :
<!-- myapp1_home.htm -->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<meta charset="utf-8">
</head>
<body>
<h2>這是 App1 首頁!</h2>
</body>
</html>
hello.htm 是可傳入變數, 顯示動態資訊的網頁模板, 內容如下 :
<!-- hello.htm -->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<meta charset="utf-8">
</head>
<body>
<h2>Hello, {{name}}, 現在的時間是 {{now}}</h2>
</body>
</html>
此模板網頁中以雙重大括號括起來的地方是模板引擎讓視圖模組 views.py 傳出的變數嵌入之處, 模板網頁中可以嵌入變數, 標籤, 以及註解 :
模板語法元素 | 說明 |
{{ 變數 & 過濾器 }} | 來自 views.py 的變數, 用來直接替換該位置內容或過濾 |
{% 標籤 %} | 標籤用來控制資料顯示邏輯 (迴圈與判斷) |
{# 註解 #} | 註解會被模板引擎忽略 |
但其實真正有作用的模板語法只有 {{}} 與 {%%} 這兩個而已, 其中 {%%} 最重要, 可使用 Python 的 if elif else 語法進行分支判斷, 也可以使用與 Python for 迴圈幾乎一樣的語法來進行迭代.
分支判斷的模板語法如下 :
單一分支 | 雙重分支 | 多重分支 |
{% if 條件式 %} 輸出網頁 (% endif %} | {% if 條件式 %} 輸出網頁 1 {% else %} 輸出網頁 2 (% endif %} | {% if 條件式 %} 輸出網頁 1 {% elif %} 輸出網頁 2 {% elif %} 輸出網頁 3 {% else %} 輸出網頁 4 (% endif %} |
for 迴圈的模板語法如下 :
模板 for 迴圈 | 說明 |
{% for 變數 in 可迭代變數 %} 內含 {{變數}} 的網頁 {% endfor %} | 用 for in 迭代內含 {{變數}} 的網頁 |
{% for 變數 in 可迭代變數 reversed%} 內含 {{變數}} 的網頁 {% endfor %} | 以倒序方式迭代內含 {{變數}} 的網頁 |
{% for 變數 in 可迭代變數%} 內含 {{變數}} 的網頁 1 {% empty %} 迴圈為空時輸出的網頁 2 {% endfor %} | 可迭代變數不為空時輸出網頁 1, 為空時輸出網頁 2 注意, empty 必須放在 endfor 前面. |
除此之外, 模板語法還提供迴圈變數 (物件) forloop, 其屬性可用在 for 迴圈中讓 if elif else 分支判斷語法決定是否要輸出特定網頁內容 :
迴圈變數 forloop 的屬性 | 說明 |
forloop.counter | 迴圈計數器 (1 起始) |
forloop.counter0 | 迴圈計數器 (0 起始) |
forloop.revcounter | 倒數之迴圈計數器 (由總圈數遞減至 1) |
forloop.revcounter0 | 倒數之迴圈計數器 (由總圈數遞減至 0) |
forloop.first | 是否為第一個迴圈 (True/False) |
forloop.last | 是否為最後一個迴圈 (True/False) |
forloop.parentloop | 上一層迴圈的 forloop 變數 |
詳細用法參考 :
其次編輯 myapp1 的視圖模組 views.py, 注意, 與前一篇測試不同之處是, 因為要透過在 URL 中傳遞變數來動態顯示打招呼的人名, 故 URL 函式名稱由 helloworld 改為 hello :
# views.py of App=myapp1
from django.shortcuts import render
from datetime import datetime
def hello(request, name='匿名'): # URL='myapp1/hello/' 的處理函式
now=datetime.now()
return render(request, 'hello.htm', {'name': name, 'now': now})
def myapp1_home(request): # App 根目錄 URL= 'myapp1/' 的處理函式
return render(request, 'myapp1_home.htm')
此處須匯入 django.shortcuts.render() 來輸出回應, 此函式可透過模板引擎對模板網頁傳遞變數, 其語法如下 :
render(request, '模板網頁檔名', 變數字典)
其中第一個參數為 http.HttpRequest 物件實例, 代表一個 URL 請求, 第二個參數為模板網頁檔名, 例如上面建立的 'myapp1_home.htm' 或 'hello.htm', 第三個參數是要傳給模板網頁的變數字典, 如果要一一列舉太麻煩, 也可呼叫 Python 內建函式 locals(), 此函式會將 views.py 裡面用到的變數組成字典傳回, 所以上面的 views.py 也可以改寫為如下較簡短的程式碼 :
# views.py of App=myapp1
from django.shortcuts import render
from datetime import datetime
def hello(request, name='匿名'): # URL='myapp1/hello/<name>' 的處理函式 (name 有預設值)
now=datetime.now() # 傳回現在日期時間
return render(request, 'hello.htm', locals())
def myapp1_home(request): # App 根目錄 URL= 'myapp1/' 的處理函式
return render(request, 'myapp1_home.htm')
注意 這裡 hello() 需列舉 URL 會攜帶的所有參數, 目前只有 1 個 : name, 因為客戶端也可能不會傳參數, 故 name 一個預設值 '匿名', 它會跟 now 變數一起被 locals() 做成變數字典傳給 render().
接著改寫 myapp1 的路由模組 urls.py (App 的 uls.py 需自建, 可從下層專案模組目錄 mysite 底下複製專案的 urls.py 來改) :
# urls.py of App=myapp1
from django.urls import path
from . import views # 匯入 App 的視圖模組
urlpatterns = [
path('hello/<str:name>/', views.hello), # 有參數
path('hello/', views.hello), # 無參數
path('', views.myapp1_home), # myapp1 的根目錄請求
]
此處主要是從 App 目錄下匯入 myapp1 自己的視圖模組 views.py, 然後分別將 'myapp1/hello' 與 'myapp1/' 的路由請求分別委派給 views.py 裡的 hello() 與 myapp1_home() 函式處理. 注意, 這裡 hellp 有兩個 path, 一個是有帶參數 name 的, 一個則無.
注意, App 路由模組中的 URL 都是相對於 'myapp1/', 故 'hello/' 在客戶端要用 'myapp1/hello/' 請求; 而 App 跟目錄 '' (空字串) 在客戶端要用 'myapp1/' 請求.
以上就完成 App 的控制器設定了.
二. 專案目錄下的模板與控制器設定 :
專案目錄 (注意是上層) templates 下的網頁模板主要是用來輸出網站首頁 (避免與 App 綁在一起以提升 App 可移植性), 與前一篇只簡單地顯示 ''歡迎來到我的首頁!' 不同的是, 此處要跟上面 myapp1 的 hello 一樣傳遞變數 (此處為傳遞目前的時間資訊) 給模板網頁, 首先在上層專案目錄的 templates 資料夾下建立一個網頁模板 home.htm :
<!-- home.htm -->
<!DOCTYPE html>
<html>
<head>
<title>首頁</title>
<meta charset="utf-8">
</head>
<body>
<h2>歡迎來到我的首頁! 現在的時間是 {{now}}</h2>
</body>
</html>
此首頁除了顯示打招呼用語外, 還會顯示從專案的視圖模組 views.py 傳遞過來的 now 變數.
接著編輯專案的視圖模組 views.py, 由於建立專案時不會在下層專案目錄中自動建立 views.py, 須自建或從 App 目錄下複製 myapp1 的 views.py 來修改 :
# views.py of project=mysite
from django.shortcuts import render
from datetime import datetime
def home(request):
now=datetime.now() # 傳回現在日期時間
return render(request, 'home.htm', locals())
此處僅定義一個 home() 函式來處理網站首頁 (根目錄) 的請求, 將變數傳給模板網頁回應給客戶端. locals() 會傳回此函式內的區域變數為一個字典 (即 {'now': now}) 傳遞給模板網頁 home.htm 顯示給客戶端.
接著編輯專案路由模組 urls.py (這模組會在建立專案時自動產生, 不須自建), 內容與前一篇的 urls.py 一樣不用修改 :
# urls.py of project=mysite
from django.contrib import admin
from django.urls import path, include # include() 用來含括各 App 的 urls.py
from . import views # 專案的視圖模組
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home), # 將網站首頁請求委派給專案的視圖模組
# 將 URL='myapp1/' 委派給 myapp1 的 urls.py
path('myapp1/', include('myapp1.urls')),
]
這樣就完成了專案控制器的設定.
三. 專案模板資料夾位置設定 :
最後必須開啟專案設定檔 settings.py, 設定專案模板的位置, 這樣才能正確取得專案模板網頁路徑並順利輸出網站首頁.
開啟 settings.py 後搜尋 TEMPLATES, 裡面 DIR 鍵的值預設為空串列 :
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
此 DIR 就是用來設定專案模板位置的, 請在空串列中填入 BASE_DIR/'templates' :
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR/'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
其中 BASE_DIR 就是上層專案目錄路徑, 在 settings.py 中搜尋 BASE_DIR 即可找到其值如下 :
BASE_DIR = Path(__file__).resolve().parent.parent
__file__ 表示 settings.py 本身, 經呼叫 resolve() 解析其絕對位置後, 因 settings.py 位於下層專案目錄 mysite 下, 故 .parent 為下層專案目錄之路徑, 再一次 .parnt 即取得上層專案目錄路徑, 而我們的專案模板資料夾 templates 即位於上層專案目錄 mysite 底下, 串接後即得專案模板資料夾 templates 路徑. 注意, 這裡必須使用字串 'templates' 而非變數 template.
至於 App 的模板位置不需特別設定, 因為 'DIR' 鍵底下的 'APP_DIR' 預設為 True, 即 Django 會自動到各 App 資料夾下找尋該 App 的 templates 資料夾.
至此完成所有網站與 App 設定, 用下列指令啟動開發伺服器 :
python manage.py runserver
然後用瀏覽器拜訪上面專案與 App 的 urls.py 所定義之 URL :
http://127.0.0.1:8000 (網站根目錄: 首頁)
http://127.0.0.1:8000/myapp1 (App 根目錄)
http://127.0.0.1:8000/myapp1/hello (App 的 hello: 無參數)
http://127.0.0.1:8000/myapp1/hello/Tony (App 的 hello: 有參數)
結果如下 :
範例檔可從 GitHub 下載 :
# https://github.com/tony1966/tony1966.github.io/blob/master/test/django/django-review-templates.zip
以上的測試總結如下 :
- 專案與 App 都可以有各自的 templates 網頁模板資料夾, 讓 App 與專案的耦合度降低以提升App 的可移植性, 在開發大型專案時能達成較高的元件可重用性.
- 專案的 templates 模板資料夾建立後必須開啟專案設定檔 settings.py, 將 TEMPLATES 變數的 DIR 串列設為 [BASE_DIR/'templates'], 這樣 Django 的模板引擎才找得到專案的模板資料夾路徑. App 的模板資料夾位置不需特別設定, 因為 TEMPLATES 變數的 APP_DIR 屬性預設為 True, 模板引擎會自動到各 App 目錄下尋找 templates 目錄.
- 若不考慮 App 的移植性, 也可以只用專案的網頁模板資料夾, 不設 App 的 templates, 亦即全部 App 都使用專案模板資料夾.
四. 模板網頁的匯入與繼承 :
為了模板網頁能達成模組化與結構化要求, 模板引擎還提供了模板網頁匯入 (include 指令) 與繼承 (extend 指令) 的語法將其他的模板網頁或片段引入到目前的模板網頁中, 兩者差別如下 :
- 被 include 的模板網頁通常是被切割後的網頁片段而非完整的網頁, 但被繼承的模板網頁一定是完整的網頁.
- 繼承指令 {% extend %} 必須放在模板網頁最前面; 而匯入指令 {% include %} 則可以在模板網頁的任何地方.
使用模板引擎的 {% include %} 指令可以在模板網頁中匯入其他網頁檔案, 語法如下 :
{% include "其他模板網頁.htm" %}
注意, 這裡 "其他模板網頁.htm" 檔名必須用引號括起來 (單雙均可), 例如下列模板網頁 :
<!--index.htm-->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<meta charset="utf-8">
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
可將其中 body 的內容單獨寫成一個 helloworld.htm 檔 :
<!--helloworld.htm-->
<h1>Hello World</h1>
然後修改模板 index.htm, 在其中用 include 匯入 helloworld.htm :
<!--index.htm-->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<meta charset="utf-8">
</head>
<body>
{% include "helloworld.htm" %}
</body>
</html>
注意, 被匯入的 hellowrld.htm 不是完整的 html 格式, 而只是一個網頁片段. 但這種將網頁片段作為一個 htm 檔的作法有點怪, 模板網頁模組化主要還是靠繼承 (extend).
模板網頁的繼承與類別的繼承概念類似, 被繼承的模板稱為父模板, 繼承者稱為子模板. 在父模板中會用下列語法定義若干讓子模板嵌入網頁片段的區塊, 並為這些區塊命名 :
{% block 區塊名稱 %}{% endblock %}
子模板則必須在檔案一開頭便使用下列語法繼承父模板 :
{% extends '父模板.htm' %}
然後用下列語法在所繼承之父模板中的指定區塊嵌入網頁片段 :
{% block 區塊名稱 %}
要嵌入之網頁片段
{% endblock %}
例如我們可以先建立一個基礎網頁模板 base.htm 當作所有網頁模板的父模板 :
<!--base.htm-->
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% endblock %}</title>
{% block link %}{% endblock %}
{% block script %}{% endblock %}
<style>
{% block style %}{% endblock %}
</style>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
上面的黃色部分就是讓繼承 base.htm 的子模板網頁用 block 指令於該處嵌入樣式, 程式檔, 或網頁片段的地方, 這樣子模板網頁就不需要重複寫 HTML 相同的部分, 結構就變得很簡單 :
{% extends "base.htm" %}
{% block title %}網頁標題{% endblock %}
{% block link %}
link 樣式檔
{% endblock %}
{% block script %}
script 程式檔
{% endblock %}
{% block body %}
網頁內容 + script 程式檔
{% endblock %}
注意, extends 指令一定要放在模板網頁最前面 (忽略註解). 其次, Javascript 程式檔在網頁中的位置可以在 head 內, 也可以在 body 內, 在 body 中匯入時不另外做一個嵌入區塊, 而是與網頁內容合在一起嵌入.
例如上面的 index.htm 就可以寫成 :
<!--index.htm-->
{% extends "base.htm" %}
{% block title %}Hello{% endblock %}
{% block body %}
<h1>Hello World</h1>
{% endblock %}
注意, base.htm 裡面的 link 與 script 區塊若沒用到就不用嵌入任何資料.
這樣就可以用模板繼承方式來改寫上面的 mysite 網站了, 首先在上層專案目錄的模板資料夾 templates 底下新增基底網頁模板 base.htm, 然後修改網站的首頁檔 home.htm 為如下 :
<!-- home.htm -->
{% extends "base.htm" %}
{% block title %}首頁{% endblock %}
{% block body %}
<h4>歡迎來到我的首頁! 現在的時間是 {{now}}</h4>
{% endblock %}
然後切換到應用程式 myapp1 下的 templates 資料夾下, 將原本的兩個模板網頁改成繼承自專案基底模板 base.htm, 下面是修改後的 hello.htm 模板 :
<!-- hello.htm -->
{% extends "base.htm" %}
{% block title %}Hello{% endblock %}
{% block body %}
<h4>Hello, {{name}}, 現在的時間是 {{now}}</h4>
{% endblock %}
下面是修改後的 myapp1_home.htm 模板 :
<!-- myapp1_home.htm -->
{% extends "base.htm" %}
{% block title %}myapp1 首頁{% endblock %}
{% block body %}
<h4>這是 App1 首頁!</h4>
{% endblock %}
結果與上面未使用模板繼承的網站是一樣的. 以上修改後的範例下載網址 :
五. 利用模板繼承使用網頁框架 :
利用上面的模板繼承功能可以讓網站在使用框架時更方便, 此處以 Bootstrap 4 為例, 使用此框架必須匯入 Bootstrap 的程式與 CSS 樣式表, 以及 jQuery 框架, 因為 Bootstrap 的互動功能是依賴 jQuery 達成的 :
<link rel="stylesheet" href="https://unpkg.com/bootstrap@4.0.0/dist/css/bootstrap.min.css">
<script src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script>
<script src="https://unpkg.com/bootstrap@4.0.0/dist/js/bootstrap.min.js"></script>
關於 Bootstrap 用法參考 :
同樣地, 模板網頁可以繼承專案 templates 的父模板, 也可以繼承應用程式本身 templates 下的父模板, 首先在專案 templates 下建立一個繼承 base.htm 的 bootstrap.htm 模板 :
<!--bootstrap.htm-->
{% extends "base.htm" %}
{% block link %}
<link rel="stylesheet" href="https://unpkg.com/bootstrap@4.0.0/dist/css/bootstrap.min.css">
{% endblock %}
{% block script %}
<script src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script>
<script src="https://unpkg.com/bootstrap@4.0.0/dist/js/bootstrap.min.js"></script>
{% endblock %}
此 Bootstrap 的框架模板在繼承 base.htm 時僅在 head 中嵌入 link 與 script 這兩個區塊, 而 title 與 body 區塊則未嵌入, 而是讓繼承 bootstrap.htm 的子模板來嵌入. 然後修改網站首頁 home.htm, 讓它從直接繼承 base.htm 改為繼承 bootstrap.htm, 並且使用 Bootstrap 的 alert-info 樣式來顯示首頁內容 :
<!-- home.htm -->
{% extends "bootstrap.htm" %}
{% block title %}首頁{% endblock %}
{% block body %}
<div class="container">
<div class="alert alert-info" role="alert">
歡迎來到我的首頁! 現在的時間是 {{now}}
</div>
</div>
{% endblock %}
然後修改應用程式 templates 下的 hello.htm 與 myapp1_home.htm, 同樣也是繼承專案 templates 下的 bootstrap.htm :
<!-- hello.htm -->
{% extends "bootstrap.htm" %}
{% block title %}Hello{% endblock %}
{% block body %}
<div class="container">
<div class="alert alert-warning" role="alert">
Hello, {{name}}, 現在的時間是 {{now}}
</div>
</div>
{% endblock %}
<!-- myapp1_home.htm -->
{% extends "bootstrap.htm" %}
{% block title %}myapp1 首頁{% endblock %}
{% block body %}
<div class="container">
<div class="alert alert-danger" role="alert">
這是 App1 首頁!
</div>
</div>
{% endblock %}
結果如下 :
# https://github.com/tony1966/tony1966.github.io/blob/master/test/django/django-review-bootstrap1.zip
Bootstrap 框架的模板不一定要放在專案的 templates 下, 也可以放在應用程式的 templates 資料夾下, 專門給該 App 的其他子模板網頁繼承之用, 這樣可以提高 App 的可移植性, 首先在 myapp1/templates 下建立應用程式的 Bootstrap 模板 :
<!--myapp1_bootstrap.htm-->
{% extends "base.htm" %}
{% block link %}
<link rel="stylesheet" href="https://unpkg.com/bootstrap@4.0.0/dist/css/bootstrap.min.css">
{% endblock %}
{% block script %}
<script src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script>
<script src="https://unpkg.com/bootstrap@4.0.0/dist/js/bootstrap.min.js"></script>
{% endblock %}
然後修改 myapp1 的兩個子模板, 將其父模板從專案的 bootstrap.htm 改成應用程式自己的 Bootstrap 模板 myapp1_bootstrap.htm :
<!-- myapp1_home.htm -->
{% extends "myapp1_bootstrap.htm" %}
{% block title %}myapp1 首頁{% endblock %}
{% block body %}
<div class="container">
<div class="alert alert-success" role="alert">
這是 App1 首頁!
</div>
</div>
{% endblock %}
此處除了父模板改成 myapp1_bootstrap.htm 外, 還將 alert 樣式改成 alert-success, 以與前一個範例作區別. 結果如下 :
此例只動了 myapp1 的模板網頁, 網站首頁沒變, 仍然是 alert-info, 但 myapp1 的模板網頁都改成 alert-success, 可見這兩個網頁確實是繼承 myapp1_bootstrap.htm, 此範例下載網址 :
# https://github.com/tony1966/tony1966.github.io/blob/master/test/django/django-review-bootstrap2.zip
上面範例雖然演示了 Bootstrap 框架父模板網頁既可以放在專案的 templates 目錄中供專案本身與所有 App 繼承使用; 也可以放在各 App 的 templates 目錄下供自己使用, 但一般來說網站會有統一的風格樣式, 故實務上會放在專案 templates 底下.