1. 程式人生 > >django 是如何處理 http 請求的

django 是如何處理 http 請求的

Web 應用的互動過程其實就是 http 請求與響應的過程。無論是在 PC 端還是移動端,我們通常使用瀏覽器來上網,我們的上網流程大致來說是這樣的:

我們開啟瀏覽器,在位址列輸入我們想訪問的網址,比如 http://www.djangoproject.com/(當然你也可能從收藏夾裡直接開啟網站,但本質上都是一樣的。)
瀏覽器知道我們想要訪問那個網址後,它在後臺幫我們做了很多事情,主要就是把我們的訪問意圖包裝成一個 http 請求,發給我們想要訪問的網址所對應的伺服器。通俗點說就是瀏覽器幫我們通知網站的伺服器,說有人來訪問你啦,訪問的請求都寫在 http 裡了,你按照要求處理後告訴我,我再幫你迴應他!
網站伺服器處理了 http 請求,然後生成一段 http 響應給瀏覽器,瀏覽器解讀這個響應,把相關的內容在瀏覽器裡顯示出來,於是我們就看到了網站的內容。比如你訪問了社群主頁 pythonzhcn - 首頁,伺服器接收到這個請求後他就知道使用者訪問的是首頁,首頁顯示的是全部帖子列表,於是它從資料庫裡把帖子資料取出來,生成一個寫著這些資料的 html 文件,包裝到 http 響應裡發給瀏覽器,瀏覽器解讀這個響應,把 html 文件顯示出來,我們就看到了帖子列表的內容。
因此,django 作為一個 web 框架,它的使命就是處理流程中的第二步,接收瀏覽器發來的 http 請求,返回相應的 http 響應。於是引出這麼幾個問題:

django 如何接收 http 請求?
django 如何處理這個 http 請求?
django 如何生成 http 響應?
對於如何處理這些問題,django 有其自身的一套規定的機制。我們按照 django 的規定,就能開發出我們所需的功能。我們先以一個最簡單的 hello world 為例來看看 django 處理上述問題的機制是怎麼樣的。

首先 django 需要知道當用戶訪問不同的網址時,應該如何處理不同的網址。django 的做法是把不同的網址對應的處理函式寫在一個 urls.py 檔案裡,當用戶訪問某個網址時,django 就去會這個檔案裡找,如果找到這個網址,就會呼叫和它繫結在一起的處理函式(叫做檢視函式),下面是具體的做法,首先在 blog 應用的目錄下建立一個

urls.py 檔案,這時你的目錄看起來是這樣:

blog/
init.py
admin.py
apps.py
migrations/
0001_initial.py
init.py
models.py
tests.py
views.py
urls.py # 新建的檔案
urls.py 中寫入這些程式碼:

from django.conf.urls import url

from . import views

urlpatterns = [
url(r’^$’, views.index, name=‘index’),
]
我們首先從 django.conf.urls 匯入了 url 函式,又從當前目錄下匯入了 views 模組。然後我們把網址和處理函式的關係寫在了 urlpatterns 列表裡。繫結關係的寫法是把網址和對應的處理函式作為引數傳給 url 函式(第一個引數是網址,第二個引數是處理函式),另外我們還傳遞了另外一個引數 name,這個引數的值將作為處理函式 index 的別名,這在以後會用到。

注意這裡我們的網址是用正則表示式寫的,django 會用這個正則表示式去匹配使用者實際輸入的網址,如果匹配成功,就會呼叫其後面的檢視函式做相應的處理。比如說我們本地開發伺服器的域名是 127.0.0.1:8000,那麼當用戶輸入網址:127.0.0.1:8000 後,django 首先會把域名(即 127.0.0.1)和埠號(8000)去掉,此時只剩下一個空字串,而 r’^$’ 的模式正是匹配一個空字串(這個正則表示式的意思是以空字串開頭且以空字串結尾),於是二者匹配,django 便會呼叫其對應的 views.index 函式。

第二步就是要實際編寫我們的 views.index 檢視函數了,按照慣例檢視函式定義在 views.py 檔案裡:

blog/views.py

from django.http import HttpResponse

def index(request):
return HttpResponse(“歡迎訪問我的部落格首頁!”)
我們前面說過,Web 伺服器的作用就是接收來自使用者的 http 請求,根據請求內容作出相應的處理,並把處理結果包裝成 http 響應返回給使用者。這個兩行的函式體現了這個過程。它首先接受了一個名為 request 的引數,這個 request 就是 django 為我們封裝好的 http 請求,它是類 HttpResponse 的一個例項。然後我們便直接返回了一個 http 響應給使用者,這個 http 響應也是 django 幫我們封裝好的,它是類 HttpResponse 的一個例項,只是我們給它傳了一個自定義的字串,使用者接受到這個響應後就會在瀏覽器顯示出我們傳遞的內容:“歡迎訪問我的部落格首頁!”

還差最後一步了,我們前面建立了一個 urls.py 檔案,並且綁定了 URL 和檢視函式 index,但是 django 並不知道。django 匹配 url 是在 blogproject 的 urls.py 下的,所以我們要把我們自己寫的 urls.py 檔案包含到這個檔案裡去,開啟這個檔案看到如下內容:

