<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                前一章中,我們解釋了如何建立一個 Django 項目并啟動 Django 開發服務器。 在這一章,你將會學到用Django創建動態網頁的基本知識。 ## 你的第一個基于Django的頁面: Hello World 正如我們的第一個目標,創建一個網頁,用來輸出這個著名的示例信息: ~~~ Hello world. ~~~ 如果你曾經發布過Hello world頁面,但是沒有使用網頁框架,只是簡單的在hello.html文本文件中輸入Hello World,然后上傳到任意的一個網頁服務器上。 注意,在這個過程中,你已經說明了兩個關于這個網頁的關鍵信息: 它包括(字符串?"Hello?world")和它的URL(?http://www.example.com/hello.html?, 如果你把文件放在子目錄,也可能是?http://www.example.com/files/hello.html)。 使用Django,你會用不同的方法來說明這兩件事 頁面的內容是靠_view function(視圖函數)_?來產生,URL定義在?_URLconf_?中。首先,我們先寫一個Hello World視圖函數。 ### 第一份視圖: 在上一章使用django-admin.py?startproject制作的mysite文件夾中,創建一個叫做views.py的空文件。這個Python模塊將包含這一章的視圖。 請留意,Django對于view.py的文件命名沒有特別的要求,它不在乎這個文件叫什么。但是根據約定,把它命名成view.py是個好主意,這樣有利于其他開發者讀懂你的代碼,正如你很容易的往下讀懂本文。 我們的Hello world視圖非常簡單。 這些是完整的函數和導入聲明,你需要輸入到views.py文件: ~~~ from django.http import HttpResponse def hello(request): return HttpResponse("Hello world") ~~~ 我們逐行逐句地分析一遍這段代碼: > 首先,我們從?django.http?模塊導入(import)?HttpResponse?類。參閱附錄 H 了解更多關于?HttpRequest和?HttpResponse?的細節。 我們需要導入這些類,因為我們會在后面用到。 > > 接下來,我們定義一個叫做hello?的視圖函數。 > > 每個視圖函數至少要有一個參數,通常被叫作request。 這是一個觸發這個視圖、包含當前Web請求信息的對象,是類django.http.HttpRequest的一個實例。在這個示例中,我們雖然不用request做任何事情,然而它仍必須是這個視圖的第一個參數。 > > 注意視圖函數的名稱并不重要;并不一定非得以某種特定的方式命名才能讓 Django 識別它。 在這里我們把它命名為:hello,是因為這個名稱清晰的顯示了視圖的用意。同樣地,你可以用諸如:hello_wonderful_beautiful_world,這樣難看的短句來給它命名。 在下一小節(Your First URLconf),將告訴你Django是如何找到這個函數的。 > > 這個函數只有簡單的一行代碼: 它僅僅返回一個HttpResponse對象,這個對象包含了文本“Hello world”。 這里主要講的是: 一個視圖就是Python的一個函數。這個函數第一個參數的類型是HttpRequest;它返回一個HttpResponse實例。為了使一個Python的函數成為一個Django可識別的視圖,它必須滿足這兩個條件。 (也有例外,但是我們稍后才會接觸到。 ### 你的第一個URLconf 現在,如果你再運行:python manage.py runserver,你還將看到Django的歡迎頁面,而看不到我們剛才寫的Hello world顯示頁面。 那是因為我們的mysite項目還對hello視圖一無所知。我們需要通過一個詳細描述的URL來顯式的告訴它并且激活這個視圖。 (繼續我們剛才類似發布靜態HTML文件的例子。現在我們已經創建了HTML文件,但還沒有把它上傳至服務器的目錄。)為了綁定視圖函數和URL,我們使用URLconf。 _URLconf_?就像是 Django 所支撐網站的目錄。 它的本質是 URL 模式以及要為該 URL 模式調用的視圖函數之間的映射表。 你就是以這種方式告訴 Django,對于這個 URL 調用這段代碼,對于那個 URL 調用那段代碼。 例如,當用戶訪問/foo/時,調用視圖函數foo_view(),這個視圖函數存在于Python模塊文件view.py中。 前一章中執行?django-admin.py?startproject?時,該腳本會自動為你建了一份 URLconf(即?urls.py?文件)。 默認的urls.py會像下面這個樣子: ~~~ from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: # from django.contrib import admin # admin.autodiscover() urlpatterns = patterns('', # Example: # (r'^mysite/', include('mysite.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: # (r'^admin/', include(admin.site.urls)), ) ~~~ 默認的URLconf包含了一些被注釋起來的Django中常用的功能,僅僅只需去掉這些注釋就可以開啟這些功能. 下面是URLconf中忽略被注釋的行后的實際內容 ~~~ from django.conf.urls.defaults import * urlpatterns = patterns('', ) ~~~ 讓我們逐行解釋一下代碼: * 第一行導入django.conf.urls.defaults下的所有模塊,它們是Django URLconf的基本構造。 這包含了一個patterns函數。 * 第二行調用?patterns()?函數并將返回結果保存到?urlpatterns?變量。patterns函數當前只有一個參數—一個空的字符串。 (這個字符串可以被用來表示一個視圖函數的通用前綴。具體我們將在第八章里面介紹。) 當前應該注意是?urlpatterns?變量, Django 期望能從?ROOT_URLCONF?模塊中找到它。 該變量定義了 URL 以及用于處理這些 URL 的代碼之間的映射關系。 默認情況下,URLconf 所有內容都被注釋起來了——Django 應用程序還是白版一塊。 (注:那是上一節中Django怎么知道顯示歡迎頁面的原因。 如果 URLconf 為空,Django 會認定你才創建好新項目,因此也就顯示那種信息。 如果想在URLconf中加入URL和view,只需增加映射URL模式和view功能的Python tuple即可. 這里演示如何添加view中hello功能. ~~~ from django.conf.urls.defaults import * from mysite.views import hello urlpatterns = patterns('', ('^hello/$', hello), ) ~~~ 請留意:為了簡潔,我們移除了注釋代碼。 如果你喜歡的話,你可以保留那些行。) 我們做了兩處修改。 * 首先,我們從模塊 (在 Python 的 import 語法中,?mysite/views.py?轉譯為?mysite.views?) 中引入了hello?視圖。 (這假設mysite/views.py在你的Python搜索路徑上。關于搜索路徑的解釋,請參照下文。) * 接下來,我們為urlpatterns加上一行: (‘^hello/$’, hello), 這行被稱作URLpattern,它是一個Python的元組。元組中第一個元素是模式匹配字符串(正則表達式);第二個元素是那個模式將使用的視圖函數。 簡單來說,我們只是告訴 Django,所有指向 URL?/hello/?的請求都應由?hello?這個視圖函數來處理。 > Python 搜索路徑 > _Python 搜索路徑_?就是使用?import?語句時,Python 所查找的系統目錄清單。 舉例來說,假定你將 Python 路徑設置為 ~~~ ['','/usr/lib/python2.4/site-packages','/home/username/djcode/'] ~~~ 如果執行代碼from?foo?import?bar?,Python 將會首先在當前目錄查找?foo.py?模塊( Python 路徑第一項的空字符串表示當前目錄)。 如果文件不存在,Python將查找?`/usr/lib/python2.4/site-packages/foo.py`?文件。 如果你想看Python搜索路徑的值,運行Python交互解釋器,然后輸入: ~~~ >>> import sys >>> print sys.path ~~~ 通常,你不必關心 Python 搜索路徑的設置。 Python 和 Django 會在后臺自動幫你處理好。 討論一下URLpattern的語法是值得的,因為它不是顯而易見的。 雖然我們想匹配地址/hello/,但是模式看上去與這有點差別。 這就是為什么: > Django在檢查URL模式前,移除每一個申請的URL開頭的斜杠(/)。 這意味著我們為/hello/寫URL模式不用包含斜杠(/)。(剛開始,這樣可能看起來不直觀,但這樣的要求簡化了許多工作,如URL模式內嵌,我們將在第八章談及。) > > 模式包含了一個尖號(^)和一個美元符號($)。這些都是正則表達式符號,并且有特定的含義: 上箭頭要求表達式對字符串的頭部進行匹配,美元符號則要求表達式對字符串的尾部進行匹配。 > > > 最好還是用范例來說明一下這個概念。 如果我們用尾部不是$的模式’^hello/’,那么任何以/hello/開頭的URL將會匹配,例如:/hello/foo 和/hello/bar,而不僅僅是/hello/。類似地,如果我們忽略了尖號(^),即’hello/$’,那么任何以hello/結尾的URL將會匹配,例如:/foo/bar/hello/。如果我們簡單使用hello/,即沒有^開頭和$結尾,那么任何包含hello/的URL將會匹配,如:/foo/hello/bar。因此,我們使用這兩個符號以確保只有/hello/匹配,不多也不少。 > > 你大多數的URL模式會以^開始、以$結束,但是擁有復雜匹配的靈活性會更好。 > 你可能會問:如果有人申請訪問/hello(尾部沒有斜杠/)會怎樣。 因為我們的URL模式要求尾部有一個斜杠(/),那個申請URL將不匹配。 然而,默認地,任何不匹配或尾部沒有斜杠(/)的申請URL,將被重定向至尾部包含斜杠的相同字眼的URL。 (這是受配置文件setting中APPEND_SLASH項控制的,參見附件D。) > 如果你是喜歡所有URL都以’/’結尾的人(Django開發者的偏愛),那么你只需要在每個URL后添加斜杠,并且設置”APPEND_SLASH”為”True”. 如果不喜歡URL以斜杠結尾或者根據每個URL來決定,那么需要設置”APPEND_SLASH”為”False”,并且根據你自己的意愿來添加結尾斜杠/在URL模式后. 另外需要注意的是,我們把hello視圖函數作為一個對象傳遞,而不是調用它。 這是 Python (及其它動態語言的) 的一個重要特性: 函數是一級對象(first-class objects), 也就是說你可以像傳遞其它變量一樣傳遞它們。 很酷吧? 啟動Django開發服務器來測試修改好的 URLconf, 運行命令行?python?manage.py?runserver?。 (如果你讓它一直運行也可以,開發服務器會自動監測代碼改動并自動重新載入,所以不需要手工重啟) 開發服務器的地址是[http://127.0.0.1:8000/](http://127.0.0.1:8000/)?,打開你的瀏覽器訪問?[http://127.0.0.1:8000/hello/](http://127.0.0.1:8000/hello/)?。 你就可以看到輸出結果了。 開發服務器將自動檢測Python代碼的更改來做必要的重新加載, 所以你不需要重啟Server在代碼更改之后。服務器運行地址?[http://127.0.0.1:8000](http://127.0.0.1:8000/)/ ,所以打開瀏覽器直接輸入?[http://127.0.0.1:8000/hello](http://127.0.0.1:8000/hello)/ ,你將看到由你的Django視圖輸出的Hello world。 萬歲! 你已經創建了第一個Django的web頁面。 正則表達式 _正則表達式_?(或?_regexes_?) 是通用的文本模式匹配的方法。 Django URLconfs 允許你 使用任意的正則表達式來做強有力的URL映射,不過通常你實際上可能只需要使用很少的一 部分功能。 這里是一些基本的語法。 | 符號 | 匹配 | | --- | --- | | .?(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}匹配一個或兩個或三個數字) | 有關正則表達式的更多內容,請訪問?[http://www.djangoproject.com/r/python/re-module/](http://www.djangoproject.com/r/python/re-module/). ### 關于“404錯誤”的快速參考 目前,我們的URLconf只定義了一個單獨的URL模式: 處理URL?/hello/?。 當請求其他URL會怎么樣呢? 讓我們試試看,運行Django開發服務器并訪問類似?http://127.0.0.1:8000/goodbye/?或者http://127.0.0.1:8000/hello/subdirectory/?,甚至?http://127.0.0.1:8000/?(網站根目錄)。 你將會看到一個 “Page not found” 頁面(圖 3-1)。 因為你的URL申請在URLconf中沒有定義,所以Django顯示這條信息。 ![2015-06-26/558d267f427f5](https://box.kancloud.cn/2015-06-26_558d267f427f5.png) 圖3-1: Django的404 Error頁 這個頁面比原始的404錯誤信息更加實用。 它同時精確的告訴你Django調用哪個URLconf及其包含的每個模式。 這樣,你應該能了解到為什么這個請求會拋出404錯誤。 當然,這些敏感的信息應該只呈現給你-開發者。 如果是部署到了因特網上的站點就不應該暴露 這些信息。 出于這個考慮,這個“Page not found”頁面只會在?_調試模式(debug mode)_?下 顯示。 我們將在以后說明怎么關閉調試模式。 ### 關于網站根目錄的快速參考。 在最后一節,如果你想通過http://127.0.0.1:8000/看網站根目錄你將看到一個404錯誤消息。Django不會增加任何東西在網站根目錄,在任何情況下這個URL都不是特殊的 就像在URLconf中的其他條目一樣,它也依賴于指定給它的URL模式. 盡管匹配網站根目錄的URL模式不能想象,但是還是值得提一下的. 當為網站根目錄實現一個視圖,你需要使用URL模式`` ‘^$’`` , 它代表一個空字符串。 例如: ~~~ from mysite.views import hello, my_homepage_view urlpatterns = patterns('', url(r'^$', my_homepage_view), # ... ) ~~~ ## Django是怎么處理請求的 在繼續我們的第二個視圖功能之前,讓我們暫停一下去了解更多一些有關Django是怎么工作的知識. 具體地說,當你通過在瀏覽器里敲http://127.0.0.1:8000/hello/來訪問Hello world消息得時候,Django在后臺有些什么動作呢? 所有均開始于setting文件。當你運行python manage.py runserver,腳本將在于manage.py同一個目錄下查找名為setting.py的文件。這個文件包含了所有有關這個Django項目的配置信息,均大寫: TEMPLATE_DIRS , DATABASE_NAME , 等. 最重要的設置時ROOT_URLCONF,它將作為URLconf告訴Django在這個站點中那些Python的模塊將被用到 還記得什么時候django-admin.py startproject創建文件settings.py和urls.py嗎?自動創建的settings.py包含一個ROOT_URLCONF配置用來指向自動產生的urls.py. 打開文件settings.py你將看到如下: ~~~ ROOT_URLCONF = 'mysite.urls' ~~~ 相對應的文件是mysite/urls.py 當訪問 URL?/hello/?時,Django 根據?ROOT_URLCONF?的設置裝載 URLconf 。 然后按順序逐個匹配URLconf里的URLpatterns,直到找到一個匹配的。 當找到這個匹配 的URLpatterns就調用相關聯的view函數,并把HttpRequest?對象作為第一個參數。 (稍后再給出?HttpRequest?的更多信息) (我們將在后面看到HttpRequest的標準) 正如我們在第一個視圖例子里面看到的,一個視圖功能必須返回一個HttpResponse。 一旦做完,Django將完成剩余的轉換Python的對象到一個合適的帶有HTTP頭和body的Web Response,(例如,網頁內容)。 總結一下: 1. 進來的請求轉入/hello/. 1. Django通過在ROOT_URLCONF配置來決定根URLconf. 1. Django在URLconf中的所有URL模式中,查找第一個匹配/hello/的條目。 1. 如果找到匹配,將調用相應的視圖函數 1. 視圖函數返回一個HttpResponse 1. Django轉換HttpResponse為一個適合的HTTP response, 以Web page顯示出來 你現在知道了怎么做一個 Django-powered 頁面了,真的很簡單,只需要寫視圖函數并用 URLconfs把它們和URLs對應起來。 你可能會認為用一系列正則表達式將URLs映射到函數也許會比較慢,但事實卻會讓你驚訝。 ## 第二個視圖: 動態內容 我們的Hello world視圖是用來演示基本的Django是如何工作的,但是它不是一個動態網頁的例子,因為網頁的內容一直是一樣的. 每次去查看/hello/,你將會看到相同的內容,它類似一個靜態HTML文件。 我們的第二個視圖,將更多的放些動態的東西例如當前日期和時間顯示在網頁上 這將非常好,簡單的下一步,因為它不引入了數據庫或者任何用戶的輸入,僅僅是輸出顯示你的服務器的內部時鐘. 它僅僅有限度的比Helloworld刺激一些,但是它將演示一些新的概念 這個視圖需要做兩件事情: 計算當前日期和時間,并返回包含這些值的HttpResponse 如果你對python很有經驗,那肯定知道在python中需要利用datetime模塊去計算時間 下面演示如何去使用它: ~~~ >>> import datetime >>> now = datetime.datetime.now() >>> now datetime.datetime(2008, 12, 13, 14, 9, 39, 2731) >>> print now 2008-12-13 14:09:39.002731 ~~~ 以上代碼很簡單,并沒有涉及Django。 它僅僅是Python代碼。 需要強調的是,你應該意識到哪些是純Python代碼,哪些是Django特性代碼。 (見上) 因為你學習了Django,希望你能將Django的知識應用在那些不一定需要使用Django的項目上。 為了讓Django視圖顯示當前日期和時間,我們僅需要把語句:datetime.datetime.now()放入視圖函數,然后返回一個HttpResponse對象即可。代碼如下: ~~~ from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) ~~~ 正如我們的hello函數一樣,這個函數也保存在view.py中。為了簡潔,上面我們隱藏了hello函數。下面是完整的view.py文件內容: ~~~ from django.http import HttpResponse import datetime def hello(request): return HttpResponse("Hello world") def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) ~~~ (從現在開始,如非必要,本文不再重復列出先前的代碼。 你應該懂得識別哪些是新代碼,哪些是先前的。) (見上) 讓我們分析一下改動后的views.py: > 在文件頂端,我們添加了一條語句:import datetime。這樣就可以計算日期了。 > 函數中的第一行代碼計算當前日期和時間,并以?datetime.datetime?對象的形式保存為局部變量?now?。 > 函數的第二行代碼用 Python 的格式化字符串(format-string)功能構造了一段 HTML 響應。 字符串中的%s是占位符,字符串后面的百分號表示用它后面的變量now的值來代替%s。變量%s是一個datetime.datetime對象。它雖然不是一個字符串,但是%s(格式化字符串)會把它轉換成字符串,如:2008-12-13 14:09:39.002731。這將導致HTML的輸出字符串為:It is now 2008-12-13 14:09:39.002731。 > > (目前HTML是有錯誤的,但我們這樣做是為了保持例子的簡短。) > > 最后,正如我們剛才寫的hello函數一樣,視圖返回一個HttpResponse對象,它包含生成的響應。 添加上述代碼之后,還要在urls.py中添加URL模式,以告訴Django由哪一個URL來處理這個視圖。 用/time/之類的字眼易于理解: ~~~ from django.conf.urls.defaults import * from mysite.views import hello, current_datetime urlpatterns = patterns('', ('^hello/$', hello), ('^time/$', current_datetime), ) ~~~ 這里,我們修改了兩個地方。 首先,在頂部導入current_datetime函數; 其次,也是比較重要的:添加URL模式來映射URL中的/time/和新視圖。 理解了么? 寫好視圖并且更新URLconf之后,運行命令python manage.py runserver以啟動服務,在瀏覽器中輸入http://127.0.0.1:8000/time/。 你將看到當前的日期和時間。 Django時區 視乎你的機器,顯示的日期與時間可能和實際的相差幾個小時。 這是因為Django是有時區意識的,并且默認時區為America/Chicago。 (它必須有個值,它的默認值是Django的誕生地:美國/芝加哥)如果你處在別的時區,你需要在settings.py文件中更改這個值。請參見它里面的注釋,以獲得最新世界時區列表。 ## URL配置和松耦合 現在是好時機來指出Django和URL配置背后的哲學:?_松耦合_?原則。 簡單的說,松耦合是一個 重要的保證互換性的軟件開發方法。 Django的URL配置就是一個很好的例子。 在Django的應用程序中,URL的定義和視圖函數之間是松 耦合的,換句話說,決定URL返回哪個視圖函數和實現這個視圖函數是在兩個不同的地方。 這使得 開發人員可以修改一塊而不會影響另一塊。 例如,考慮一下current_datetime視圖。 如果我們想把它的URL 從原來的?/time/?改變到?/currenttime/?,我們只需要快速的修改一下URL配置即可, 不用擔心這個函數的內部實現。 同樣的,如果我們想要修改這個函數的內部實現也不用擔心會影響 到對應的URL。 此外,如果我們想要輸出這個函數到?_一些_?URL, 我們只需要修改URL配置而不用 去改動視圖的代碼。 在這個例子里,current_datetime被兩個URL使用。 這是一個故弄玄虛的例子,但這個方法遲早會用得上。 ~~~ urlpatterns = patterns('', ('^hello/$', hello), ('^time/$', current_datetime), ('^another-time-page/$', current_datetime), ) ~~~ URLconf和視圖是松耦合的。 我們將在本書中繼續給出這一重要哲學的相關例子。 ## 第三個視圖 動態URL 在我們的`` 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模式就是一個正則表達式。因此,這里可以使用d+來匹配1個以上的數字。 ~~~ urlpatterns = patterns('', # ... (r'^time/plus/\d+/$', hours_ahead), # ... ) ~~~ 這里使用# …來表示省略了其它可能存在的URL模式定義。 (見上) 這個URL模式將匹配類似?/time/plus/2/?,?/time/plus/25/?,甚至?/time/plus/100000000000/?的任何URL。 更進一步,讓我們把它限制在最大允許99個小時, 這樣我們就只允許一個或兩個數字,正則表達式的語法就是\d{1,2}?: ~~~ (r'^time/plus/\d{1,2}/$', hours_ahead), ~~~ > 備注 > 在建造Web應用的時候,盡可能多考慮可能的數據輸入是很重要的,然后決定哪些我們可以接受。 在這里我們就設置了99個小時的時間段限制。 另外一個重點,正則表達式字符串的開頭字母“r”。 它告訴Python這是個原始字符串,不需要處理里面的反斜杠(轉義字符)。 在普通Python字符串中,反斜杠用于特殊字符的轉義。比如n轉義成一個換行符。 當你用r把它標示為一個原始字符串后,Python不再視其中的反斜杠為轉義字符。也就是說,“n”是兩個字符串:“”和“n”。由于反斜杠在Python代碼和正則表達式中有沖突,因此建議你在Python定義正則表達式時都使用原始字符串。 從現在開始,本文所有URL模式都用原始字符串。 現在我們已經設計了一個帶通配符的URL,我們需要一個方法把它傳遞到視圖函數里去,這樣 我們只用一個視圖函數就可以處理所有的時間段了。 我們使用圓括號把參數在URL模式里標識 出來。 在這個例子中,我們想要把這些數字作為參數,用圓括號把?\d{1,2}?包圍起來: ~~~ (r'^time/plus/(\d{1,2})/$', hours_ahead), ~~~ 如果你熟悉正則表達式,那么你應該已經了解,正則表達式也是用圓括號來從文本里?_提取_?數據的。 最終的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?視圖。 編碼次序 這個例子中,我們先寫了URLpattern ,然后是視圖,但是在前面的例子中, 我們先寫了視圖,然后是URLpattern 。 哪一種方式比較好? 嗯,怎么說呢,每個開發者是不一樣的。 如果你是喜歡從總體上來把握事物(注: 或譯為“大局觀”)類型的人,你應該會想在項目開始 的時候就寫下所有的URL配置。 如果你從更像是一個自底向上的開發者,你可能更喜歡先寫視圖, 然后把它們掛接到URL上。 這同樣是可以的。 最后,取決與你喜歡哪種技術,兩種方法都是可以的。 (見上) 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。 如今,這種方式已經過時了。 在完成視圖函數和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錯誤。 ## Django 漂亮的出錯頁面 花幾分鐘時間欣賞一下我們寫好的Web應用程序,然后我們再來搞點小破壞。 我們故意在?views.py?文件中引入一項 Python 錯誤,注釋掉?hours_ahead?視圖中的?offset?=?int(offset)?一行。 ~~~ 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) ~~~ 啟動開發服務器,然后訪問?/time/plus/3/?。你會看到一個包含大量信息的出錯頁,最上面 的一條?TypeError信息是:?"unsupported?type?for?timedelta?hours?component:??unicode"?. 怎么回事呢? 是的,?datetime.timedelta?函數要求?hours?參數必須為整型, 而我們注釋掉了將?offset?轉為整型的代碼。 這樣導致?datetime.timedelta?彈出?TypeError?異常。 這個例子是為了展示 Django 的出錯頁面。 我們來花些時間看一看這個出錯頁,了解一下其中 給出了哪些信息。 以下是值得注意的一些要點: > 在頁面頂部,你可以得到關鍵的異常信息: 異常數據類型、異常的參數 (如本例中的?"unsupported?type")、在哪個文件中引發了異常、出錯的行號等等。 > 在關鍵異常信息下方,該頁面顯示了對該異常的完整 Python 追蹤信息。 這類似于你在 Python 命令行解釋器中獲得的追溯信息,只不過后者更具交互性。 對棧中的每一幀,Django 均顯示了其文件名、函數或方法名、行號及該行源代碼。 > 點擊該行代碼 (以深灰色顯示),你可以看到出錯行的前后幾行,從而得知相關上下文情況。 > > 點擊棧中的任何一幀的“Local vars”可以看到一個所有局部變量的列表,以及在出錯 那一幀時它們的值。 這些調試信息相當有用。 > 注意“Traceback”下面的“Switch to copy-and-paste view”文字。 點擊這些字,追溯會 切換另一個視圖,它讓你很容易地復制和粘貼這些內容。 當你想同其他人分享這些異常 追溯以獲得技術支持時(比如在 Django 的 IRC 聊天室或郵件列表中),可以使用它。 > 你按一下下面的“Share this traceback on a public Web site”按鈕,它將會完成這項工作。 點擊它以傳回追溯信息至http://www.dpaste.com/,在那里你可以得到一個單獨的URL并與其他人分享你的追溯信息。 > 接下來的“Request information”部分包含了有關產生錯誤的 Web 請求的大量信息: GET 和 POST、cookie 值、元數據(象 CGI 頭)。 在附錄H里給出了request的對象的 完整參考。 > Request信息的下面,“Settings”列出了 Django 使用的具體配置信息。 (我們已經提及過ROOT_URLCONF,接下來我們將向你展示各式的Django設置。 附錄D覆蓋了所有可用的設置。) Django 的出錯頁某些情況下有能力顯示更多的信息,比如模板語法錯誤。 我們討論 Django 模板系統時再說它們。 現在,取消?offset?=?int(offset)?這行的注釋,讓它重新正常 工作。 不知道你是不是那種使用小心放置的?print?語句來幫助調試的程序員? 你其實可以用 Django 出錯頁來做這些,而不用?print?語句。 在你視圖的任何位置,臨時插入一個?assert?False?來觸發出錯頁。 然后,你就可以看到局部變量和程序語句了。 這里有個使用hours_ahead視圖的例子: ~~~ def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) assert False html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html) ~~~ 最后,很顯然這些信息很多是敏感的,它暴露了你 Python 代碼的內部結構以及 Django 配置,在 Internet 上公開這信息是很愚蠢的。 不懷好意的人會嘗試使用它攻擊你的 Web 應用程序,做些下流之事。 因此,Django 出錯信息僅在 debug 模式下才會顯現。 我們稍后 說明如何禁用 debug 模式。 現在,你只要知道 Django 服務器在你開啟它時默認運行在 debug 模式就行了。 (聽起來很熟悉? 頁面沒有發現錯誤,如前所述,工作正常。) ## 下一章 目前為止,我們已經寫好了視圖函數和硬編碼的HTML。 在演示核心概念時,我們所作的是為了保持簡單。但是在現實世界中,這差不多總是個壞主意。 幸運的是,Django內建有一個簡單有強大的模板處理引擎來讓你分離兩種工作: 下一章,我們將學習模板引擎。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看