about 4 years ago

  • 使用模版的理由
  • 創建與填寫模版
    • 模版成分表
    • 將模版分離
    • 建立模版目錄與使用模版自動載入
    • 使用locals函數

還記得上一篇那個醜到不行的html寫法嗎,本篇就要來拯救世界了。

使用模版的理由

大家會想學Django都是為了寫出動態的網站,動態的意思有兩點:

1. web內容不是一成不變的,會根據時間和狀態而不同,這代表的是html中含有變量
2. web必須要能跟使用者互動,最主要依據的就是表單,這部份我們留到後面的筆記再談

要如何處理含有變量的html呢,一個方法就是使用上篇的方法,重頭寫出一個html並且在適當的地方插入變量形成的字串,但這個方法似乎很笨,每一次要產生一個回應頁面時都必須重新寫過,這還不打緊,這些html code跟view function其他用來處理商業邏輯的code根本混在一起了,既難看,又容易造成維護或更動的困難(記得嗎!我們追尋的是鬆耦合阿!)

模版(或稱樣板)就是一個很好的解答了,關於使用模版的理由,Django Book列出了以下幾點:

  1. 對頁面設計進行的任何改變都必須對Python代碼進行相應的修改。站點設計的修改往往比底層Python代碼的修改要頻繁得多,因此如果可以在不進行Python代碼修改的情況下變更設計,那將會方便得多。

  2. Python代碼編寫和HTML設計是兩項不同的工作,大多數專業的網站開發環境都將他們分配給不同的人員(甚至不同部門)來完成。設計者和HTML/CSS的編碼人員不應該被要求去編輯Python的代碼來完成他們的工作。

  3. 程序員編寫Python代碼和設計人員製作模板兩項工作同時進行的效率是最高的,遠勝於讓一個人等待另一個人完成對某個既包含Python又包含HTML的文件的編輯工作。

其實簡單來說,就是想要將html和python code分開撰寫,不但不會混亂還能同時進行,也能交給分別專精的設計師。更重要的是,改一邊可以不用動到另一邊。

創建與填寫模版

使用模版一共只有兩個步驟:

1. 創建模版
2. 填寫模版

一個模版主要由下表所列的元素構成:

模版成分表