“”"
一大段註釋
“”"

from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
url(r’^admin/’, admin.site.urls),
]
修改成如下的形式:

  • from django.conf.urls import url
  • from django.conf.urls import url, include
    from django.contrib import admin

urlpatterns = [
url(r’^admin/’, admin.site.urls),

  • url(r’’, include(‘blog.urls’)),
    ]
    這裡 - 表示刪掉這一行,+ 表示新增這一行。我們這裡匯入了一個 include 函式,然後利用這個函式把 blog 應用下的 urls.py 包含了進來。此外 include 前還有一個 r’’,這是一個空字串,這裡也可以寫其他字串,django 會把這個字串和後面 include 的 urls.py 檔案中的 url 拼接。假如我們這裡把 r’’ 改成 r’blog/’,而我們在 blog.urls 中寫的url 是 r’^$’,一個空字串,那麼 django 最終匹配的就是 blog/ 加上一個空字串,即 blog/。

執行 python manage.py runserver 開啟開發伺服器,在瀏覽器輸入開發伺服器的地址 http://127.0.0.1:8000/,可以看到我們返回的內容了:歡迎訪問我的部落格首頁!

這基本上就上 django 的開發流程了,寫好處理 http 請求和返回 http 響應的檢視函式,然後把檢視函式繫結到相應的 URL 上。但是等一等!我們看到在我們的檢視函式裡返回的是一個 HttpResponse 類的例項,我們給他傳入了一個我們希望顯示在使用者瀏覽器上的字串。但是我們的部落格不可能只顯示這麼一句話,它有可能會顯示很長很長的內容,比如我們釋出的部落格文章列表,或者一大段的部落格文章,我們不能每次都把這些大段大段的內容傳給 HttpResponse。於是 django 對這個問題給我們提供了一個好的方法,叫做模板系統。django 要我們把大段的文字寫到一個檔案裡,然後 django 自己會去讀取這個檔案,django 再把讀取到的內容傳給 HttpResponse。我們用模板系統來改造一下上面的例子。首先在我們的專案根目錄下建立一個名為 templates 的資料夾,用來存放我們的模板。然後再建立一個名為 blog 的資料夾,用來存放和 blog 應用相關的模板。當然模板存放在哪裡是無關緊要的,只要 django 能夠找到的就好。但是我們建立這樣的資料夾結構的目的是把不同應用用到的模板隔離開來,這樣方便以後維護,養成良好的習慣。然後我們在 blog 目錄下建立一個名為 index.html 的檔案,寫上下面的程式碼:

{{ title }}

{{ welcome }}

這是一個標準的 html 文件了,只是裡面有兩個比較奇怪的地方:{{ title }},{{ welcome }},這是 django 規定的語法。用 {{ }} 包起來的叫做模板變數。django 在讀取這個模板的時候回根據我們傳來值替換這些變數。最終在模板中顯示的將會是我們傳遞的值。

模板寫好了,還得告訴 django 去哪裡找模板,在 settings.py 檔案裡設定一下模板檔案所在的路徑。在 settings.py 找到 TEMPLATES 選項,它的內容是這樣的:

blogproject/settings.py

TEMPLATES = [
{
‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’,
‘DIRS’: [],
‘APP_DIRS’: True,
‘OPTIONS’: {
‘context_processors’: [
‘django.template.context_processors.debug’,
‘django.template.context_processors.request’,
‘django.contrib.auth.context_processors.auth’,
‘django.contrib.messages.context_processors.messages’,
],
},
},
]
其中 DIRS 就是設定模板的路徑,在 [] 中寫入 os.path.join(BASE_DIR, ‘templates’),變成這樣:

blogproject/settings.py

TEMPLATES = [
{

‘DIRS’: [os.path.join(BASE_DIR, ‘templates’)],

},
]
這裡 BASE_DIR 是 settings.py 前面定義的變數,記錄的是工程根目錄 blogproject 的值,在這個目錄下有我們的模板目錄 templates,於是利用os.path.join 把這兩個路徑連起來,構成完整的模板路徑,django 就知道去這個路徑下面找我們的模板了。

檢視函式可以改一下了:

blog/views.py

from django.http import HTTPResponse
from django.shrotcuts import render

def index(request):
return render(request, ‘blog/index.html’, context={
‘title’: ‘我的部落格首頁’,
‘welcome’: ‘歡迎訪問我的部落格首頁’
})

這裡我們在是直接把字串傳給 HttpResponse 了,而是呼叫 django 提供了 render 函式,這個函式根據我們傳入的引數來構造 HttpResponse。我們首先把 http 請求傳了進去,然後它根據第二個引數的值 blog/index.html 找到我們的模板,然後讀取模板中的內容,並且根據我們傳入的 context 把模板中的變數替換為我們傳遞的值,{{ title }} 被替換成了 context 字典中 title 對應的值,同理 {{ welcome }} 也被替換成相應的值。最終,我們的 html 模板中的內容字串被傳遞給 HttpResponse 物件並返回給瀏覽器,這樣使用者的瀏覽器上便顯示出了我們寫的 html 模板的內容。