Django 教程第五部分:建立我們的主頁
我們現在準備新增程式碼,以顯示我們的第一個完整頁面——一個用於 LocalLibrary 網站的主頁。主頁將顯示每種模型型別的記錄數量,並提供側邊欄導航連結到我們的其他頁面。在此過程中,我們將獲得編寫基本 URL 對映和檢視、從資料庫獲取記錄以及使用模板的實踐經驗。
| 預備知識 | 閱讀 Django 簡介。完成之前的教程主題(包括 Django 教程第四部分:Django 管理站點)。 |
|---|---|
| 目標 | 學習建立簡單的 URL 對映和檢視(URL 中沒有編碼資料),從模型中獲取資料,並建立模板。 |
概述
在定義了模型並建立了一些初始庫記錄之後,是時候編寫程式碼來向用戶展示這些資訊了。我們需要做的第一件事是確定我們想要在頁面中顯示哪些資訊,並定義用於返回這些資源的 URL。然後,我們將建立 URL 對映器、檢視和模板來顯示頁面。
以下圖表描述了主資料流以及處理 HTTP 請求和響應時所需的元件。由於我們已經實現了模型,我們將建立的主要元件是:
- URL 對映器,用於將支援的 URL(以及 URL 中編碼的任何資訊)轉發到適當的檢視函式。
- 檢視函式,用於從模型中獲取請求的資料,建立顯示資料的 HTML 頁面,並將頁面返回給使用者以在瀏覽器中檢視。
- 在檢視中渲染資料時使用的模板。

