文中涉及的示例代碼,已同步更新到 HelloGitHub-Team 倉庫
Web 服務簡單的說就是處理請求,每一個請求就像是一個「顧客」。首先熱情地把顧客迎接進來,而後知足用戶的個性化需求,最後讓顧客心滿意足的離開。Django 做爲一個 web 框架,可以讓開發者有更多的精力和時間去應付複雜多變的需求,而不是把時間花費在招店小2、作飯的廚子、服務員等。那麼下面咱們就來看看 Django 的接客之道吧。html
Web 應用的交互過程其實就是 HTTP 請求與響應的過程。不管是在 PC 端仍是移動端,咱們一般使用瀏覽器來上網,上網流程大體來講是這樣的:python
所以,django 做爲一個 Web 框架,它的使命就是處理流程中的第二步。即接收瀏覽器發來的 HTTP 請求,返回相應的 HTTP 響應。因而引出這麼幾個問題:git
對於如何處理這些問題,django 有其一套規定的機制。咱們按照 django 的規定,就能開發出所需的功能。github
咱們先以一個最簡單的 Hello World 爲例來看看 django 處理上述問題的機制是怎麼樣的。web
首先 django 須要知道當用戶訪問不一樣的網址時,應該如何處理這些不一樣的網址(即所說的路由)。django 的作法是把不一樣的網址對應的處理函數寫在一個 urls.py 文件裏,當用戶訪問某個網址時,django 就去會這個文件裏找,若是找到這個網址,就會調用和它綁定在一塊兒的處理函數(叫作視圖函數)。數據庫
下面是具體的作法,首先在 blog 應用的目錄下建立一個 urls.py 文件,這時你的目錄看起來是這樣:django
blog\ __init__.py admin.py apps.py migrations\ 0001_initial.py __init__.py models.py tests.py views.py urls.py
在 blogurls.py 中寫入這些代碼:瀏覽器
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
咱們首先從 django.urls 導入了 path
函數,又從當前目錄下導入了 views 模塊。而後咱們把網址和處理函數的關係寫在了 urlpatterns
列表裏。服務器
綁定關係的寫法是把網址和對應的處理函數做爲參數傳給 path
函數(第一個參數是網址,第二個參數是處理函數),另外咱們還傳遞了另一個參數 name
,這個參數的值將做爲處理函數 index
的別名,這在之後會用到。app
注意這裏咱們的網址其實是一個規則,django 會用這個規則去匹配用戶實際輸入的網址,若是匹配成功,就會調用其後面的視圖函數作相應的處理。
好比說咱們本地開發服務器的域名是 http://127.0.0.1:8000,那麼當用戶輸入網址 http://127.0.0.1:8000 後,django 首先會把協議 http、域名 127.0.0.1 和端口號 8000 去掉,此時只剩下一個空字符串,而 ''
的模式正是匹配一個空字符串,因而兩者匹配,django 便會調用其對應的 views.index
函數。
注意在 blogproject 目錄下(即 settings.py 所在的目錄),本來就有一個 urls.py 文件,這是整個工程項目的 URL 配置文件。而咱們這裏新建了一個 urls.py 文件,且位於 blog 應用下。這個文件將用於 blog 應用相關的 URL 配置,這樣便於模塊化管理。不要把兩個文件搞混了。
第二步就是要實際編寫咱們的 views.index
視圖函數了,按照慣例視圖函數定義在 views.py 文件裏:
blog/views.py from django.http import HttpResponse def index(request): return HttpResponse("歡迎訪問個人博客首頁!")
咱們前面說過,Web 服務器的做用就是接收來自用戶的 HTTP 請求,根據請求內容做出相應的處理,並把處理結果包裝成 HTTP 響應返回給用戶。
這個兩行的函數體現了這個過程。它首先接受了一個名爲 request
的參數,這個 request
就是 django 爲咱們封裝好的 HTTP 請求,它是類 HttpRequest
的一個實例。而後咱們便直接返回了一個 HTTP 響應給用戶,這個 HTTP 響應也是 django 幫咱們封裝好的,它是類 HttpResponse
的一個實例,只是咱們給它傳了一個自定義的字符串參數。
瀏覽器接收到這個響應後就會在頁面上顯示出咱們傳遞的內容 :歡迎訪問個人博客首頁!
還差最後一步了,咱們前面創建了一個 urls.py 文件,而且綁定了 URL 和視圖函數 index
,可是 django 並不知道。django 匹配 URL 模式是在 blogproject 目錄(即 settings.py 文件所在的目錄)的 urls.py 下的,因此咱們要把 blog 應用下的 urls.py 文件包含到 blogprojecturls.py 裏去,打開這個文件看到以下內容:
blogproject/urls.py """ 一大段註釋 """ from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.site.urls), ]
修改爲以下的形式:
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('blog.urls')), ]
咱們這裏導入了一個 include
函數,而後利用這個函數把 blog 應用下的 urls.py 文件包含了進來。此外 include 前還有一個 ''
,這是一個空字符串。這裏也能夠寫其它字符串,django 會把這個字符串和後面 include 的 urls.py 文件中的 URL 拼接。好比說若是咱們這裏把 ''
改爲 'blog/'
,而咱們在 blogurls.py 中寫的 URL 是 ''
,即一個空字符串。那麼 django 最終匹配的就是 blog/ 加上一個空字符串,即 blog/。
運行 pipenv run python manage.py runserver
打開開發服務器,在瀏覽器輸入開發服務器的地址 http://127.0.0.1:8000/,能夠看到 django 返回的內容了。
歡迎訪問個人博客首頁!
這基本上就上 django 的開發流程了,寫好處理 HTTP 請求和返回 HTTP 響應的視圖函數,而後把視圖函數綁定到相應的 URL 上。
可是等一等!咱們看到在視圖函數裏返回的是一個 HttpResponse
類的實例,咱們給它傳入了一個但願顯示在用戶瀏覽器上的字符串。可是咱們的博客不可能只顯示這麼一句話,它有可能會顯示很長很長的內容。好比咱們發佈的博客文章列表,或者一大段的博客文章。咱們不能每次都把這些大段大段的內容傳給 HttpResponse
。
django 對這個問題給咱們提供了一個很好的解決方案,叫作模板系統。django 要咱們把大段的文本寫到一個文件裏,而後 django 本身會去讀取這個文件,再把讀取到的內容傳給 HttpResponse
。讓咱們用模板系統來改造一下上面的例子。
首先在咱們的項目根目錄(即 manage.py 文件所在目錄)下創建一個名爲 templates 的文件夾,用來存放咱們的模板。而後在 templates 目錄下創建一個名爲 blog 的文件夾,用來存放和 blog 應用相關的模板。
固然模板存放在哪裏是可有可無的,只要 django 可以找到的就好。可是咱們創建這樣的文件夾結構的目的是把不一樣應用用到的模板隔離開來,這樣方便之後維護。咱們在 templatesblog 目錄下創建一個名爲 index.html 的文件,此時你的目錄結構應該是這樣的:
HelloDjango-blog-tutorial\ manage.py ... templates\ blog\ index.html
注意再一次強調 templates 目錄位於項目根目錄,而 index.html 位於 templatesblog 目錄下,而不是 blog 應用下,若是弄錯了你可能會獲得一個
TemplateDoesNotExist
異常。若是遇到這個異常,請回來檢查一下模板目錄結構是否正確。
在 templatesblogindex.html 文件裏寫入下面的代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ title }}</title> </head> <body> <h1>{{ welcome }}</h1> </body> </html>
這是一個標準的 HTML 文檔,只是裏面有兩個比較奇怪的地方:{{ title }}
,{{ welcome }}
。這是 django 規定的語法。用 {{ }} 包起來的變量叫作模板變量。django 在渲染這個模板的時候會根據咱們傳遞給模板的變量替換掉這些變量。最終在模板中顯示的將會是咱們傳遞的值。
注意:index.html 必須以 UTF-8 的編碼格式保存,且當心不要往裏面添加一些特殊字符,不然極有可能獲得一個
UnicodeDecodeError
這樣的錯誤。
模板寫好了,還得告訴 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 在配置開頭前面定義的變量,記錄的是工程根目錄 HelloDjango-blog-tutorial 的值。在這個目錄下有模板文件所在的目錄 templates,因而利用os.path.join
把這兩個路徑連起來,構成完整的模板路徑,django 就知道去這個路徑下面找咱們的模板了。
視圖函數能夠改一下了:
blog/views.py from django.shortcuts import render def index(request): return render(request, 'blog/index.html', context={ 'title': '個人博客首頁', 'welcome': '歡迎訪問個人博客首頁' })
這裏咱們再也不是直接把字符串傳給 HttpResponse
了,而是調用 django 提供的 render
函數。這個函數根據咱們傳入的參數來構造 HttpResponse
。
咱們首先把 HTTP 請求傳了進去,而後 render
根據第二個參數的值 blog/index.html 找到這個模板文件並讀取模板中的內容。以後 render
根據咱們傳入的 context
參數的值把模板中的變量替換爲咱們傳遞的變量的值,{{ title }}
被替換成了 context
字典中 title
對應的值,同理 {{ welcome }}
也被替換成相應的值。
最終,咱們的 HTML 模板中的內容字符串被傳遞給 HttpResponse
對象並返回給瀏覽器(django 在 render
函數裏隱式地幫咱們完成了這個過程),這樣用戶的瀏覽器上便顯示出了咱們寫的 HTML 模板的內容了。