Django中的 動態URL配置

舉個例子,一家在線書店會爲每一本書提供一個URL,如:/books/243/、/books/81196/。html

讓咱們建立第三個視圖來顯示當前時間和加上時間誤差量的時間,設計是這樣的:  /time/plus/1/ 顯示當前時間+1個小時的頁面 /time/plus/2/ 顯示當前時間+2個小時的頁面 /time/plus/3/ 顯示當前時間+3個小時的頁面,以此類推。
 
新手可能會考慮寫不一樣的視圖函數來處理每一個時間誤差量,URL配置看起來就象這樣:
 
urlpatterns = patterns('',
    ('^time/$', current_datetime),
    ('^time/plus/1/$', one_hour_ahead),
    ('^time/plus/2/$', two_hours_ahead),
    ('^time/plus/3/$', three_hours_ahead),
    ('^time/plus/4/$', four_hours_ahead),
)

   很明顯,這樣處理是不太穩當的。 不但有不少冗餘的視圖函數,並且整個應用也被限制了只支持 預先定義好的時間段,2小時,3小時,或者4小時。 若是哪天咱們要實現 5 小時,咱們就 不得再也不單首創建新的視圖函數和配置URL,既重複又混亂。 咱們須要在這裏作一點抽象,提取 一些共同的東西出來。web

關於漂亮URL的一點建議正則表達式

  若是你有其它web平臺的開發經驗(如PHP或Java),你可能會想:嘿!讓咱們用查詢字符串參數吧! 就像/time/plus?hours=3裏面的小時應該在查詢字符串中被參數hours指定(問號後面的是參數)。django

  你能夠 在Django裏也這樣作 (若是你真的想要這樣作,咱們稍後會告訴你怎麼作), 可是Django的一個核心理念就是URL必須看起來漂亮。 URL /time/plus/3/ 更加清晰, 更簡單,也更有可讀性,能夠很容易的大聲念出來,由於它是純文本,沒有查詢字符串那麼 複雜。 漂亮的URL就像是高質量的Web應用的一個標誌。瀏覽器

  Django的URL配置系統可使你很容易的設置漂亮的URL,而儘可能不要考慮它的反面 。服務器

  那麼,咱們如何設計程序來處理任意數量的時差? 答案是:使用通配符(wildcard URLpatterns)。正如咱們以前提到過,一個URL模式就是一個正則表達式。所以,這裏可使用d+來匹配1個以上的數字。函數

urlpatterns = patterns('',
    # ...
    (r'^time/plus/\d+/$', hours_ahead),
    # ...
)

  這裏使用# …來表示省略了其它可能存在的URL模式定義。 (見上)url

  這個URL模式將匹配相似 /time/plus/2/ , /time/plus/25/ ,甚至 /time/plus/100000000000/ 的任何URL。 更進一步,讓咱們把它限制在最大容許99個小時, 這樣咱們就只容許一個或兩個數字,正則表達式的語法就是 \d{1,2} :spa

(r'^time/plus/\d{1,2}/$', hours_ahead),

    在建造Web應用的時候,儘量多考慮可能的數據輸入是很重要的,而後決定哪些咱們能夠接受。 在這裏咱們就設置了99個小時的時間段限制。設計

  另一個重點,正則表達式字符串的開頭字母「r」。 它告訴Python這是個原始字符串,不須要處理裏面的反斜槓(轉義字符)。 在普通Python字符串中,反斜槓用於特殊字符的轉義。好比n轉義成一個換行符。 當你用r把它標示爲一個原始字符串後,Python再也不視其中的反斜槓爲轉義字符。也就是說,「n」是兩個字符串:「」和「n」。因爲反斜槓在Python代碼和正則表達式中有衝突,所以建議你在Python定義正則表達式時都使用原始字符串。 從如今開始,本文全部URL模式都用原始字符串。10

  如今咱們已經設計了一個帶通配符的URL,咱們須要一個方法把它傳遞到視圖函數裏去,這樣 咱們只用一個視圖函數就能夠處理全部的時間段了。 咱們使用圓括號把參數在URL模式裏標識 出來。 在這個例子中,咱們想要把這些數字做爲參數,用圓括號把 \d{1,2} 包圍起來:

(r'^time/plus/(\d{1,2})/$', hours_ahead),