正如您在下一節中看到的,我們有 5 個頁面要顯示,這對於一篇單獨的文章來說資訊量太大了。因此,本文將重點介紹如何實現主頁,我們將在後續文章中介紹其他頁面。這應該能讓您對 URL 對映器、檢視和模型在實踐中如何工作有一個良好的端到端理解。
定義資源 URL
由於此版本的 LocalLibrary 對終端使用者來說基本上是隻讀的,我們只需要為網站提供一個登入頁(主頁),以及用於顯示圖書和作者的列表和詳細檢視的頁面。
我們的頁面所需的 URL 是:
catalog/— 主頁(索引)頁。catalog/books/— 所有圖書的列表。catalog/authors/— 所有作者的列表。catalog/book/<id>— 特定圖書的詳細檢視,其主鍵欄位為<id>(預設)。例如,新增到列表中的第三本書的 URL 將是/catalog/book/3。catalog/author/<id>— 具有主鍵欄位<id>的特定作者的詳細檢視。例如,新增到列表中的第 11 位作者的 URL 將是/catalog/author/11。
前三個 URL 將返回索引頁、圖書列表和作者列表。這些 URL 不編碼任何額外資訊,從資料庫獲取資料的查詢將始終相同。但是,查詢返回的結果將取決於資料庫的內容。
相比之下,最後兩個 URL 將顯示特定圖書或作者的詳細資訊。這些 URL 編碼了要顯示的專案標識(如上所示,用 <id> 表示)。URL 對映器將提取編碼資訊並將其傳遞給檢視,檢視將動態地確定從資料庫獲取哪些資訊。透過在 URL 中編碼資訊,我們將使用一套 URL 對映、一個檢視和一個模板來處理所有圖書(或作者)。
注意:使用 Django,您可以根據需要構建您的 URL——您可以在 URL 正文中編碼資訊,如上所示,或者在 URL 中包含 GET 引數,例如 /book/?id=6。無論您使用哪種方法,URL 都應保持清晰、邏輯和可讀,正如 W3C 所建議的。Django 文件建議在 URL 正文中編碼資訊以實現更好的 URL 設計。
正如概述中提到的,本文的其餘部分將描述如何構建索引頁。
建立索引頁
我們將建立的第一個頁面是索引頁(catalog/)。索引頁將包含一些靜態 HTML,以及資料庫中不同記錄的生成“計數”。為了實現這一點,我們將建立一個 URL 對映、一個檢視和一個模板。
注意:本節值得多加關注。大部分資訊也適用於我們將建立的其他頁面。
URL 對映
當我們建立 骨架網站 時,我們更新了 locallibrary/urls.py 檔案,以確保每當收到以 catalog/ 開頭的 URL 時,URLConf 模組 catalog.urls 將處理剩餘的子字串。
以下來自 locallibrary/urls.py 的程式碼片段包含了 catalog.urls 模組:
urlpatterns += [
path('catalog/', include('catalog.urls')),
]
注意:每當 Django 遇到匯入函式 django.urls.include() 時,它會根據指定的結束字元分割 URL 字串,並將剩餘的子字串傳送到包含的 URLConf 模組進行進一步處理。
我們還為 URLConf 模組建立了一個名為 /catalog/urls.py 的佔位符檔案。將以下行新增到該檔案:
urlpatterns = [
path('', views.index, name='index'),
]
path() 函式定義了以下內容:
- 一個 URL 模式,一個空字串:
''。我們將在處理其他檢視時詳細討論 URL 模式。 - 如果檢測到 URL 模式,將呼叫的檢視函式:
views.index,它是 views.py 檔案中名為index()的函式。
path() 函式還指定了一個 name 引數,它是此特定 URL 對映的唯一識別符號。您可以使用該名稱“反轉”對映器,即動態建立指向對映器旨在處理的資源的 URL。例如,我們可以透過在模板中新增以下連結來使用 name 引數從任何其他頁面連結到我們的主頁:
<a href="{% url 'index' %}">Home</a>.
注意:我們可以像 <a href="/catalog/">Home</a> 那樣硬編碼連結,但如果我們將主頁的模式更改為,例如 /catalog/index,模板將不再正確連結。使用反轉 URL 對映更加健壯。
檢視(基於函式)
檢視是一個函式,它處理 HTTP 請求,從資料庫中獲取所需資料,使用 HTML 模板在 HTML 頁面中渲染資料,然後將生成的 HTML 以 HTTP 響應的形式返回,以向用戶顯示頁面。索引檢視遵循此模型——它獲取資料庫中 Book、BookInstance、可用 BookInstance 和 Author 記錄數量的資訊,並將該資訊傳遞給模板以供顯示。
開啟 catalog/views.py 並注意該檔案已匯入 render() 快捷函式,用於使用模板和資料生成 HTML 檔案:
from django.shortcuts import render
# Create your views here.
將以下行貼上到檔案底部:
from .models import Book, Author, BookInstance, Genre
def index(request):
"""View function for home page of site."""
# Generate counts of some of the main objects
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
# Available books (status = 'a')
num_instances_available = BookInstance.objects.filter(status__exact='a').count()
# The 'all()' is implied by default.
num_authors = Author.objects.count()
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
}
# Render the HTML template index.html with the data in the context variable
return render(request, 'index.html', context=context)
第一行匯入了我們將在所有檢視中用於訪問資料的模型類。
檢視函式的第一部分使用模型類上的 objects.all() 屬性獲取記錄數量。它還獲取狀態欄位中值為“a”(可用)的 BookInstance 物件列表。您可以在我們之前的教程 Django 教程第三部分:使用模型 > 搜尋記錄 中找到有關如何訪問模型資料的更多資訊。
在檢視函式末尾,我們呼叫 render() 函式來建立 HTML 頁面並以響應形式返回該頁面。此快捷函式封裝了許多其他函式,以簡化一個非常常見的用例。render() 函式接受以下引數:
- 原始的
request物件,這是一個HttpRequest。 - 帶有資料佔位符的 HTML 模板。
- 一個
context變數,它是一個 Python 字典,包含要插入到佔位符中的資料。
我們將在下一節詳細討論模板和 context 變數。讓我們開始建立模板,以便我們能夠實際向用戶顯示一些內容!
模板
模板是一個文字檔案,它定義了檔案(例如 HTML 頁面)的結構或佈局,它使用佔位符來表示實際內容。
使用 startapp 建立的 Django 應用程式(例如本示例的骨架)將在應用程式的名為“templates”的子目錄中查詢模板。例如,在我們剛剛新增的索引檢視中,render() 函式將期望在 /django-locallibrary-tutorial/catalog/templates/ 中找到檔案 index.html,如果檔案不存在,將引發錯誤。
您可以透過儲存之前的更改並在瀏覽器中訪問 127.0.0.1:8000 來檢查這一點——它將顯示一個相當直觀的錯誤訊息:“TemplateDoesNotExist at /catalog/”,以及其他詳細資訊。
注意:根據您的專案設定檔案,Django 將在多個位置查詢模板,預設情況下在您已安裝的應用程式中搜索。您可以在 Django 文件的模板部分 中瞭解有關 Django 如何查詢模板以及它支援哪些模板格式的更多資訊。
擴充套件模板
索引模板將需要用於頭部和主體的標準 HTML 標記,以及連結到網站其他頁面(我們尚未建立)的導航部分,以及顯示介紹性文字和圖書資料的部分。
我們網站的每個頁面中的大部分 HTML 和導航結構都將相同。與其在每個頁面上重複樣板程式碼,您可以使用 Django 模板語言宣告一個基本模板,然後擴充套件它以只替換每個特定頁面不同的部分。
以下程式碼片段是一個來自 base_generic.html 檔案的示例基本模板。我們很快將為 LocalLibrary 建立模板。下面的示例包含通用 HTML,其中包含標題、側邊欄和主要內容的區塊,這些區塊用命名的 block 和 endblock 模板標籤標記。您可以將區塊留空,或包含在渲染從模板派生的頁面時使用的預設內容。
注意:模板標籤是您可以在模板中使用的函式,用於遍歷列表、根據變數值執行條件操作等等。除了模板標籤,模板語法還允許您引用從檢視傳遞到模板的變數,並使用模板過濾器來格式化變數(例如,將字串轉換為小寫)。
<!doctype html>
<html lang="en">
<head>
{% block title %}
<title>Local Library</title>
{% endblock %}
</head>
<body>
{% block sidebar %}
<!-- insert default navigation text for every page -->
{% endblock %}
{% block content %}
<!-- default content text (typically empty) -->
{% endblock %}
</body>
</html>
當為特定檢視定義模板時,我們首先使用 extends 模板標籤指定基本模板——參見下面的程式碼示例。然後,我們宣告要替換模板中的哪些部分(如果有),使用 block/endblock 部分,如基本模板中所示。
例如,下面的程式碼片段展示瞭如何使用 extends 模板標籤並覆蓋 content 塊。生成的 HTML 將包含在基本模板中定義的程式碼和結構,包括您在 title 塊中定義的預設內容,但新的 content 塊將替換預設的塊。
{% extends "base_generic.html" %}
{% block content %}
<h1>Local Library Home</h1>
<p>
Welcome to LocalLibrary, a website developed by
<em>Mozilla Developer Network</em>!
</p>
{% endblock %}
LocalLibrary 基本模板
我們將使用以下程式碼片段作為 LocalLibrary 網站的基本模板。如您所見,它包含一些 HTML 程式碼,並定義了 title、sidebar 和 content 的塊。我們有一個預設標題和一個預設側邊欄,其中包含所有圖書和作者列表的連結,兩者都包含在塊中,以便將來輕鬆更改。
注意:我們還引入了另外兩個模板標籤:url 和 load static。這些標籤將在後續章節中解釋。
在 /django-locallibrary-tutorial/catalog/templates/ 中建立一個新檔案 base_generic.html,並將以下程式碼貼上到檔案中:
<!doctype html>
<html lang="en">
<head>
{% block title %}
<title>Local Library</title>
{% endblock %}
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
crossorigin="anonymous">
<!-- Add additional CSS in static file -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}" />
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
{% block sidebar %}
<ul class="sidebar-nav">
<li><a href="{% url 'index' %}">Home</a></li>
<li><a href="">All books</a></li>
<li><a href="">All authors</a></li>
</ul>
{% endblock %}
</div>
<div class="col-sm-10 ">{% block content %}{% endblock %}</div>
</div>
</div>
</body>
</html>
該模板包含來自 Bootstrap 的 CSS,以改善 HTML 頁面的佈局和呈現。使用 Bootstrap(或其他客戶端 Web 框架)是建立在不同螢幕尺寸上都能良好顯示的有吸引力頁面的快速方法。
基本模板還引用了一個提供額外樣式的本地 CSS 檔案 (styles.css)。在 /django-locallibrary-tutorial/catalog/static/css/ 中建立一個 styles.css 檔案,並將以下程式碼貼上到檔案中:
.sidebar-nav {
margin-top: 20px;
padding: 0;
list-style: none;
}
索引模板
在 /django-locallibrary-tutorial/catalog/templates/ 中建立一個新的 HTML 檔案 index.html,並將以下程式碼貼上到檔案中。此程式碼在第一行擴充套件了我們的基本模板,然後替換了模板的預設 content 塊。
{% extends "base_generic.html" %}
{% block content %}
<h1>Local Library Home</h1>
<p>
Welcome to LocalLibrary, a website developed by
<em>Mozilla Developer Network</em>!
</p>
<h2>Dynamic content</h2>
<p>The library has the following record counts:</p>
<ul>
<li><strong>Books:</strong> {{ num_books }}</li>
<li><strong>Copies:</strong> {{ num_instances }}</li>
<li><strong>Copies available:</strong> {{ num_instances_available }}</li>
<li><strong>Authors:</strong> {{ num_authors }}</li>
</ul>
{% endblock %}
在“動態內容”部分,我們為要包含的檢視資訊聲明瞭佔位符(模板變數)。變數用雙大括號(雙花括號)括起來。
注意:您可以輕鬆識別模板變數和模板標籤(函式)——變數用雙大括號({{ num_books }})括起來,標籤用帶百分號的單大括號({% extends "base_generic.html" %})括起來。
這裡需要注意的重要一點是,變數的命名與我們在檢視的 render() 函式中傳遞給 context 字典的鍵相同(參見下面的示例)。當模板被渲染時,變數將被替換為其關聯的值。
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
}
return render(request, 'index.html', context=context)
在模板中引用靜態檔案
您的專案可能會使用靜態資源,包括 JavaScript、CSS 和影像。由於這些檔案的位置可能未知(或可能更改),Django 允許您在模板中相對於 STATIC_URL 全域性設定指定位置。預設的骨架網站將 STATIC_URL 的值設定為 "/static/",但您可以選擇將其託管在內容分發網路或其他地方。
在模板中,您首先呼叫 load 模板標籤並指定“static”以新增模板庫,如以下程式碼示例所示。然後您可以使用 static 模板標籤並指定所需檔案的相對 URL。
<!-- Add additional CSS in static file -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}" />
您可以透過類似的方式將影像新增到頁面中,例如:
{% load static %}
<img
src="{% static 'images/local_library_model_uml.png' %}"
alt="UML diagram"
style="width:555px;height:540px;" />
注意:上面的示例指定了檔案的位置,但 Django 預設不提供它們。我們在 建立網站骨架 時透過修改全域性 URL 對映器 (/django-locallibrary-tutorial/locallibrary/urls.py) 配置了開發 Web 伺服器來提供檔案,但仍需要在生產環境中啟用檔案提供。我們將在以後討論這一點。
有關使用靜態檔案的更多資訊,請參閱 Django 文件中的 管理靜態檔案。
連結到 URL
上面的基本模板引入了 url 模板標籤。
<li><a href="{% url 'index' %}">Home</a></li>
此標籤接受在您的 urls.py 中呼叫的 path() 函式的名稱,以及該函式將從該函式接收到的任何引數的值,並返回一個可用於連結到資源的 URL。
配置模板查詢位置
Django 搜尋模板的位置在 settings.py 檔案中的 TEMPLATES 物件中指定。預設的 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',
],
},
},
]
'APP_DIRS': True 的設定最重要,因為它告訴 Django 在專案中的每個應用程式的名為“templates”的子目錄中搜索模板(這使得模板更容易與相關的應用程式分組以便於重用)。
我們還可以使用 'DIRS': [] 為 Django 指定特定的目錄搜尋位置(但目前不需要)。
注意:您可以在 Django 文件的模板部分 中瞭解有關 Django 如何查詢模板以及它支援哪些模板格式的更多資訊。
它看起來怎麼樣?
至此,我們已經建立了顯示索引頁所需的所有資源。執行伺服器(python3 manage.py runserver)並在瀏覽器中開啟 http://127.0.0.1:8000/。如果一切配置正確,您的網站應該如下圖所示。

注意:“所有圖書”和“所有作者”連結暫時無法工作,因為這些頁面的路徑、檢視和模板尚未定義。我們只是在 base_generic.html 模板中為這些連結插入了佔位符。
挑戰自我
這裡有幾個任務可以測試您對模型查詢、檢視和模板的熟悉程度。
總結
我們剛剛建立了網站的主頁——一個顯示資料庫中多條記錄並連結到其他尚未建立的頁面的 HTML 頁面。在此過程中,我們瞭解了有關 URL 對映器、檢視、使用模型查詢資料庫、從檢視向模板傳遞資訊以及建立和擴充套件模板的基本資訊。
在下一篇文章中,我們將在此知識的基礎上建立我們網站的其餘四個頁面。
另見
- 編寫您的第一個 Django 應用程式,第 3 部分:檢視和模板 (Django 文件)
- URL 排程器 (Django 文件)
- 檢視函式 (Django 文件)
- 模板 (Django 文件)
- 管理靜態檔案 (Django 文件)
- Django 快捷函式 (Django 文件)