django動態url

lm_y發表於2017-08-31

程式實現

我們建立第三個檢視來顯示當前時間和加上時間偏差量的時間,設計是這樣的: /time/plus/1/ 顯示當前時間+1個小時的頁面 /time/plus/2/ 顯示當前時間+2個小時的頁面 /time/plus/3/ 顯示當前時間+3個小時的頁面,以此類推。

1. urls.py

1 from django.conf.urls.defaults import *
2 from PythonProject.views import hello, current_datetime, hours_ahead
3  
4 urlpatterns = patterns('',
5     ('^hello/$', hello),
6     ('^time/$', current_datetime),
7     (r'^time/plus/(\d{1,2})/$', hours_ahead),
8 )

2. views.py

01 from django.http import Http404, HttpResponse
02 import datetime
03  
04 def hello(request):
05     return HttpResponse("Hello NowaMagic")
06  
07 def current_datetime(request):
08     now = datetime.datetime.now()
09     html = "<html><body>It is now %s.</body></html>" % now
10     return HttpResponse(html)
11  
12 def hours_ahead(request, offset):
13     offset = int(offset)
14     dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
15     html = "<html><body>In %s hour(s), it will be %s.</body></html>" %(offset, dt)
16     return HttpResponse(html)

現在訪問 http://127.0.0.1:8000/time/plus/3/,比實際時間多了 3 小時。OK,程式通過。

程式解釋

新手可能會考慮寫不同的檢視函式來處理每個時間偏差量,URL配置看起來就象這樣:

1 urlpatterns = patterns('',
2     ('^time/$', current_datetime),
3     ('^time/plus/1/$', one_hour_ahead),
4     ('^time/plus/2/$', two_hours_ahead),
5     ('^time/plus/3/$', three_hours_ahead),
6     ('^time/plus/4/$', four_hours_ahead),
7 )

很明顯,這樣處理是不太妥當的。 不但有很多冗餘的檢視函式,而且整個應用也被限制了只支援 預先定義好的時間段,2小時,3小時,或者4小時。如果哪天我們要實現 5 小時,我們就 不得不再單獨建立新的檢視函式和配置URL,既重複又混亂。 我們需要在這裡做一點抽象,提取一些共同的東西出來。

那麼,我們如何設計程式來處理任意數量的時差? 答案是:使用萬用字元(wildcard URLpatterns)。正如我們之前提到過,一個URL模式就是一個正規表示式。因此,這裡可以使用d+來匹配1個以上的數字。

1 urlpatterns = patterns('',
2     # ...
3     (r'^time/plus/(\d+)/$', hours_ahead),
4     # ...
5 )

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

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

另外一個重點,正規表示式字串的開頭字母“r”。 它告訴python這是個原始字串,不需要處理裡面的反斜槓(轉義字元)。 在普通Python字串中,反斜槓用於特殊字元的轉義。比如n轉義成一個換行符。 當你用r把它標示為一個原始字串後,Python不再視其中的反斜槓為轉義字元。也就是說,“n”是兩個字串:“”和“n”。由於反斜槓在Python程式碼和正規表示式中有衝突,因此建議你在Python定義正規表示式時都使用原始字串。 從現在開始,本文所有URL模式都用原始字串。

現在我們已經設計了一個帶萬用字元的URL,我們需要一個方法把它傳遞到檢視函式裡去,這樣 我們只用一個檢視函式就可以處理所有的時間段了。 我們使用圓括號把引數在URL模式裡標識 出來。 在這個例子中,我們想要把這些數字作為引數,用圓括號把 \d{1,2} 包圍起來

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

如果你熟悉正規表示式,那麼你應該已經瞭解,正規表示式也是用圓括號來從文字里 提取 資料的。

讓我們逐行分析一下 views.py 的程式碼:

檢視函式, 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。

OK,程式解釋完畢。用 Django 實現動態 URL 大概就這樣。



五、Q&A
*先寫URLpattern還是先寫檢視?
根據個人喜好,一般設定主框架時,可以先寫出URLpattern,在開發具體的檢視;細節處,可以先寫好檢視函式,然後在掛到

URLpattern上。


*正規表示式
. (dot) 任意單一字元 
\d 任意一位數字 
[A-Z] A 到 Z中任意一個字元(大寫) 
[a-z] a 到 z中任意一個字元(小寫) 
[A-Za-z] a 到 z中任意一個字元(不區分大小寫) 
+ 匹配一個或更多 (例如, \d+ 匹配一個或 多個數字字元) 
[^/]+ 一個或多個不為‘/’的字元 
? 零個或一個之前的表示式(例如:\d? 匹配零個或一個數字) 
* 匹配0個或更多 (例如, \d* 匹配0個 或更多數字字元) 
{1,3} 介於一個和三個(包含)之前的表示式(例如,\d{1,3}匹配一個或兩個或三個數字)

相關文章