名稱 描述 特徵 範例
變量 內容填到模版的位置 使用成對的兩個大括號括著的文字 {{ sum }}
標籤 提供視圖邏輯 使用成對的大括號加百分比括著的文本 {% if real %}
注釋 注釋 使用成對的大括號加井字號括著的文本 {# this is comment #}
文字 就是純文字,字面文字 不屬於上述成分的字面文本,包含html標籤 just text

首先我們來嘗試一些簡單的基本操作,利用Django的python shell來進行練習

我們選擇Django自帶的shell來練習而不是使用原本的python shell,原因是Django的shell會設置好所有跟Django相關的環境,比較不會出現問題

$ python manage.py shell

接著,我們試試看基本的模版建立與填寫

>>> from django import template
>>> t = template.Template('I love {{ name }}.')
>>> c = template.Context({'name':'Mary'})
>>> print t.render(c)
I love Mary.

這邊我們使用了name這個變量,這個地方就好像版上可以更換填空的點,記得name必須被{{}}給括住才會被當成變量。接著我們利用一個類似於字典的Context物件來填寫他,字典的鍵(key)會對應到相同名稱的變量,而值會成為該變量的值,簡單來說就是在模版中看到{{ name }}變量就替喚為字串'Mary'。

Template物件中的render方法執行的就是填寫的動作,會將Context的鍵找到對應的變量位置並且填入該鍵對應的值。

我知道雖然才過了那麼一會兒,但是大家一定很想問,模版要怎麼樣來解決上一篇提到的網頁計算機的問題呢?
我們馬上來看範例碼:

mysite/mysite/views.py
from django.http import HttpResponse
from django import template

def math(request, a, b):
    a = int(a)
    b = int(b)
    s = a + b
    d = a - b
    p = a * b
    q = a / b
    t = template.Template('<html>sum={{s}}<br>dif={{d}}<br>pro={{p}}<br>quo={{q}}</html>')
    c = template.Context({'s':s, 'd':d, 'p':p, 'q':q})
    return HttpResponse(t.render(c))

我知道你已經快發飆了,這看起來並沒有比較好,好像還麻煩多了!請看倌先別著急,我們還沒走到最後一步呢。讓我們一步一步來吧!

將模版分離

首先我們先來解決剛剛提到的要將view logic和business logic分離的部分。我們在上層mysite中新增一個資料夾templates專門放置模版。接著在templates目錄下新增一個檔案math.html,然後我們將剛剛的模版內容移到math.html中。現在的目錄結構和math.html會長這樣子:

mysite-|--manage.py
       |--templates--math.html
       |--mysite----|--__init__.py
                    |--settings.py
                    |--urls.py
                    |--wsgi.py
mysite/templates/math.html
<html>
    sum={{s}}<br>
    dif={{d}}<br>
    pro={{p}}<br>
    quo={{q}}
</html>

這樣子我們便輕鬆地將不同的邏輯分開了,而且我們也會發現模版的編輯和排版也更容易了。但是我們要如何處理原先的視圖函式呢?我們可能會有一個簡單的想法,讀檔把內容讀進來就好啦!

mysite/mysite/views.py
from django.http import HttpResponse
from django import template

def math(request, a, b):
    a = int(a)
    b = int(b)
    s = a + b
    d = a - b
    p = a * b
    q = a / b
    with open('templates/math.html','r') as reader:
        t = template.Template(reader.read())
    c = template.Context({'s':s, 'd':d, 'p':p, 'q':q})
    return HttpResponse(t.render(c))

因為我們的BASE_DIR設定的是上層mysite,所以開檔路徑這樣設置是沒問題的!

雖然分離是分離了,但是每次都得自行讀入也太麻煩,在模版丟失的情況下還會引發IOError,況且又臭又長的模版路徑很令人討厭,尤其模版是會被重複利用的,每一次都得重輸路徑真的不是個好主意,所以...我們接著看下去

建立模版目錄與使用模版自動載入

還記得我們在Django筆記(1)的時候有示範過的模版目錄設定嗎?忘記的話快打開settings.py跟著回憶一下吧。

mysite/mysite/settings.py
TEMPLATE_DIRS = (
    os.path.join(BASE_DIR,  'templates'),
)

上述設定便將我們剛剛創建的templates目錄設為模版的預設目錄了,這表示Django將能夠自動找到在該目錄下的所有模版。這還不夠,我們還希望模版可以自行載入,讓我們修改views.py中的math function

mysite/mysite/views.py
from django.http import HttpResponse
from django.template.loader import get_template
from django import template

def math(request, a, b):
    a = int(a)
    b = int(b)
    s = a + b
    d = a - b
    p = a * b
    q = a / b
    t = get_template('math.html')
    c = template.Context({'s':s, 'd':d, 'p':p, 'q':q})
    return HttpResponse(t.render(c))

get_template函數將會讀取一個模版檔並且返回一個模版物件,很好,我們解決了不少問題,但身為懶人的我們還需要在更進一步簡化他,我們將取得模版,填寫模版跟Http回應融合在一起吧!

取得模版(get_template)+填寫模版(Context+render)+Http回應(HttpResponse) = render_to_response

如此四合一的選擇,不用嗎!!我們的views.py要做出如下修改

mysite/mysite/views.py
from django.shortcuts import render_to_response

def math(request, a, b):
    a = int(a)
    b = int(b)
    s = a + b
    d = a - b
    p = a * b
    q = a / b
    return render_to_response('math.html',{'s':s, 'd':d, 'p':p, 'q':q})

render_to_response需要兩個參數,分別是一個模版和一個要填入模版的字典,他將整合所有動作使得一步完成。

使用locals函數

太好了,一切都完美了,但這邊還要教大家一個小技巧,那就是函數locals。在python中,locals這個內建函數將會返回一個字典,以區域變數的名稱為鍵,以區域變數的值(指的是__unicode__或是__str__所回傳的值,若讀者不太清楚,也可以先略過本句,以直覺去猜測)為值。所以說我們不用自己手動輸入那個可能會長到誇張的字典,只要這樣做:

return render_to_response('math.html',locals())

不過要記住,所有要填入模版的變量一定得要以區域變數的形式出現在呼叫locals函數之前!

為了避免本篇過長,我們將變量的深入跟標籤的使用放到下一篇去說明,請徹底消化後再前進吧。

← Django筆記(2) - 視圖與URL Django筆記(4) - 模版的變量與標籤 →
 
comments powered by Disqus