01 6月 2011

[文件] Django 框架大冒險之二:狐狸的尾巴

始學架網站的時候,我一度很困惑。困惑的是,一旦網站上線了,那麼網站首頁的 http://www.myTestSite.com.tw/index.html 這個網址不就明明白白地告訴所有瀏覽的訪客我家裡有個叫 index.html 的檔案嗎?也就是說,只要對方想個辦法把這個 index.html 檔案的內容換掉,那我的首頁也就被換掉了。

再來學著玩 php 的網頁程式的時候,困惑的感覺更深了。像這種網址:http://www.myTestSite.com.tw/value?v="myQuestion"&k=20 紅色的段落裡,不就明白地告訴我的訪客,我的伺服器程式可以處理一個叫 v 的字串 (myQuestion) 和一個叫 k 的數值 (20) ?那也就是說,只要我的演算法不是太複雜的,那麼訪客就可以「猜」得出來我在算什麼東西囉?只要他猜出來了,再依照程式函數名稱換來換去就是那幾個生字的 「慣用法」,那豈不是隨隨便便就給人看光光了…

在認識 Django 以前,我自己想出來的處理方法是利用使用者輸入的資料搭配資料庫,然後用亂數命名法,隨機生成一個 ooxx.html ,再把使用者的瀏覽器跳轉到這個剛剛生成的網頁上。一旦使用者離開這個網頁,伺服器就馬上把這個網頁的 html 檔刪除。如此一來,就算利用網址的目錄結構被人摸清了我家的平面圖,你也不知道我家裡的東西是怎麼擺的。但不可避免的是,這樣的網址出來都很醜怪。明明是 學術單位的網站,但那個網址動不動就一堆 ooxx 的,搞得像是色情網站的網址似的。更慘的是,除了首頁外,其它頁面都無法被「加入書籤」(或是 IE 上的「我的最愛」),因為實際上這些網頁「都不存在」。只有在訪客要看的時候,才由伺服器生一頁出來傳給訪客。

認識了 Django 以後,發現 Django 提供了更優雅的方法…

假設我要做一個叫 CoffeeShop 的網站好了。那麼安裝好 Django 以後,只要利用 Django 提供的指令,就能馬上產生一個網站專案 (project) 的目錄:
django-admin startproject CoffeeShop
打開這個 CoffeeShop 的目錄 (或是 Windows 使用者習慣的「資料夾」) 就能看到以下的結構:

上一章提過的,__init__.py 這個檔是說明 CoffeeShop 這個目錄可以被 Python 當做 package 使用而已。其實它的內容是空的。而 manage.py 這個檔案,則是啟動各種 Django 內建的指令用的,所以也不需要更動它。

比較特別的是 settings.py 和 urls.py 這兩個檔案。

用習慣的編輯器打開 settings.py 看看。(我習慣用 madedit ) 上半部主要是和資料庫之間的設定,這部份在這一篇先略過不表,倒是下半部的內容相當有意思:
這裡的 TEMPLATE_DIRS 指的就是 Django 本身在運作的時候所有會用到的網頁的位置。只要這裡沒有設定的,即使檔案放在同一個目錄下, Django 也會直接裝作沒看到。而 INSTALLED_APPS 這裡則是設定網頁程式用的。這部份待以後的篇章裡再說明。

延續 CoffeeShop 這個網站的想法,我在這裡加上一個叫 menu 的目錄,裡面放滿各種咖啡的介紹網頁好了。加上以後,應該看起來像下面這樣子:

注意到上圖中黃色的部份是我新增的目錄設定,而且每個目錄設定後面一定要加上一個逗號做為結束。待會兒我就要把要拿來顯示的 html 檔放在該目錄下。

接著,我在 CoffeeShop 這個目錄下,再新增一個叫 view.py 的檔案。所以現在 CoffeeShop 裡面有五個檔案,和一個叫 menu 的空目錄:
在 Django 裡,預設把叫做 view.py 的檔案視為處理 url.py 所傳來的呼叫和寫在伺服器上的程式或是 template (模板) 之間的一個轉譯站。 template 則可視為是一些 html ,也就是待會兒要放在 menu 裡的東西。

初學者可能開始覺得上一段很難理解,其實…就算看不懂也不要緊。總之,這幾個檔案之間的互動關係大致如下:

一切準備好後,我們來寫兩個簡單的 html 檔放到 menu 裡面。一個叫 espresso.html ,一個叫 latte.html 。兩個檔案裡都只有一句話。

espresso.html 內文:
latte.html 的內文:
接著要在 views.py 裡設定繪製這兩頁的方法,在 views.py 裡先引入 render_to_response ,然後再制訂兩個 function (函式) 以便待會兒可以回應 url.py 的呼叫:
到目前為止, url.py 還不認識這個 view.py 檔,所以我們再打開 urls.py,然後先在檔案最開始的地方加上一行介紹文:
from view import espresso, latte
然後再下面加上兩行,變成:
意思是…先用個字母 "r" 標在最前面,告訴 Python 這一段要用正規表示式來看。"^" 這個向上指的小飛標,意思是如果網頁的最後一段從前面往後讀,看看它長得像不像 espresso/;而後面的 "$" 則是說把網址的最後一段由後向前讀,看看它長得像不像 espresso/。如果以上兩個答案都是「好像!相似度 100% 啊!」 那就呼叫 view.py 裡的那個 espresso 函式來處理。

