文中涉及的示例代碼,已同步更新到 HelloGitHub-Team 倉庫css
在此以前咱們已經編寫了博客的首頁視圖,而且配置了 URL 和模板,讓 django 可以正確地處理 HTTP 請求並返回合適的 HTTP 響應。不過咱們僅僅在首頁返回了一句話:「歡迎訪問個人博客「,這是個 Hello World 級別的視圖函數,毫無美感。html
這篇文章咱們須要編寫真正的首頁視圖函數,當用戶訪問咱們的博客首頁時,他將看到咱們發表的博客文章列表,就像 演示項目 裏展現的這樣。python
上一節咱們闡明瞭 django 的開發流程。即首先配置 URL,把 URL 和相應的視圖函數綁定,通常寫在 urls.py 文件裏,而後在工程的 urls.py 文件引入。其次是編寫視圖函數,視圖中須要渲染模板,咱們也在 settings.py 中進行了模板相關的配置,讓 django 可以找到須要渲染的模板。最後把渲染完成的 HTTP 響應返回就能夠了。相關的配置和準備工做都在以前完成了,這裏咱們只需專心編寫視圖函數,讓它實現咱們想要的功能便可。jquery
首頁的視圖函數其實很簡單,代碼像這樣:git
blog/views.py
from django.shortcuts import render
from .models import Post
def index(request):
post_list = Post.objects.all().order_by('-created_time')
return render(request, 'blog/index.html', context={'post_list': post_list})
複製代碼
咱們曾經在前面的章節講解過模型管理器 objects
的使用。這裏咱們使用 all()
方法從數據庫裏獲取了所有的文章,存在了 post_list
變量裏。all
方法返回的是一個 QuerySet
(能夠理解成一個相似於列表的數據結構),因爲一般來講博客文章列表是按文章發表時間倒序排列的,即最新的文章排在最前面,因此咱們緊接着調用了 order_by
方法對這個返回的 queryset 進行排序。排序依據的字段是 created_time
,即文章的建立時間。-
號表示逆序,若是不加 -
則是正序。 接着如以前所作,咱們渲染了 blog\index.html 模板文件,而且把包含文章列表數據的 post_list
變量傳給了模板。github
咱們的項目使用了從網上下載的一套博客模板(點擊這裏下載全套模板)。這裏面除了 HTML 文檔外,還包含了一些 CSS 文件和 JavaScript 文件以讓網頁呈現出咱們如今看到的樣式。一樣咱們須要對 django 作一些必要的配置,才能讓 django 知道如何在開發服務器中引入這些 CSS 和 JavaScript 文件,這樣才能讓博客頁面的 CSS 樣式生效。數據庫
按照慣例,咱們把 CSS 和 JavaScript 文件放在 blog 應用的 static\ 目錄下。所以,先在 blog 應用下創建一個 static 文件夾。同時,爲了不和其它應用中的 CSS 和 JavaScript 文件命名衝突(別的應用下也可能有和 blog 應用下同名的 CSS 、JavaScript 文件),咱們再在 static\ 目錄下創建一個 blog 文件夾,把下載的博客模板中的 css 和 js 文件夾連同裏面的所有文件一同拷貝進這個目錄。最終咱們的 blog 應用目錄結構應該是這樣的:django
blog\
__init__.py
static\
blog\
css\
.css 文件...
js\
.js 文件...
admin.py
apps.py
migrations\
__init__.py
models.py
tests.py
views.py
複製代碼
用下載的博客模板中的 index.html 文件替換掉以前咱們本身寫的 index.html 文件。若是你好奇,如今就能夠運行開發服務器,看看首頁是什麼樣子。bootstrap
如圖所示,你會看到首頁顯示的樣式很是混亂,緣由是瀏覽器沒法正確加載 CSS 等樣式文件。須要以 django 的方式來正確地處理 CSS 和 JavaScript 等靜態文件的加載路徑。CSS 樣式文件一般在 HTML 文檔的 head 標籤裏引入,打開 index.html 文件,在文件的開始處找到 head 標籤包裹的內容,大概像這樣:瀏覽器
templates/blog/index.html
<!DOCTYPE html>
<html>
<head>
<title>Black & White</title>
<!-- meta -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- css -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<link rel="stylesheet" href="css/pace.css">
<link rel="stylesheet" href="css/custom.css">
<!-- js -->
<script src="js/jquery-2.1.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/pace.min.js"></script>
<script src="js/modernizr.custom.js"></script>
</head>
<body>
<!-- 其它內容 -->
<script src="js/script.js"></script>
</body>
</html>
複製代碼
CSS 樣式文件的路徑在 link 標籤的 href 屬性裏,而 JavaScript 文件的路徑在 script 標籤的 src 屬性裏。能夠看到諸如 `href="css/bootstrap.min.css" 或者 src="js/jquery-2.1.3.min.js" 這樣的引用,因爲引用文件的路徑不對,因此瀏覽器引入這些文件失敗。咱們須要把它們改爲正確的路徑。把代碼改爲下面樣子,正確地引入 static 文件下的 CSS 和 JavaScript 文件:
templates/blog/index.html
+ {% load static %}
<!DOCTYPE html>
<html>
<head>
<title>Black & White</title>
<!-- meta -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- css -->
- <link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
- <link rel="stylesheet" href="css/pace.css">
- <link rel="stylesheet" href="css/custom.css">
+ <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
+ <link rel="stylesheet" href="{% static 'blog/css/pace.css' %}">
+ <link rel="stylesheet" href="{% static 'blog/css/custom.css' %}">
<!-- js -->
- <script src="js/jquery-2.1.3.min.js"></script>
- <script src="js/bootstrap.min.js"></script>
- <script src="js/pace.min.js"></script>
- <script src="js/modernizr.custom.js"></script>
+ <script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script>
+ <script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
+ <script src="{% static 'blog/js/pace.min.js' %}"></script>
+ <script src="{% static 'blog/js/modernizr.custom.js' %}"></script>
</head>
<body>
<!-- 其它內容 -->
- <script src="js/script.js' %}"></script>
+ <script src="{% static 'blog/js/script.js' %}"></script>
</body>
</html>
複製代碼
這裏 - 表示刪掉這一行,而 + 表示增長這一行。(增長了哪些內容看仔細一點,千萬別漏掉)
咱們把引用路徑放在了一個奇怪的符號裏,例如:href="{% static 'blog/css/bootstrap.min.css' %}"。用 {% %} 包裹起來的叫作模板標籤。咱們前面說過用 {{ }} 包裹起來的叫作模板變量,其做用是在最終渲染的模板裏顯示由視圖函數傳過來的變量值。而這裏咱們使用的模板標籤的功能則相似於函數,例如這裏的 static
模板標籤,它把跟在後面的字符串 'css/bootstrap.min.css'
轉換成正確的文件引入路徑。這樣 css 和 js 文件才能被正確加載,樣式才能正常顯示。
注意:
爲了能在模板中使用 {% static %} 模板標籤,別忘了在最頂部 {% load static %} 。static 模板標籤位於 static模塊中,只有經過 load 模板標籤將該模塊引入後,才能在模板中使用 {% static %} 標籤。
替換完成後你能夠刷新頁面並看看網頁的源代碼,看一看 {% static %} 模板標籤在頁面渲染後究竟被替換成了什麼樣的值。例如咱們能夠看到
<link rel="stylesheet" href="{% static 'blog/css/pace.css' %}">
複製代碼
這一部分最終在瀏覽器中顯示的是:
<link rel="stylesheet" href="/static/blog/css/pace.css">
複製代碼
這正是 pace.css 文件所在的路徑,其它的文件路徑也被相似替換。能夠看到 {% static %} 標籤的做用實際就是把後面的字符串加了一個 /static/ 前綴,好比 {% static 'blog/css/pace.css' %}
最終渲染的值是 /static/blog/css/pace.css
。而 /static/ 前綴是咱們在 settings.py 文件中經過 STATIC_URL = '/static/'
指定的。事實上,若是咱們直接把引用路徑寫成 /static/blog/css/pace.css
也是能夠的,那麼爲何要使用 {% static %} 標籤呢?想一下,目前 URL 的前綴是 /static/,若是哪一天由於某些緣由,咱們須要把 /static/ 改爲 /resource/,若是你是直接寫的引用路勁而沒有使用 static 模板標籤,那麼你可能須要改 N 個地方。若是你使用了 static 模板標籤,那麼只要在 settings.py 處改一個地方就能夠了,即把 STATIC_URL = '/static/'
改爲 STATIC_URL = '/resource/'
。
提示
有時候按 F5 刷新後頁面仍是很亂,這多是由於瀏覽器緩存了以前的結果。按 Shift + F5(有些瀏覽器多是 Ctrl + F5)強制刷新瀏覽器頁面便可。若是仍是不行,重啓一下開發服務器以及清除瀏覽器緩存。
注意這裏有一個 CSS 文件的引入
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
複製代碼
咱們沒有使用模板標籤,由於這裏的引用的文件是一個外部文件,不是咱們項目裏 static\blog\css\ 目錄下的文件,所以無需使用模板標籤。
正確引入了靜態文件後樣式顯示正常了。
目前咱們看到的只是模板中預先填充的一些數據,咱們得讓它顯示從數據庫中獲取的文章數據。下面來稍微改造一下模板:
在模板 index.html 中你會找到一系列 article 標籤:
templates/blog/index.html
...
<article class="post post-1">
...
</article>
<article class="post post-2">
...
</article>
<article class="post post-3">
...
</article>
...
複製代碼
這裏麪包裹的內容顯示的就是文章數據了。咱們前面在視圖函數 index 裏給模板傳了一個 post_list
變量,它裏面包含着從數據庫中取出的文章列表數據。就像 Python 同樣,咱們能夠在模板中循環這個列表,把文章一篇篇循環出來,而後一篇篇顯示文章的數據。要在模板中使用循環,須要使用到前面提到的模板標籤,此次使用 {% for %} 模板標籤。將 index.html 中多餘的 article 標籤刪掉,只留下一個 article 標籤,而後寫上下列代碼:
templates/blog/index.html
...
{% for post in post_list %}
<article class="post post-{{ post.pk }}">
...
</article>
{% empty %}
<div class="no-post">暫時尚未發佈的文章!</div>
{% endfor %}
...
複製代碼
能夠看到語法和 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 顯示的是文章的標題,
<h1 class="entry-title">
<a href="single.html">Adaptive Vs. Responsive Layouts And Optimal Text Readability</a>
</h1>
複製代碼
咱們把標題替換成 post
的 title
屬性值。注意要把它包裹在模板變量裏,由於它最終要被替換成實際的 title 值。
<h1 class="entry-title">
<a href="single.html">{{ post.title }}</a>
</h1>
複製代碼
下面這 5 個 span 標籤裏分別顯示了分類(category)、文章發佈時間、文章做者、評論數、閱讀量。
<div class="entry-meta">
<span class="post-category"><a href="#">django 博客教程</a></span>
<span class="post-date"><a href="#"><time class="entry-date" datetime="2012-11-09T23:15:57+00:00">2017年5月11日</time></a></span>
<span class="post-author"><a href="#">追夢人物</a></span>
<span class="comments-link"><a href="#">4 評論</a></span>
<span class="views-count"><a href="#">588 閱讀</a></span>
</div>
複製代碼
再次替換掉一些數據,因爲評論數和閱讀量暫時無法替換,所以先留着,咱們在以後實現了這些功能後再來修改它,目前只替換分類、文章發佈時間、文章做者:
<div class="entry-meta">
<span class="post-category"><a href="#">{{ post.category.name }}</a></span>
<span class="post-date"><a href="#"><time class="entry-date" datetime="{{ post.created_time }}">{{ post.created_time }}</time></a></span>
<span class="post-author"><a href="#">{{ post.author }}</a></span>
<span class="comments-link"><a href="#">4 評論</a></span>
<span class="views-count"><a href="#">588 閱讀</a></span>
</div>
複製代碼
這裏 p 標籤裏顯示的是摘要
<div class="entry-content clearfix">
<p>免費、中文、零基礎,完整的項目,基於最新版 django 1.10 和 Python 3.5。帶你從零開始一步步開發屬於本身的博客網站,幫助你以最快的速度掌握 django
開發的技巧...</p>
<div class="read-more cl-effect-14">
<a href="#" class="more-link">繼續閱讀 <span class="meta-nav">→</span></a>
</div>
</div>
複製代碼
替換成 post
的摘要:
<div class="entry-content clearfix">
<p>{{ post.excerpt }}</p>
<div class="read-more cl-effect-14">
<a href="#" class="more-link">繼續閱讀 <span class="meta-nav">→</span></a>
</div>
</div>
複製代碼
再次訪問首頁,它顯示:暫時尚未發佈的文章!好吧,作了這麼多工做,可是數據庫中其實尚未任何數據呀!接下來咱們就實際寫幾篇文章保存到數據庫裏,看看顯示的效果究竟如何。