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