在Django中建立動態視圖的教程

來源:互聯網
上載者:User
在我們的`` current_datetime`` 視圖範例中,儘管內容是動態,但是URL ( /time/ )是靜態。 在 大多數動態web應用程式,URL通常都包含有相關的參數。 舉個例子,一家線上書店會為每一本書提供一個URL,如:/books/243/、/books/81196/。

讓我們建立第三個視圖來顯示目前時間和加上時間偏差量的時間,設計是這樣的: /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,既重複又混亂。 我們需要在這裡做一點抽象,提取 一些共同的東西出來。

關於漂亮URL的一點建議

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

你 可以 在Django裡也這樣做 (如果你真的想要這樣做,我們稍後會告訴你怎麼做), 但是Django的一個核心理念就是URL必須看起來漂亮。 URL /time/plus/3/ 更加清晰, 更簡單,也更有可讀性,可以很容易的大聲念出來,因為它是純文字,沒有查詢字串那麼 複雜。 漂亮的URL就像是高品質的Web應用的一個標誌。

Django的URL配置系統可以使你很容易的設定漂亮的URL,而盡量不要考慮它的 反面 。

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

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

這裡使用# …來表示省略了其它可能存在的URL模式定義。 這個URL模式將匹配類似 /time/plus/2/ , /time/plus/25/ ,甚至 /time/plus/100000000000/ 的任何URL。 更進一步,讓我們把它限制在最大允許99個小時, 這樣我們就只允許一個或兩個數字,Regex的文法就是 \d{1,2} :

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

備忘

在建造Web應用的時候,儘可能多考慮可能的資料輸入是很重要的,然後決定哪些我們可以接受。 在這裡我們就設定了99個小時的時間段限制。

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

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

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

如果你熟悉Regex,那麼你應該已經瞭解,Regex也是用圓括弧來從文本裡 提取 資料的。

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

from django.conf.urls.defaults import *from mysite.views import hello, current_datetime, hours_aheadurlpatterns = patterns('',  (r'^hello/$', hello),  (r'^time/$', current_datetime),  (r'^time/plus/(\d{1,2})/$', hours_ahead),)

現在開始寫 hours_ahead 視圖。

編碼次序

這個例子中,我們先寫了URLpattern ,然後是視圖,但是在前面的例子中, 我們先寫了視圖,然後是URLpattern 。 哪一種方式比較好?

嗯,怎麼說呢,每個開發人員是不一樣的。

如果你是喜歡從總體上來把握事物(註: 或譯為“大局觀”)類型的人,你應該會想在項目開始 的時候就寫下所有的URL配置。

如果你從更像是一個自底向上的開發人員,你可能更喜歡先寫視圖, 然後把它們掛接到URL上。 這同樣是可以的。

最後,取決與你喜歡哪種技術,兩種方法都是可以的。 (見上)

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

from django.http import Http404, HttpResponseimport datetimedef hours_ahead(request, offset):  try:    offset = int(offset)  except ValueError:    raise Http404()  dt = datetime.datetime.now() + datetime.timedelta(hours=offset)  html = "In %s hour(s), it will be %s." % (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模式中用Regex(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。 如今,這種方式已經過時了。

在完成視圖函數和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錯誤。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.