在此之前我們已經編寫了 Blog 的首頁視圖,并且配置了 URL 和模板,讓 Django 能夠正確地處理 HTTP 請求并返回合適的 HTTP 響應。不過僅僅在首頁返回了一句話:訪問我的第一個博客首頁。這是個 Hello World 級別的視圖函數,我們需要編寫真正的首頁視圖函數,當用戶訪問博客首頁時,他將看到我們發表的博客文章列表。
首頁視圖函數
上一節闡明了 Django 的開發流程。即首先配置 URL,把 URL 和相應的視圖函數綁定,一般寫在 urls.py 文件里,然后在工程的 urls.py 文件引入。其次是編寫視圖函數,視圖中需要渲染模板,我們也在 settings.py 中進行了模板相關的配置,讓 Django 能夠找到需要渲染的模板。最后把渲染完成的 HTTP 響應返回就可以了。相關的配置和準備工作都在之前完成了,這里只需專心編寫視圖函數,讓它實現我們想要的功能即可。
首頁的視圖函數其實很簡單,代碼像這樣:
在前面講解過模型管理器objects的使用。這里使用all()方法從數據庫里獲取了全部的文章,存在了post_list變量里。all方法返回的是一個QuerySet(可以理解成一個類似于列表的數據結構),由于通常來說博客文章列表是按文章發表時間倒序排列的,即最新的文章排在最前面,所以緊接著調用了order_by方法對這個返回的 queryset 進行排序。排序依據的字段是created_time,即文章的創建時間。-號表示逆序,如果不加-則是正序。 接著如之前所做,渲染了 blog\index.html 模板文件,并且把包含文章列表數據的post_list變量傳給了模板。
處理靜態文件
項目使用了從網上下載的一套博客模板,這里面除了 HTML 文檔外,還包含了一些 CSS 文件和 JavaScript 文件以讓網頁呈現出我們現在看到的樣式。同樣需要對 Django 做一些必要的配置,才能讓 Django 知道如何在開發服務器中引入這些 CSS 和 JavaScript 文件,這樣才能讓博客頁面的 CSS 樣式生效。
按照慣例,把 CSS 和 JavaScript 文件放在blog 應用的 static\ 目錄下。因此,先在blog 應用下建立一個 static 文件夾。同時,為了避免和其它應用中的 CSS 和 JavaScript 文件命名沖突(別的應用下也可能有和 blog 應用下同名的 CSS 、JavaScript 文件),我們再在 static\ 目錄下建立一個 blog 文件夾,把下載的博客模板中的 css 和 js 文件夾連同里面的全部文件一同拷貝進這個目錄。最終我們的 blog 應用目錄結構應該是這樣的:
用下載的博客模板中的 index.html 文件替換掉之前我們自己寫的 index.html 文件。如果你好奇,現在就可以運行開發服務器,看看首頁是什么樣子。
如圖所示,你會看到首頁顯示的樣式非常混亂,原因是瀏覽器無法正確加載 CSS 等樣式文件。需要以 Django 的方式來正確地處理 CSS 和 JavaScript 等靜態文件的加載路徑。CSS 樣式文件通常在 HTML 文檔的 head 標簽里引入,打開 index.html 文件,在文件的開始處找到 head 標簽包裹的內容,大概像這樣:
CSS 樣式文件的路徑在 link 標簽的 href 屬性里,而 JavaScript 文件的路徑在 script 標簽的 src 屬性里。可以看到諸如 `href="css/bootstrap.min.css" 或者 src="js/jquery-2.1.3.min.js" 這樣的引用,由于引用文件的路徑不對,所以瀏覽器引入這些文件失敗。需要把它們改成正確的路徑。把代碼改成下面樣子,正確地引入 static 文件下的 CSS 和 JavaScript 文件:
把引用路徑放在了一個奇怪的符號里,例如:href="{% static 'blog/css/bootstrap.min.css' %}"。用 {% %} 包裹起來的叫做模板標簽。前面說過用 {{ }} 包裹起來的叫做模板變量,其作用是在最終渲染的模板里顯示由視圖函數傳過來的變量值。而這里使用的模板標簽的功能則類似于函數,例如這里的static模板標簽,它把跟在后面的字符串'css/bootstrap.min.css'轉換成正確的文件引入路徑。這樣 css 和 js 文件才能被正確加載,樣式才能正常顯示。
替換完成后你可以刷新頁面并看看網頁的源代碼,看一看 {% static %} 模板標簽在頁面渲染后究竟被替換成了什么樣的值。例如可以看到
正確引入了靜態文件后樣式顯示正常了。
修改模板
目前看到的只是模板中預先填充的一些數據,我們得讓它顯示從數據庫中獲取的文章數據。下面來稍微改造一下模板:
在模板 index.html 中你會找到一系列 article 標簽:
這里面包裹的內容顯示的就是文章數據了。我們前面在視圖函數 index 里給模板傳了一個post_list變量,它里面包含著從數據庫中取出的文章列表數據。就像 Python 一樣,可以在模板中循環這個列表,把文章一篇篇循環出來,然后一篇篇顯示文章的數據。要在模板中使用循環,需要使用到前面提到的模板標簽,這次使用 {% for %} 模板標簽。將 index.html 中多余的 article 標簽刪掉,只留下一個 article 標簽,然后寫上下列代碼:
可以看到語法和 Python 的 for 循環類似,只是被 {% %} 這樣一個模板標簽符號包裹著。{% empty %} 的作用是當post_list為空,即數據庫里沒有文章時顯示 {% empty %} 下面的內容,最后我們用 {% endfor %} 告訴 Django 循環在這里結束了。
你可能不太理解模板中的post和post_list是什么。post_list是一個QuerySet(類似于一個列表的數據結構),其中每一項都是之前定義在 blog\models.py 中的 Post 類的實例,且每個實例分別對應著數據庫中每篇文章的記錄。因此我們循環遍歷post_list,每一次遍歷的結果都保存在post變量里。所以使用模板變量來顯示post的屬性值。例如這里的{{ post.pk }}(pk 是 primary key 的縮寫,即 post 對應于數據庫中記錄的 id 值,該屬性盡管我們沒有顯示定義,但是 Django 會自動為我們添加)。
現在可以在循環體內通過post變量訪問單篇文章的數據了。分析 article 標簽里面的 HTML 內容,h1 顯示的是文章的標題,把標題替換成post的title屬性值。注意要把它包裹在模板變量里,因為它最終要被替換成實際的 title 值。
下面這 5 個 span 標簽里分別顯示了分類(category)、文章發布時間、文章作者、評論數、閱讀量。再次替換掉一些數據,由于評論數和閱讀量暫時沒法替換,因此先留著,我們在之后實現了這些功能后再來修改它,目前只替換分類、文章發布時間、文章作者:
這里 p 標簽里顯示的是摘要,替換成post的摘要:
再次訪問首頁,它顯示:暫時還沒有發布的文章!做了這么多工作,但是數據庫中其實還沒有任何數據呀!接下來就實際寫幾篇文章保存到數據庫里,看看顯示的效果究竟如何。