申明: 本站飛宇網 https://feiyetopro.blogspot.com/。自網路收集整理之書籍、文章、影音僅供預覽交流學習研究,其[書籍、文章、影音]情節內容, 評論屬其個人行為, 與本網站無關。版權歸原作者和出版社所有,請在下載 24 小時內刪除,不得用作商業用途;如果您喜歡其作品,請支持訂閱購買[正版]。謝謝!
專案3 Web應用程式
第 18 章 Django入門
當今的網站實際上都是富應用程式(rich application),就像成熟的桌面應用程式一樣。Python提供了一組開發Web應用程式的卓越工具。在本章中,你將學習如何使用Django(http://djangoproject.com/ )來開發一個名為“學習筆記”(Learning Log)的專案,這是一個線上日誌系統,讓你能夠記錄所學習的有關特定主題的知識。
我們將為這個專案制定規範,然後為應用程式使用的資料定義模型。我們將使用Django的管理系統來輸入一些初始資料,再學習編寫視圖和範本,讓Django能夠為我們的網站創建網頁。
Django是一個Web框架 ——一套用於幫助開發互動式網站的工具。Django能夠回應網頁請求,還能讓你更輕鬆地讀寫資料庫、管理使用者等。在第19章和第20章,我們將改進“學習筆記”專案,再將其部署到活動的伺服器,讓你和你的朋友能夠使用它。
18.1 建立專案
建立專案時,首先需要以規範的方式對專案進行描述,再建立虛擬環境,以便在其中創建專案。
18.1.1 制定規範
完整的規範詳細說明了專案的目標,闡述了專案的功能,並討論了專案的外觀和使用者介面。與任何良好的項目規劃和商業計畫書一樣,規範應突出重點,説明避免專案偏離軌道。這裡不會制定完整的項目規劃,而只列出一些明確的目標,以突出開發的重點。我們制定的規範如下:
我們要編寫一個名為“學習筆記”的Web應用程式,讓使用者能夠記錄感興趣的主題,並在學習每個主題的過程中添加日誌條目。“學習筆記”的主頁對這個網站進行描述,並邀請用戶註冊或登錄。使用者登錄後,就可創建新主題、添加新條目以及閱讀既有的條目。
學習新的主題時,記錄學到的知識可幫助跟蹤和複習這些知識。優秀的應用程式讓這個記錄過程簡單易行。
18.1.2 建立虛擬環境
要使用Django,首先需要建立一個虛擬工作環境。虛擬環境 是系統的一個位置,你可以在其中安裝包,並將其與其他Python包隔離。將專案的庫與其他專案分離是有益的,且為了在第20章將“學習筆記”部署到伺服器,這也是必須的。
為專案新建一個目錄,將其命名為learning_log,再在終端中切換到這個目錄,並創建一個虛擬環境。如果你使用的是Python 3,可使用如下命令來創建虛擬環境:
learning_log$
python -m venv ll_env
learning_log$
這裡運行了模組venv ,並使用它來創建一個名為ll_env的虛擬環境。如果這樣做管用,請跳到後面的18.1.4節;如果不管用,請閱讀18.1.3節。
18.1.3 安裝virtualenv
如果你使用的是較早的Python版本,或者系統沒有正確地設置,不能使用模組venv ,可安裝virtualenv包。為此,可執行如下命令:
$ pip
install --user virtualenv
別忘了,對於這個命令,你可能需要使用稍微不同的版本(如果你沒有使用過pip,請參閱12.2.1節)。
注意 如果你使用的是Linux系統,且上面的做法不管用,可使用系統的包管理器來安裝virtualenv。例如,要在Ubuntu系統中安裝virtualenv,可使用命令sudo apt-get install python-virtualenv 。
在終端中切換到目錄learning_log,並像下面這樣創建一個虛擬環境:
learning_log$
virtualenv ll_env
New
python executable in ll_env/bin/python
Installing
setuptools, pip...done.
learning_log$
注意 如果你的系統安裝了多個Python版本,需要指定virtualenv使用的版本。例如,命令virtualenv ll_env --python=python3 創建一個使用Python 3的虛擬環境。
18.1.4 啟動虛擬環境
建立虛擬環境後,需要使用下面的命令啟動它:
learning_log$ source ll_env/bin/activate
❶
(ll_env)learning_log$
這個命令運行ll_env/bin中的腳本activate。環境處於活動狀態時,環境名將包含在括弧內,如❶處所示。在這種情況下,你可以在環境中安裝包,並使用已安裝的包。你在ll_env中安裝的包僅在該環境處於活動狀態時才可用。
注意 如果你使用的是Windows系統,請使用命令ll_env\Scripts\activate (不包含source )來啟動這個虛擬環境。
要停止使用虛擬環境,可執行命令deactivate :
(ll_env)learning_log$
deactivate
learning_log$
如果關閉運行虛擬環境的終端,虛擬環境也將不再處於活動狀態。
18.1.5 安裝Django
創建並啟動虛擬環境後,就可安裝Django了:
(ll_env)learning_log$
pip install Django
Installing
collected packages: Django
Successfully
installed Django
Cleaning
up...
(ll_env)learning_log$
由於我們是在虛擬環境中工作,因此在所有的系統中,安裝Django的命令都相同:不需要指定標誌--user ,也無需使用python -m pip install package_name 這樣較長的命令。
別忘了,Django僅在虛擬環境處於活動狀態時才可用。
18.1.6 在Django中創建項目
在依然處於活動的虛擬環境的情況下(ll_env包含在括弧內),執行如下命令來新建一個專案:
❶
(ll_env)learning_log$ django-admin.py startproject learning_log .
❷
(ll_env)learning_log$ ls
learning_log ll_env manage.py
❸
(ll_env)learning_log$ ls learning_log
__init__.py
settings.py urls.py wsgi.py
❶處的命令讓Django新建一個名為learning_log的項目。這個命令末尾的句點讓新專案使用合適的目錄結構,這樣開發完成後可輕鬆地將應用程式部署到伺服器。
注意 千萬別忘了這個句點,否則部署應用程式時將遭遇一些配置問題。如果忘記了這個句點,就將創建的檔和資料夾刪除(ll_env除外),再重新運行這個命令。
在❸處,運行了命令ls (在Windows系統上應為dir ),結果表明Django新建了一個名為learning_log的目錄。它還創建了一個名為manage.py的檔,這是一個簡單的程式,它接受命令並將其交給Django的相關部分去運行。我們將使用這些命令來管理諸如使用資料庫和運行伺服器等任務。
目錄learning_log包含4個檔(見❸),其中最重要的是settings.py、urls.py和wsgi.py。文件settings.py指定Django如何與你的系統交互以及如何管理專案。在開發項目的過程中,我們將修改其中一些設置,並添加一些設置。文件urls.py告訴Django應創建哪些網頁來回應流覽器請求。文件wsgi.py幫助Django提供它創建的檔,這個檔案名是web server gateway interface(Web伺服器閘道介面 )的首字母縮寫。
18.1.7 創建資料庫
Django將大部分與專案相關的資訊都存儲在資料庫中,因此我們需要創建一個供Django使用的資料庫。為給專案“學習筆記”創建資料庫,請在處於活動虛擬環境中的情況下執行下面的命令:
(ll_env)learning_log$ python manage.py
migrate
❶
Operations to perform:
Synchronize unmigrated apps: messages,
staticfiles
Apply all migrations: contenttypes,
sessions, auth, admin
--snip--
Applying sessions.0001_initial... OK
❷
(ll_env)learning_log$ ls
db.sqlite3
learning_log ll_env manage.py
我們將修改資料庫稱為遷移 資料庫。首次執行命令migrate 時,將讓Django確保資料庫與專案的當前狀態匹配。在使用SQLite(後面將更詳細地介紹)的新項目中首次執行這個命令時,Django將新建一個資料庫。在❶處,Django指出它將創建必要的資料庫表,用於存儲我們將在這個專案(Synchronize
unmigrated apps,同步未遷移的應用程式 )中使用的資訊,再確保資料庫結構與當前代碼(Apply all
migrations,應用所有的遷移 )匹配。
在❷處,我們運行了命令ls ,其輸出表明Django又創建了一個檔——db.sqlite3。SQLite是一種使用單個檔的資料庫,是編寫簡單應用程式的理想選擇,因為它讓你不用太關注資料庫管理的問題。
18.1.8 查看項目
下麵來核實Django是否正確地創建了專案。為此,可執行命令runserver ,如下所示:
(ll_env)learning_log$ python manage.py
runserver
Performing system checks...
❶ System
check identified no issues (0 silenced).
July 15, 2015 - 06:23:51
❷ Django
version 1.8.4, using settings 'learning_log.settings'
❸ Starting
development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Django啟動一個伺服器,讓你能夠查看系統中的專案,瞭解它們的工作情況。當你在流覽器中輸入URL以請求網頁時,該Django伺服器將進行回應:生成合適的網頁,並將其發送給流覽器。
在❶處,Django通過檢查確認正確地創建了專案;在❷處,它指出了使用的Django版本以及當前使用的設置檔的名稱;在❸處,它指出了專案的URL。URL http://127.0.0.1:8000/表明專案將在你的電腦(即localhost)的埠8000上偵聽請求。localhost是一種只處理當前系統發出的請求,而不允許其他任何人查看你正在開發的網頁的伺服器。
現在打開一款Web流覽器,並輸入URL:http://localhost:8000/;如果這不管用,請輸入http://127.0.0.1:8000/。你將看到類似於圖18-1所示的頁面,這個頁面是Django創建的,讓你知道到目前為止一切正常。現在暫時不要關閉這個伺服器。若要關閉這個伺服器,按Ctrl + C即可。
注意 如果出現錯誤消息“That port is
already in use”(指定埠已被佔用),請執行命令python
manage.py runserver 8001 ,讓Diango使用另一個埠;如果這個埠也不可用,請不斷執行上述命令,並逐漸增大其中的埠號,直到找到可用的埠。
動手試一試
18-1 新項目 :為更深入地瞭解Django做了些什麼,可創建兩個空項目,看看Django創建了什麼。新建一個資料夾,並給它指定簡單的名稱,如InstaBook或FaceGram(不要在目錄learning_log中新建該資料夾),在終端中切換到該資料夾,並創建一個虛擬環境。在這個虛擬環境中安裝Django,並執行命令django-admin.py
startproject instabook. (千萬不要忘了這個命令末尾的句點)。
看看這個命令創建了哪些檔和資料夾,並與專案“學習筆記”包含的檔和資料夾進行比較。這樣多做幾次,直到對Django新建項目時創建的東西瞭若指掌。然後,將專案目錄刪除——如果你想這樣做的話。
18.2 創建應用程式
Django專案 由一系列應用程式組成,它們協同工作,讓專案成為一個整體。我們暫時只創建一個應用程式,它將完成專案的大部分工作。在第19章,我們將再添加一個管理使用者帳戶的應用程式。
當前,在前面打開的終端視窗中應該還運行著runserver 。請再打開一個終端視窗(或標籤頁),並切換到manage.py所在的目錄。啟動該虛擬環境,再執行命令startapp :
learning_log$ source ll_env/bin/activate
(ll_env)learning_log$ python manage.py
startapp learning_logs
❶
(ll_env)learning_log$ ls
db.sqlite3
learning_log learning_logs ll_env
manage.py
❷
(ll_env)learning_log$ ls learning_logs/
admin.py
__init__.py migrations models.py
tests.py views.py
命令startapp appname 讓Django建立創建應用程式所需的基礎設施。如果現在查看專案目錄,將看到其中新增了一個資料夾learning_logs(見❶)。打開這個資料夾,看看Django都創建了什麼(見❷)。其中最重要的文件是models.py、admin.py和views.py。我們將使用models.py來定義我們要在應用程式中管理的資料。admin.py和views.py將在稍後介紹。
18.2.1 定義模型
我們來想想涉及的資料。每位元使用者都需要在學習筆記中創建很多主題。使用者輸入的每個條目都與特定主題相關聯,這些條目將以文本的方式顯示。我們還需要存儲每個條目的時間戳記,以便能夠告訴用戶各個條目都是什麼時候創建的。
打開文件models.py,看看它當前包含哪些內容:
models.py
from
django.db import models
# 在這裡創建模型
這為我們導入了模組models,還讓我們創建自己的模型。模型告訴Django如何處理應用程式中存儲的資料。在代碼層面,模型就是一個類,就像前面討論的每個類一樣,包含屬性和方法。下面是表示使用者將要存儲的主題的模型:
from django.db import models
class Topic(models.Model):
"""使用者學習的主題"""
❶ text = models.CharField(max_length=200)
❷ date_added = models.DateTimeField(auto_now_add=True)
❸ def __str__(self):
"""返回模型的字串表示"""
return self.text
我們創建了一個名為Topic 的類,它繼承了Model ——Django中一個定義了模型基本功能的類。Topic 類只有兩個屬性:text 和date_added 。
屬性text是一個CharField——由字元或文本組成的資料(見❶)。需要存儲少量的文本,如名稱、標題或城市時,可使用CharField 。定義CharField 屬性時,必須告訴Django該在資料庫中預留多少空間。在這裡,我們將max_length 設置成了200(即200個字元),這對存儲大多數主題名來說足夠了。
屬性date_added 是一個DateTimeField ——記錄日期和時間的資料(見❷)。我們傳遞了實參auto_add_now=True ,每當使用者創建新主題時,這都讓Django將這個屬性自動設置成當前日期和時間。
注意 要獲悉可在模型中使用的各種欄位,請參閱Django Model
Field Reference(Django模型欄位參考),其網址為https://docs.djangoproject.com/en/1.8/ref/models/fields/ 。就當前而言,你無需全面瞭解其中的所有內容,但自己開發應用程式時,這些內容會提供極大的説明。
我們需要告訴Django,預設應使用哪個屬性來顯示有關主題的資訊。Django調用方法__str__() 來顯示模型的簡單表示。在這裡,我們編寫了方法__str__() ,它返回存儲在屬性text 中的字串(見❸)。
注意 如果你使用的是Python 2.7,應調用方法__unicode__() ,而不是__str__() ,但其中的代碼相同。
18.2.2 啟動模型
要使用模型,必須讓Django將應用套裝程式含到項目中。為此,打開settings.py(它位於目錄learning_log/learning_log中),你將看到一個這樣的片段,即告訴Django哪些應用程式安裝在專案中:
settings.py
--snip--
INSTALLED_APPS
= (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
)
--snip--
這是一個元組,告訴Django專案是由哪些應用程式組成的。請將INSTALLED_APPS 修改成下面這樣,將前面的應用程式添加到這個元組中:
--snip--
INSTALLED_APPS
= (
--snip--
'django.contrib.staticfiles',
# 我的應用程式
'learning_logs',
)
--snip--
通過將應用程式編組,在專案不斷增大,包含更多的應用程式時,有助於對應用程式進行跟蹤。這裡新建了一個名為My apps的片段,當前它只包含應用程式learning_logs。
接下來,需要讓Django修改資料庫,使其能夠存儲與模型Topic 相關的資訊。為此,在終端視窗中執行下麵的命令:
(ll_env)learning_log$
python manage.py makemigrations learning_logs
Migrations
for 'learning_logs':
0001_initial.py:
- Create model Topic
(ll_env)learning_log$
命令makemigrations 讓Django確定該如何修改資料庫,使其能夠存儲與我們定義的新模型相關聯的資料。輸出表明Django創建了一個名為0001_initial.py的遷移檔,這個檔將在資料庫中為模型Topic 創建一個表。
下面來應用這種遷移,讓Django替我們修改資料庫:
(ll_env)learning_log$ python manage.py
migrate
--snip--
Running migrations:
Rendering model states... DONE
❶ Applying learning_logs.0001_initial... OK
這個命令的大部分輸出都與我們首次執行命令migrate的輸出相同。我們需要檢查的是❶處的輸出行,在這裡,Django確認為learning_logs 應用遷移時一切正常(OK )。
每當需要修改“學習筆記”管理的資料時,都採取如下三個步驟:修改models.py;對learning_logs 調用makemigrations ;讓Django遷移項目。
18.2.3 Django管理網站
為應用程式定義模型時,Django提供的管理網站(admin site)讓你能夠輕鬆地處理模型。網站的管理員可使用管理網站,但普通用戶不能使用。在本節中,我們將建立管理網站,並通過它使用模型Topic 來添加一些主題。
1. 創建超級用戶
Django允許你創建具備所有權限的用戶——超級用戶。許可權決定了用戶可執行的操作。最嚴格的許可權設置只允許用戶閱讀網站的公開信息;註冊了的使用者通常可閱讀自己的私有資料,還可查看一些只有會員才能查看的資訊。為有效地管理Web應用程式,網站所有者通常需要訪問網站存儲的所有資訊。優秀的管理員會小心對待使用者的敏感資訊,因為使用者對其訪問的應用程式有極大的信任。
為在Django中創建超級用戶,請執行下面的命令並按提示做:
(ll_env)learning_log$ python manage.py
createsuperuser
❶ Username
(leave blank to use 'ehmatthes'): ll_admin
❷ Email
address:
❸ Password:
Password (again):
Superuser created successfully.
(ll_env)learning_log$
你執行命令createsuperuser 時,Django提示你輸入超級用戶的用戶名(見❶)。這裡我們輸入的是ll_admin,但你可以輸入任何用戶名,比如電子郵寄地址,也可讓這個欄位為空(見❷)。你需要輸入密碼兩次(見❸)。
注意 可能會對網站管理員隱藏有些敏感資訊。例如,Django並不存儲你輸入的密碼,而存儲從該密碼派生出來的一個字串——散列值。每當你輸入密碼時,Django都計算其散列值,並將結果與存儲的散列值進行比較。如果這兩個散列值相同,就通過了身份驗證。通過存儲散列值,即便駭客獲得了網站資料庫的訪問權,也只能獲取其中存儲的散列值,而無法獲得密碼。在網站配置正確的情況下,幾乎無法根據散列值推導出原始密碼。
2. 向管理網站註冊模型
Django自動在管理網站中添加了一些模型,如User 和Group ,但對於我們創建的模型,必須手工進行註冊。
我們創建應用程式learning_logs 時,Django在models.py所在的目錄中創建了一個名為admin.py的文件:
admin.py
from
django.contrib import admin
# 在這裡註冊你的模型
為向管理網站註冊Topic ,請輸入下面的代碼:
from django.contrib import admin
❶ from
learning_logs.models import Topic
❷ admin.site.register(Topic)
這些代碼導入我們要註冊的模型Topic (見❶),再使用admin.site.register() (見❷)讓Django通過管理網站管理我們的模型。
現在,使用超級用戶帳戶訪問管理網站:訪問http://localhost:8000/admin/ ,並輸入你剛創建的超級使用者的用戶名和密碼,你將看到類似於圖18-2所示的螢幕。這個網頁讓你能夠添加和修改用戶和用戶組,還可以管理與剛才定義的模型Topic 相關的資料。
注意 如果你在流覽器中看到一條消息,指出訪問的網頁不可用,請確認你在終端視窗中運行著Django伺服器。如果沒有,請啟動虛擬環境,並執行命令python
manage.py runserver 。
3. 添加主題
向管理網站註冊Topic 後,我們來添加第一個主題。為此,按一下Topics進入主題網頁,它幾乎是空的,這是因為我們還沒有添加任何主題。按一下Add,你將看到一個用於添加新主題的表單。在第一個方框中輸入Chess ,再按一下Save,這將返回到主題管理頁面,其中包含剛創建的主題。
下面再創建一個主題,以便有更多的資料可供使用。再次按一下Add,並創建另一個主題Rock Climbing 。當你按一下Save時,將重新回到主題管理頁面,其中包含主題Chess和Rock Climbing。
18.2.4 定義模型Entry
要記錄學到的國際象棋和攀岩知識,需要為使用者可在學習筆記中添加的條目定義模型。每個條目都與特定主題相關聯,這種關係被稱為多對一關係,即多個條目可關聯到同一個主題。
下面是模型Entry 的代碼:
models.py
from django.db import models
class Topic(models.Model):
--snip--
❶ class
Entry(models.Model):
"""學到的有關某個主題的具體知識"""
❷ topic = models.ForeignKey(Topic)
❸ text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
❹ class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""返回模型的字串表示"""
❺ return self.text[:50] +
"..."
像Topic 一樣,Entry 也繼承了Django基類Model (見❶)。第一個屬性topic 是一個ForeignKey 實例(見❷)。外鍵是一個資料庫術語,它引用了資料庫中的另一條記錄;這些代碼將每個條目關聯到特定的主題。每個主題創建時,都給它分配了一個鍵(或ID)。需要在兩項資料之間建立聯繫時,Django使用與每項資訊相關聯的鍵。稍後我們將根據這些聯繫獲取與特定主題相關聯的所有條目。
接下來是屬性text ,它是一個TextField 實例(見❸)。這種欄位不需要長度限制,因為我們不想限制條目的長度。屬性date_added 讓我們能夠按創建順序呈現條目,並在每個條目旁邊放置時間戳記。
在❹處,我們在Entry 類中嵌套了Meta 類。Meta 存儲用於管理模型的額外資訊,在這裡,它讓我們能夠設置一個特殊屬性,讓Django在需要時使用Entries 來表示多個條目。如果沒有這個類, Django將使用Entrys來表示多個條目。最後,方法__str__() 告訴Django,呈現條目時應顯示哪些資訊。由於條目包含的文本可能很長,我們讓Django只顯示text 的前50個字元(見❺)。我們還添加了一個省略號,指出顯示的並非整個條目。
18.2.5 遷移模型Entry
由於我們添加了一個新模型,因此需要再次遷移資料庫。你將慢慢地對這個過程瞭若指掌:修改models.py,執行命令python
manage.py makemigrations app_name ,再執行命令python
manage.py migrate 。
下面來遷移資料庫並查看輸出:
(ll_env)learning_log$ python manage.py makemigrations
learning_logs
Migrations for 'learning_logs':
❶ 0002_entry.py:
- Create model Entry
(ll_env)learning_log$ python manage.py
migrate
Operations to perform:
--snip--
❷ Applying learning_logs.0002_entry... OK
生成了一個新的遷移檔——0002_entry.py,它告訴Django如何修改資料庫,使其能夠存儲與模型Entry 相關的資訊(見❶)。執行命令migrate ,我們發現Django應用了這種遷移且一切順利(見❷)。
18.2.6 向管理網站註冊Entry
我們還需要註冊模型Entry 。為此,需要將admin.py修改成類似於下面這樣:
admin.py
from
django.contrib import admin
from
learning_logs.models import Topic, Entry
admin.site.register(Topic)
admin.site.register(Entry)
返回到http://localhost/admin/ ,你將看到learning_logs下列出了Entries。按一下Entries的Add連結,或者按一下Entries再選擇Add entry。你將看到一個下拉清單,讓你能夠選擇要為哪個主題創建條目,還有一個用於輸入條目的文字方塊。從下拉清單中選擇Chess,並添加一個條目。下面是我添加的第一個條目。
The opening is the first part of the
game, roughly the first ten moves or so. In the opening, it's a good idea to do
three things— bring out your bishops and knights, try to control the center of
the board, and castle your king.(國際象棋的第一個階段是開局,大致是前10步左右。在開局階段,最好做三件事情:將象和馬調出來;努力控制棋盤的中間區域;用車將王護住。)
Of course, these are just guidelines. It
will be important to learn when to follow these guidelines and when to
disregard these suggestions.(當然,這些只是指導原則。學習什麼情況下遵守這些原則、什麼情況下不用遵守很重要。)
當你按一下Save時,將返回到主條目管理頁面。在這裡,你將發現使用text[:50] 作為條目的字串表示的好處:管理介面中,只顯示了條目的開頭部分而不是其所有文本,這使得管理多個條目容易得多。
再來創建一個國際象棋條目,並創建一個攀岩條目,以提供一些初始資料。下面是第二個國際象棋條目。
In the opening phase of the game, it's
important to bring out your bishops and knights. These pieces are powerful and
maneuverable enough to play a significant role in the beginning moves of a
game.(在國際象棋的開局階段,將象和馬調出來很重要。這些棋子威力大,機動性強,在開局階段扮演著重要角色。)
下面是第一個攀岩條目:
One of the most important concepts in
climbing is to keep your weight on your feet as much as possible. There's a
myth that climbers can hang all day on their arms. In reality, good climbers
have practiced specific ways of keeping their weight over their feet whenever
possible.(最重要的攀岩概念之一是盡可能讓雙腳承受體重。有謬誤認為攀岩者能依靠手臂的力量堅持一整天。實際上,優秀的攀岩者都經過專門訓練,能夠盡可能讓雙腳承受體重。)
繼續往下開發“學習筆記”時,這三個條目可為我們提供使用的資料。
18.2.7 Django shell
輸入一些資料後,就可通過互動式終端會話以程式設計方式查看這些資料了。這種互動式環境稱為Django shell,是測試專案和排除其故障的理想之地。下面是一個互動式shell會話示例:
(ll_env)learning_log$ python manage.py shell
❶
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
[<Topic: Chess>, <Topic: Rock
Climbing>]
在活動的虛擬環境中執行時,命令python manage.py shell 啟動一個Python解譯器,可使用它來探索存儲在專案資料庫中的資料。在這裡,我們導入了模組learning_logs.models 中的模型Topic (見❶),然後使用方法Topic.objects.all() 來獲取模型Topic 的所有實例;它返回的是一個列表,稱為查詢集(queryset)。
我們可以像遍歷列表一樣遍歷查詢集。下面演示了如何查看分配給每個主題物件的ID:
>>>
topics = Topic.objects.all()
>>>
for topic in topics:
... print(topic.id, topic)
...
1
Chess
2
Rock Climbing
我們將返回的查詢集存儲在topics 中,然後列印每個主題的id 屬性和字串表示。從輸出可知,主題Chess的ID為1,而Rock Climbing的ID為2。
知道物件的ID後,就可獲取該物件並查看其任何屬性。下面來看看主題Chess的屬性text 和date_added 的值:
>>>
t = Topic.objects.get(id=1)
>>>
t.text
'Chess'
>>>
t.date_added
datetime.datetime(2015,
5, 28, 4, 39, 11, 989446, tzinfo=<UTC>)
我們還可以查看與主題相關聯的條目。前面我們給模型Entry 定義了屬性topic ,這是一個ForeignKey ,將條目與主題關聯起來。利用這種關聯,Django能夠獲取與特定主題相關聯的所有條目,如下所示:
❶
>>> t.entry_set.all()
[<Entry: The opening is the first part of
the game, roughly...>, <Entry: In the opening phase of the game, it's
important t...>]
為通過外鍵關係獲取資料,可使用相關模型的小寫名稱、底線和單詞set(見❶)。例如,假設你有模型Pizza 和Topping ,而Topping通過一個外鍵關聯到Pizza ;如果你有一個名為my_pizza 的物件,表示一張比薩,就可使用代碼my_pizza.topping_set.all() 來獲取這張比薩的所有配料。
編寫用戶可請求的網頁時,我們將使用這種語法。確認代碼能獲取所需的資料時,shell很有幫助。如果代碼在shell中的行為符合預期,那麼它們在專案檔案中也能正確地工作。如果代碼引發了錯誤或獲取的資料不符合預期,那麼在簡單的shell環境中排除故障要比在生成網頁的檔中排除故障容易得多。我們不會太多地使用shell,但應繼續使用它來熟悉對存儲在專案中的資料進行訪問的Django語法。
注意 每次修改模型後,你都需要重啟shell,這樣才能看到修改的效果。要退出shell會話,可按Ctr + D;如果你使用的是Windows系統,應按Ctr + Z,再按回車鍵。
動手試一試
18-2 簡短的條目 :當前,Django在管理網站或shell中顯示Entry 實例時,模型Entry 的方法__str__() 都在它的末尾加上省略號。請在方法__str__() 中添加一條if 語句,以便僅在條目長度超過50字元時才添加省略號。使用管理網站來添加一個長度少於50字元的條目,並核實顯示它時沒有省略號。
18-3 Django API :編寫訪問專案中的資料的代碼時,你編寫的是查詢。請流覽有關如何查詢資料的文檔,其網址為https://docs.djangoproject.com/en/7.8/topics/db/queries/ 。其中大部分內容都是你不熟悉的,但等你自己開發專案時,這些內容會很有用。
18-4 比薩店 :新建一個名為pizzeria 的專案,並在其中添加一個名為pizzas 的應用程式。定義一個名為Pizza 的模型,它包含欄位name ,用於存儲比薩名稱,如Hawaiian和Meat Lovers。定義一個名為Topping 的模型,它包含欄位pizza 和name ,其中欄位pizza 是一個關聯到Pizza 的外鍵,而欄位name 用於存儲配料,如pineapple 、Canadian
bacon 和sausage 。
向管理網站註冊這兩個模型,並使用管理網站輸入一些比薩名和配料。使用shell來查看你輸入的資料。
18.3 創建網頁:學習筆記主頁
使用Django創建網頁的過程通常分三個階段:定義URL、編寫視圖和編寫範本。首先,你必須定義URL模式。URL模式描述了URL是如何設計的,讓Django知道如何將流覽器請求與網站URL匹配,以確定返回哪個網頁。
每個URL都被映射到特定的視圖 ——視圖函數獲取並處理網頁所需的資料。視圖函數通常調用一個範本,後者生成流覽器能夠理解的網頁。為明白其中的工作原理,我們來創建學習筆記的主頁。我們將定義該主頁的URL、編寫其視圖函數並創建一個簡單的範本。
鑒於我們只是要確保“學習筆記”按要求的那樣工作,我們將暫時讓這個網頁盡可能簡單。Web應用程式能夠正常運行後,設置樣式可使其更有趣,但中看不中用的應用程式毫無意義。就目前而言,主頁只顯示標題和簡單的描述。
18.3.1 映射URL
使用者通過在流覽器中輸入URL以及按一下連結來請求網頁,因此我們需要確定專案需要哪些URL。主頁的URL最重要,它是用戶用來訪問項目的基礎URL。當前,基礎URL(http://localhost:8000/)返回默認的Django網站,讓我們知道正確地建立了項目。我們將修改這一點,將這個基礎URL映射到“學習筆記”的主頁。
打開專案主資料夾learning_log中的檔urls.py,你將看到如下代碼:
urls.py
❶ from
django.conf.urls import include, url
from django.contrib import admin
❷
urlpatterns = [
❸ url(r'^admin/', include(admin.site.urls)),
]
前兩行導入了為專案和管理網站管理URL的函數和模組(見❶)。這個檔的主體定義了變數urlpatterns (見❷)。在這個針對整個項目的urls.py檔中,變數urlpatterns 包含專案中的應用程式的URL。❸處的代碼包含模組admin.site.urls ,該模組定義了可在管理網站中請求的所有URL。
我們需要包含learning_logs的URL:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/',
include(admin.site.urls)),
❶ url(r'', include('learning_logs.urls',
namespace='learning_logs')),
]
在❶處,我們添加了一行代碼來包含模組learning_logs.urls 。這行代碼包含實參namespace ,讓我們能夠將learning_logs 的URL同項目中的其他URL區分開來,這在項目開始擴展時很有幫助。
默認的urls.py包含在資料夾learning_log中,現在我們需要在資料夾learning_logs中創建另一個urls.py文件:
urls.py
❶
"""定義learning_logs的URL模式"""
❷ from
django.conf.urls import url
❸ from .
import views
❹
urlpatterns = [
# 主頁
❺ url(r'^$', views.index, name='index'),
]
為弄清楚當前位於哪個urls.py檔中,我們在這個檔開頭添加了一個文檔字串(見❶)。接下來,我們導入了函數url ,因為我們需要使用它來將URL映射到視圖(見❷)。我們還導入了模組views (見❸),其中的句點讓Python從當前的urls.py模組所在的資料夾中導入視圖。在這個模組中,變數urlpatterns 是一個清單,包含可在應用程式learning_logs 中請求的網頁(見❹)。
實際的URL模式是一個對函數url() 的調用,這個函數接受三個實參(見❸)。第一個是一個規則運算式。Django在urlpatterns 中查找與請求的URL字串匹配的規則運算式,因此規則運算式定義了Django可查找的模式。
我們來看看規則運算式r'^$' 。其中的r 讓Python將接下來的字串視為原始字串,而引號告訴Python規則運算式始於和終於何處。脫字元(^ )讓Python查看字串的開頭,而美元符號讓Python查看字串的末尾。總體而言,這個規則運算式讓Python查找開頭和末尾之間沒有任何東西的URL。Python忽略項目的基礎URL(http://localhost:8000/),因此這個規則運算式與基礎URL匹配。其他URL都與這個規則運算式不匹配。如果請求的URL不與任何URL模式匹配,Django將返回一個錯誤頁面。
url() 的第二個實參(見❺)指定了要調用的視圖函數。請求的URL與前述規則運算式匹配時,Django將調用views.index (這個視圖函數將在下一節編寫)。第三個實參將這個URL模式的名稱指定為index,讓我們能夠在代碼的其他地方引用它。每當需要提供到這個主頁的連結時,我們都將使用這個名稱,而不編寫URL。
注意 規則運算式通常被稱為regex,幾乎每種程式設計語言都使用它。它們的用途多得難以置信,但需要經過一定的練習才能熟悉。如果你不明白前面介紹的內容,也不用擔心,你在完成這個項目的過程中,將會看到很多規則運算式。
18.3.2 編寫視圖
視圖函數接受請求中的資訊,準備好生成網頁所需的資料,再將這些資料發送給流覽器——這通常是使用定義了網頁是什麼樣的範本實現的。
learning_logs中的文件views.py是你執行命令python manage.py startapp 時自動生成的,當前其內容如下:
views.py
from
django.shortcuts import render
# 在這裡創建視圖
當前,這個檔只導入了函數render() ,它根據視圖提供的資料渲染回應。下面的代碼演示了該如何為主頁編寫視圖:
from
django.shortcuts import render
def
index(request):
"""學習筆記的主頁"""
return render(request, 'learning_logs/index.html')
URL請求與我們剛才定義的模式匹配時,Django將在檔views.py中查找函數index() ,再將請求物件傳遞給這個視圖函數。在這裡,我們不需要處理任何資料,因此這個函數只包含調用render() 的代碼。這裡向函數render() 提供了兩個實參:原始請求物件以及一個可用於創建網頁的範本。下面來編寫這個範本。
18.3.3 編寫範本
範本定義了網頁的結構。範本指定了網頁是什麼樣的,而每當網頁被請求時,Django將填入相關的資料。範本讓你能夠訪問視圖提供的任何資料。我們的主頁視圖沒有提供任何資料,因此相應的範本非常簡單。
在資料夾learning_logs中新建一個資料夾,並將其命名為templates。在資料夾templates中,再新建一個資料夾,並將其命名為learning_logs。這好像有點多餘(我們在資料夾learning_logs中創建了資料夾templates,又在這個資料夾中創建了資料夾learning_logs),但建立了Django能夠明確解讀的結構,即便專案很大,包含很多應用程式亦如此。在最裡面的資料夾learning_logs中,新建一個檔,並將其命名為index.html,再在這個檔中編寫如下代碼:
index.html
<p>Learning
Log</p>
<p>Learning
Log helps you keep track of your learning, for any topic you're
learning
about.</p>
這個檔非常簡單。對於不熟悉HTML的讀者,這裡解釋一下:標籤<p></p> 標識段落;標籤<p> 指出了段落的開頭位置,而標籤</p> 指出了段落的結束位置。這裡定義了兩個段落:第一個充當標題,第二個闡述了使用者可使用“學習筆記”來做什麼。
現在,如果你請求這個項目的基礎URL——http://localhost:8000/,將看到剛才創建的網頁,而不是默認的Django網頁。Django接受請求的URL,發現該URL與模式r'^$' 匹配,因此調用函數views.index() ,這將使用index.html包含的範本來渲染網頁,結果如圖18-3所示。
創建網頁的過程看起來可能很複雜,但將URL、視圖和範本分離的效果實際上很好。這讓我們能夠分別考慮項目的不同方面,且在項目很大時,讓各個參與者可專注於其最擅長的方面。例如,資料庫專家可專注于模型,程式師可專注于視圖代碼,而Web設計人員可專注于範本。
動手試一試
18-5 膳食規劃程式 :假設你要創建一個應用程式,説明使用者規劃一周的膳食。為此,新建一個資料夾,並將其命名為meal_planner,再在這個資料夾中新建一個Django項目。接下來,新建一個名為meal_plans 的應用程式,並為這個專案創建一個簡單的主頁。
18-6 比薩店主頁 :在你為完成練習18-4而創建的項目Pizzeria中,添加一個主頁。
18.4 創建其他網頁
制定創建網頁的流程後,可以開始擴充“學習筆記”專案了。我們將創建兩個顯示資料的網頁,其中一個列出所有的主題,另一個顯示特定主題的所有條目。對於每個網頁,我們都將指定URL模式,編寫一個視圖函數,並編寫一個範本。但這樣做之前,我們先創建一個父範本,專案中的其他範本都將繼承它。
18.4.1 範本繼承
創建網站時,幾乎都有一些所有網頁都將包含的元素。在這種情況下,可編寫一個包含通用元素的父範本,並讓每個網頁都繼承這個範本,而不必在每個網頁中重複定義這些通用元素。這種方法能讓你專注于開發每個網頁的獨特方面,還能讓修改項目的整體外觀容易得多。
1. 父範本
我們首先來創建一個名為base.html的範本,並將其存儲在index.html所在的目錄中。這個檔包含所有頁面都有的元素;其他的範本都繼承base.html。當前,所有頁面都包含的元素只有頂端的標題。我們將在每個頁面中包含這個範本,因此我們將這個標題設置為到主頁的連結:
base.html
<p>
❶ <a href="{% url 'learning_logs:index'
%}">Learning Log</a>
</p>
❷ {% block
content %}{% endblock content %}
這個檔的第一部分創建一個包含項目名的段落,該段落也是一個到主頁的連結。為創建連結,我們使用了一個範本標籤 ,它是用大括弧和百分號({% %} )表示的。範本標籤是一小段代碼,生成要在網頁中顯示的資訊。在這個實例中,範本標籤{%
url 'learning_logs:index' %} 生成一個URL,該URL與learning_logs/urls.py中定義的名為index 的URL模式匹配(見❶)。在這個示例中,learning_logs 是一個命名空間 ,而index 是該命名空間中一個名稱獨特的URL模式。
在簡單的HTML頁面中,連結是使用錨 標籤定義的:
<a
href="link_url">link text</a>
讓範本標籤來生成URL,可讓連結保持最新容易得多。要修改專案中的URL,只需修改urls.py中的URL模式,這樣網頁被請求時,Django將自動插入修改後的URL。在我們的項目中,每個網頁都將繼承base.html,因此從現在開始,每個網頁都包含到主頁的連結。
在❶處,我們插入了一對塊標籤。這個塊名為content ,是一個預留位置,其中包含的資訊將由子範本指定。
子範本並非必須定義父範本中的每個塊,因此在父範本中,可使用任意多個塊來預留空間,而子範本可根據需要定義相應數量的塊。
注意 在Python代碼中,我們幾乎總是縮進四個空格。相比於Python檔,範本檔的縮進層級更多,因此每個層級通常只縮進兩個空格。
2. 子範本
現在需要重新編寫index.html,使其繼承base.html,如下所示:
index.html
❶ {%
extends "learning_logs/base.html" %}
❷ {% block
content %}
<p>Learning Log helps you keep track
of your learning, for any topic you're
learning about.</p>
❸ {%
endblock content %}
如果將這些代碼與原來的index.html進行比較,可發現我們將標題Learning Log替換成了從父範本那裡繼承的代碼(見❶)。子範本的第一行必須包含標籤{% extends
%} ,讓Django知道它繼承了哪個父範本。文件base.html位於資料夾learning_logs中,因此父範本路徑中包含learning_logs。這行代碼導入範本base.html的所有內容,讓index.html能夠指定要在content 塊預留的空間中添加的內容。
在❷處,我們插入了一個名為content 的{% block %} 標籤,以定義content 塊。不是從父範本繼承的內容都包含在content 塊中,在這裡是一個描述專案“學習筆記”的段落。在❸處,我們使用標籤{% endblock content %} 指出了內容定義的結束位置。
範本繼承的優點開始顯現出來了:在子範本中,只需包含當前網頁特有的內容。這不僅簡化了每個範本,還使得網站修改起來容易得多。要修改很多網頁都包含的元素,只需在父範本中修改該元素,你所做的修改將傳導到繼承該父範本的每個頁面。在包含數十乃至數百個網頁的專案中,這種結構使得網站改進起來容易而且快捷得多。
注意 在大型項目中,通常有一個用於整個網站的父範本——base.html,且網站的每個主要部分都有一個父範本。每個部分的父範本都繼承base.html,而網站的每個網頁都繼承相應部分的父範本。這讓你能夠輕鬆地修改整個網站的外觀、網站任何一部分的外觀以及任何一個網頁的外觀。這種配置提供了一種效率極高的工作方式,讓你樂意不斷地去改進網站。
18.4.2 顯示所有主題的頁面
有了高效的網頁創建方法,就能專注於另外兩個網頁了:顯示全部主題的網頁以及顯示特定主題中條目的網頁。所有主題頁面顯示使用者創建的所有主題,它是第一個需要使用資料的網頁。
1. URL模式
首先,我們來定義顯示所有主題的頁面的URL。通常,使用一個簡單的URL片段來指出網頁顯示的資訊;我們將使用單詞topics,因此URL http://localhost:8000/topics/將返回顯示所有主題的頁面。下面演示了該如何修改learning_logs/urls.py:
urls.py
"""為learning_logs定義URL模式"""
--snip--
urlpatterns = [
# 主頁
url(r'^$', views.index, name='index'),
# 顯示所有的主題
❶ url(r'^topics/$', views.topics, name='topics'),
]
我們只是在用於主頁URL的規則運算式中添加了topics/ (見❶)。Django檢查請求的URL時,這個模式與這樣的URL匹配:基礎URL後面跟著topics 。可以在末尾包含斜杠,也可以省略它,但單詞topics 後面不能有任何東西,否則就與該模式不匹配。其URL與該模式匹配的請求都將交給views.py中的函數topics() 進行處理。
2. 視圖
函數topics() 需要從資料庫中獲取一些資料,並將其發送給範本。我們需要在views.py中添加的代碼如下:
views.py
from django.shortcuts import render
❶ from .models
import Topic
def index(request):
--snip--
❷ def
topics(request):
"""顯示所有的主題"""
❸ topics = Topic.objects.order_by('date_added')
❹ context = {'topics': topics}
❺ return render(request,
'learning_logs/topics.html', context)
我們首先導入了與所需資料相關聯的模型(見❶)。函數topics() 包含一個形參:Django從伺服器那裡收到的request 物件(見❷)。在❸處,我們查詢資料庫——請求提供Topic 物件,並按屬性date_added 對它們進行排序。我們將返回的查詢集存儲在topics 中。
在❹處,我們定義了一個將要發送給範本的上下文。上下文是一個字典,其中的鍵是我們將在範本中用來訪問資料的名稱,而值是我們要發送給範本的資料。在這裡,只有一個鍵—值對,它包含我們將在網頁中顯示的一組主題。創建使用資料的網頁時,除物件request 和範本的路徑外,我們還將變數context 傳遞給render() (見❺)。
3. 範本
顯示所有主題的頁面的範本接受字典context ,以便能夠使用topics() 提供的資料。請創建一個檔,將其命名為topics.html,並存儲到index.html所在的目錄中。下面演示了如何在這個範本中顯示主題:
topics.html
{% extends
"learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
❶ <ul>
❷ {% for topic in topics %}
❸ <li>{{ topic }}</li>
❹ {% empty %}
<li>No topics have been added
yet.</li>
❺ {% endfor %}
❻ </ul>
{% endblock content %}
就像範本index.html一樣,我們首先使用標籤{% extends %} 來繼承base.html,再開始定義content 塊。這個網頁的主體是一個專案列表,其中列出了使用者輸入的主題。在標準HTML中,專案列表被稱為無序列表,用標籤<ul></ul> 表示。包含所有主題的專案清單始於❶處。
在❷處,我們使用了一個相當於for 迴圈的範本標籤,它遍歷字典context 中的清單topics 。範本中使用的代碼與Python代碼存在一些重要差別:Python使用縮進來指出哪些代碼行是for 迴圈的組成部分,而在範本中,每個for 迴圈都必須使用{% endfor
%} 標籤來顯式地指出其結束位置。因此在範本中,迴圈類似於下面這樣:
{%
for item in list %}
do something with each item
{%
endfor %}
在迴圈中,我們要將每個主題轉換為一個專案清單項。要在範本中列印變數,需要將變數名用雙花括弧括起來。每次迴圈時,❸處的代碼{{ topic }} 都被替換為topic 的當前值。這些花括弧不會出現在網頁中,它們只是用於告訴Django我們使用了一個範本變數。HTML標籤<li></li> 表示一個專案列表項,在標籤對<ul></ul> 內部,位於標籤<li> 和</li> 之間的內容都是一個專案清單項。
在❹處,我們使用了範本標籤{%
empty %} ,它告訴Django在列表topics 為空時該怎麼辦:這裡是列印一條消息,告訴使用者還沒有添加任何主題。最後兩行分別結束for 迴圈(見❺)和項目列表(見❻)。
現在需要修改父範本,使其包含到顯示所有主題的頁面的連結:
base.html
<p>
❶ <a href="{% url 'learning_logs:index'
%}">Learning Log</a> -
❷ <a href="{% url 'learning_logs:topics'
%}">Topics</a>
</p>
{% block content %}{% endblock content %}
我們在到主頁的連結後面添加了一個連字號(見❶),然後添加了一個到顯示所有主題的頁面的連結——使用的也是範本標籤url (見❷)。這一行讓Django生成一個連結,它與learning_logs/
urls.py中名為topics 的URL模式匹配。
現在如果你刷新流覽器中的主頁,將看到連結Topics。按一下這個連結,將看到類似於圖18-4所示的網頁。
18.4.3 顯示特定主題的頁面
接下來,我們需要創建一個專注於特定主題的頁面——顯示該主題的名稱及該主題的所有條目。同樣,我們將定義一個新的URL模式,編寫一個視圖並創建一個範本。我們還將修改顯示所有主題的網頁,讓每個專案清單項都是一個連結,按一下它將顯示相應主題的所有條目。
1. URL模式
顯示特定主題的頁面的URL模式與前面的所有URL模式都稍有不同,因為它將使用主題的id 屬性來指出請求的是哪個主題。例如,如果使用者要查看主題Chess(其id 為1)的詳細頁面,URL將為http://localhost:8000/topics/1/。下面是與這個URL匹配的模式,它包含在learning_logs/urls.py中:
urls.py
--snip--
urlpatterns
= [
--snip--
# 特定主題的詳細頁面
url(r'^topics/(?P<topic_id>\d+)/$',
views.topic, name='topic'),
]
我們來詳細研究這個URL模式中的規則運算式——r'^topics/(?P<topic_id>\d+)/$' 。r 讓Django將這個字串視為原始字串,並指出規則運算式包含在引號內。這個運算式的第二部分(/(?P<topic_id>\d+)/ )與包含在兩個斜杠內的整數匹配,並將這個整數存儲在一個名為topic_id 的實參中。這部分運算式兩邊的括弧捕獲URL中的值;?P<topic_id> 將匹配的值存儲到topic_id 中;而運算式\d+ 與包含在兩個斜杆內的任何數字都匹配,不管這個數字為多少位元。
發現URL與這個模式匹配時,Django將調用視圖函數topic() ,並將存儲在topic_id 中的值作為實參傳遞給它。在這個函數中,我們將使用topic_id 的值來獲取相應的主題。
2. 視圖
函數topic() 需要從資料庫中獲取指定的主題以及與之相關聯的所有條目,如下所示:
views.py
--snip--
❶ def
topic(request, topic_id):
"""顯示單個主題及其所有的條目"""
❷ topic = Topic.objects.get(id=topic_id)
❸ entries = topic.entry_set.order_by('-date_added')
❹ context = {'topic': topic, 'entries':
entries}
❺ return render(request, 'learning_logs/topic.html',
context)
這是第一個除request 物件外還包含另一個形參的視圖函數。這個函數接受規則運算式(?P<topic_id>\d+) 捕獲的值,並將其存儲到topic_id 中(見❶)。在❷處,我們使用get() 來獲取指定的主題,就像前面在Django shell中所做的那樣。在❸處,我們獲取與該主題相關聯的條目,並將它們按date_added 排序:date_added 前面的減號指定按降冪排列,即先顯示最近的條目。我們將主題和條目都存儲在字典context 中(見❹),再將這個字典發送給範本topic.html(見❺)。
注意 ❷處和❸處的代碼被稱為查詢,因為它們向資料庫查詢特定的資訊。在自己的項目中編寫這樣的查詢時,先在Django shell中進行嘗試大有裨益。相比於編寫視圖和範本,再在流覽器中檢查結果,在shell中執行代碼可更快地獲得回饋。
3. 範本
這個範本需要顯示主題的名稱和條目的內容;如果當前主題不包含任何條目,我們還需向用戶指出這一點:
topic.html
{% extends 'learning_logs/base.html' %}
{% block content %}
❶ <p>Topic: {{ topic }}</p>
<p>Entries:</p>
❷ <ul>
❸ {% for entry in entries %}
<li>
❹ <p>{{ entry.date_added|date:'M d,
Y H:i' }}</p>
❺ <p>{{ entry.text|linebreaks
}}</p>
</li>
❻ {% empty %}
<li>
There are no entries for this topic
yet.
</li>
{% endfor %}
</ul>
{% endblock content %}
像這個專案的其他頁面一樣,這裡也繼承了base.html。接下來,我們顯示當前的主題(見❶),它存儲在範本變數{{ topic
}} 中。為什麼可以使用變數topic 呢?因為它包含在字典context 中。接下來,我們開始定義一個顯示每個條目的專案清單(見❷),並像前面顯示所有主題一樣遍歷條目(見❸)。
每個專案清單項都將列出兩項資訊:條目的時間戳記和完整的文本。為列出時間戳記(見❹),我們顯示屬性date_added 的值。在Django範本中,分隔號(| )表示範本篩檢程式——對範本變數的值進行修改的函數。篩檢程式date: 'M
d, Y H:i' 以這樣的格式顯示時間戳記:January 1, 2015 23:00。接下來的一行顯示text 的完整值,而不僅僅是entry 的前50個字元。篩檢程式linebreaks (見❺)將包含分行符號的長條目轉換為流覽器能夠理解的格式,以免顯示為一個不間斷的文字區塊。在❻處,我們使用範本標籤{% empty %} 列印一條消息,告訴使用者當前主題還沒有條目。
4. 將顯示所有主題的頁面中的每個主題都設置為連結
在流覽器中查看顯示特定主題的頁面前,我們需要修改範本topics.html,讓每個主題都連結到相應的網頁,如下所示:
topics.html
--snip--
{% for topic in topics %}
<li>
<a href="{% url
'learning_logs:topic' topic.id %}">{{ topic }}</a>
</li>
{% empty %}
--snip--
我們使用範本標籤url 根據learning_logs中名為topic 的URL模式來生成合適的連結。這個URL模式要求提供實參topic_id ,因此我們在範本標籤url 中添加了屬性topic.id 。現在,主題清單中的每個主題都是一個連結,連結到顯示相應主題的頁面,如http://localhost:8000/topics/1/。
如果你刷新顯示所有主題的頁面,再按一下其中的一個主題,將看到類似於圖18-5所示的頁面。
動手試一試
18-7 範本文檔 :請流覽Django範本文檔,其網址為https://docs.djangoproject.com/en/1.8/ref/templates/ 。自己開發專案時,可再回過頭來參考該文檔。
18-8 比薩店頁面 :在練習18-6中開發的專案Pizzeria中添加一個頁面,它顯示供應的比薩的名稱。然後,將每個比薩名稱都設置成一個連結,按一下這種連結將顯示一個頁面,其中列出了相應比薩的配料。請務必使用範本繼承來高效地創建頁面。
18.5 小結
在本章中,你首先學習了如何使用Django框架來創建Web應用程式。你制定了簡要的專案規範,在虛擬環境中安裝了Django,創建了一個專案,並核實該項目已正確地創建。你學習了如何創建應用程式,以及如何定義表示應用程式資料的模型。你學習了資料庫,以及在你修改模型後,Django可為你遷移資料庫提供什麼樣的説明。你學習了如何創建可訪問管理網站的超級用戶,並使用管理網站輸入了一些初始資料。
你還探索了Django shell,它讓你能夠在終端會話中處理專案的資料。你學習了如何定義URL、創建視圖函數以及編寫為網站創建網頁的範本。最後,你使用了範本繼承,它可簡化各個範本的結構,並使得修改網站更容易。
在第19章,我們將創建對用戶友好而直觀的網頁,讓用戶無需通過管理網站就能添加新的主題和條目,以及編輯既有的條目。我們還將添加一個使用者註冊系統,讓使用者能夠創建帳戶和自己的學習筆記。讓任意數量的用戶都能與之交互,是Web應用程式的核心所在。






0 留言:
發佈留言