一旦呼叫了 view.py 裡的 espresso 這個函式,它就如內容所示地:
view.py 收到 url.py 的呼叫後,便先去讀取 'menu/espresso.html' 這個檔案,然後再將它繪製成網頁 (render_to_response) 後,傳到使用者的螢幕上。

整個兒流程,就是這樣。那麼接下來,就是試試看這些設定管不管用囉~

打開終端機 (或是 Windows 下的命令列) ,進到 CoffeeShop  的目錄裡,鍵入:
python manage.py runserver
Django 開始運作後,在終端機中會出現以下的東西:
Validating models...
0 errors found

Django version 1.0.2 final, using settings 'CoffeeShop.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

當然,因為 Django 裡的網頁伺服器只是在設計網站的時候自行測試用的,所以網址就是有名的 http://127.0.0.1 ,然後後面再加上通訊埠 ":8000/" 。

因為我自己很不喜歡記數字,所以就把那個 127.0.0.1 改成 "localhost" 鍵入到瀏覽器的網址列裡,看看網頁變成什麼模樣吧!
網址:http://localhost:8000/
哦!不~ 是 "404 找不到佩吉" !(404 是什麼?人力銀行嗎?還是總機小姐?)

怎麼會找不到佩吉呢?回想一下,原來是因為,我們剛才告訴 Django 如何去處理網址尾巴是 espresso/ 或是 latte/ 的時候,該怎麼辦,但我們從來沒告訴 Django 如果網址沒有尾巴的話,到底該怎麼辦啊!!

沒關係,那我們先幫網址裝上尾巴,測試看看這麼一大篇 blog 前半部講的鬼話有沒有一點道理。再次鍵入網址 http://localhost:8000/espresso/ 出現畫面如下:
噠啦~我的 Espresso 出現啦!

趕快再來試試看 latte 能不能用!再鍵入網址 http://localhost:8000/latte 看看:
喲嘿~我的 Latte 也來了!

那麼…到底要怎麼做,才能讓沒有尾巴的網址也能跑起來呢?

簡單~就再回到 menu 目錄裡去加個叫 waiter.html 的檔案,裡面寫個…寫個 "Bonjour madame, voulez vous acheter de la sauce de soja?" 好了(這句法文隨便寫的啊!)。然後再到 view.py 裡寫個
def home(request)
    html = "menu/waiter.html"
    return render_to_response(html)
最後再到urls.py 裡去加一項 (r"^$", home),  別忘了每次加東西到 urls.py 的 urlpatterns 裡時,最後要有個逗號。這項是說當網址的最後一段從前面讀過來空空的沒東西,從後面讀過去,也是空空的沒東西的時候,就叫 home  來處理。

而我們剛剛已經在 view.py 裡設定好了, home 這個函式會去讀 menu 裡的 waiter.html 來繪製成網頁…

再試試看 http://localhost:8000/ 吧!

最後要說明 Django 到底哪裡優雅了呢!

首先,網址上再也看不到 index.html 這種字眼了!也就是說,訪客根本就無法確定是不是真的有個檔案叫做 index.html 。更絕的是,就算在網址上出現了 /espresso/ 或是 /latte/ 這樣的目錄結構,但實際上這兩個網頁都是放在一個叫 /menu 的目錄下的。在網址上也根本看不出來有 /menu 這個目錄的存在!

簡單地說,網址裡顯示的目錄結構和實際的目錄結構「脫勾」了, 網站的安全性就提高了!你看我家有個浴缸,但它可不一定放在浴室 (說不定擺在客廳),你看我端出一盤蛤蜊義大利麵,但這可不表示我家裡一定有廚房 (其實我是從後門叫外賣的)!

Django 這種無厘頭的風格,真是太太…太合我的胃口了!(可惜已經嫁做人婦了…:p)

ps. 那句法文的意思是「太太要不要買醬油?

{{未完,待續…}}

6 則留言:

  1. 總算有點概念了... 不知道什麼時候會有下一篇?

    回覆刪除
  2. Hi Indiana,

    謝謝你的留言。
    最晚在農曆年前會有下一篇。我正在努力搞清楚 static_elements 在開發時和實際上線時的差別。

    祝 安平
    Peter. w

    回覆刪除
  3. 作者已經移除這則留言。

    回覆刪除
  4. 謝謝!期待您的文章~
    昨晚還在看 Taipei-GTUG 釋出的影片...
    http://www.youtube.com/user/taipeigtug#p/a/u/1/HQRmBoDzy

    回覆刪除
  5. + 1 , 期待您的文章,很少能找到講解這麼清楚的文章,對新手而言真是久旱逢甘霖,非常感動
    ~~一個google&wiki了好幾天卻還不懂什麼是Django的新手~~

    回覆刪除
  6. 最近要用到Django逛到格主的文章,太有趣了,結果未完待續一直沒有續啊~~(哭哭)

    回覆刪除