若是你熟悉正則表達式,那麼你應該已經瞭解,正則表達式也是用圓括號來從文本里 提取 數據的。2

最終的URLconf包含上面兩個視圖,如:

from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = patterns('',
    (r'^hello/$', hello),
    (r'^time/$', current_datetime),
    (r'^time/plus/(\d{1,2})/$', hours_ahead),
)

如今開始寫 hours_ahead 視圖。

hours_ahead 和咱們之前寫的 current_datetime 很象,關鍵的區別在於: 它多了一個額外參數,時間差。 如下是view代碼:

from django.http import Http404, HttpResponse
import datetime

def hours_ahead(request, offset):
    try:
        offset = int(offset)
    except ValueError:
        raise Http404()
    dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
    html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
    return HttpResponse(html)

讓咱們逐行分析一下代碼:

視圖函數, hours_ahead , 有 兩個 參數: request 和 offset . (見上)

  request 是一個 HttpRequest 對象, 就像在 current_datetime 中同樣. 再說一次好了: 每個視圖 老是 以一個 HttpRequest 對象做爲 它的第一個參數。 (見上)

   offset 是從匹配的URL裏提取出來的。 例如:若是請求URL是/time/plus/3/,那麼offset將會是3;若是請求URL是/time/plus/21/,那麼offset將會是21。請注意:捕獲值永遠都是字符串(string)類型,而不會是整數(integer)類型,即便這個字符串全由數字構成(如:「21」)。

(從技術上來講,捕獲值老是Unicode objects,而不是簡單的Python字節串,但目前不須要擔憂這些差異。)

  在這裏咱們命名變量爲 offset ,你也能夠任意命名它,只要符合Python 的語法。 變量名是可有可無的,重要的是它的位置,它是這個函數的第二個 參數 (在 request 的後面)。 你還可使用關鍵字來定義它,而不是用 位置。

  咱們在這個函數中要作的第一件事情就是在 offset 上調用 int() . 這會把這個字符串值轉換爲整數。

請留意:若是你在一個不能轉換成整數類型的值上調用int(),Python將拋出一個ValueError異常。如:int(‘foo’)。在這個例子中,若是咱們遇到ValueError異常,咱們將轉爲拋出django.http.Http404異常——正如你想象的那樣:最終顯示404頁面(提示信息:頁面不存在)。

  機靈的讀者可能會問: 咱們在URL模式中用正則表達式(d{1,2})約束它,僅接受數字怎麼樣?這樣不管如何,offset都是由數字構成的。 答案是:咱們不會這麼作,由於URLpattern提供的是「適度但有用」級別的輸入校驗。萬一這個視圖函數被其它方式調用,咱們仍需自行檢查ValueError。 實踐證實,在實現視圖函數時,不臆測參數值的作法是比較好的。 鬆散耦合,還記得麼?

  下一行,計算當前日期/時間,而後加上適當的小時數。 在current_datetime視圖中,咱們已經見過datetime.datetime.now()。這裏新的概念是執行日期/時間的算術操做。咱們須要建立一個datetime.timedelta對象和增長一個datetime.datetime對象。 結果保存在變量dt中。

  這一行還說明了,咱們爲何在offset上調用int()——datetime.timedelta函數要求hours參數必須爲整數類型。

  這行和前面的那行的的一個微小差異就是,它使用帶有兩個值的Python的格式化字符串功能, 而不只僅是一個值。 所以,在字符串中有兩個 %s 符號和一個以進行插入的值的元組: (offset, dt) 。

最終,返回一個HTML的HttpResponse。 現在,這種方式已通過時了。28

  在完成視圖函數和URL配置編寫後,啓動Django開發服務器,用瀏覽器訪問 http://127.0.0.1:8000/time/plus/3/ 來確認它工做正常。 而後是http://127.0.0.1:8000/time/plus/5/ 。再而後是 http://127.0.0.1:8000/time/plus/24/ 。最後,訪問 http://127.0.0.1:8000/time/plus/100/ 來檢驗URL配置裏設置的模式是否只 接受一個或兩個數字;Django會顯示一個 Page not found error 頁面, 和之前看到的 404 錯誤同樣。 訪問URL http://127.0.0.1:8000/time/plus/ (沒有 定義時間差) 也會拋出404錯誤。

相關文章
相關標籤/搜索