---恢復內容開始---
昨天敲得忘記保存了。。。然后自動恢復了一些,有點難受。。。就當鞏固一遍吧。
18.1 建立項目
18.1.1 制定規范
編寫一個名為“學習筆記”的Web應用程序,讓用戶能夠記錄感興趣的主題,並在學習每個主題的過程中添加日志條目。“學習筆記”的主頁對這個網站進行描述,並邀請用戶注冊或登錄。用戶登錄后,就可以創建新主題、添加新條目以及閱讀既有的條目。
18.1.2 建立虛擬環境
要使用Django,首先需要建立一個虛擬工作環境。虛擬工作環境是系統的一個位置,你可以再其中安裝包,並將其與其他Python包隔離。
為項目新建一個目錄,將其命名為learning_log,再在終端中切換到這個目錄,並創建一個虛擬環境。
18.1.4 激活虛擬環境
Windows系統,使用命令11_env\Scripts\activate(不包含source)
要停止使用虛擬環境,可執行命令deactivate
18.1.5 安裝Django
18.1.6 在Django中創建項目
在仍然處於活動的虛擬環境的情況下(11_env包含在括號內),執行命令新建一個項目:
這個命令末尾的句點讓新項目使用合適的目錄結構,千萬不能忘了這個句點,否則部署應用程序時,將遭遇一些配置問題。
目錄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 創建數據庫
為給項目“學習筆記”創建數據庫,請在處於活躍虛擬環境中的情況下執行下面的命令:
python manage.py migrate
我們將修改數據庫稱為遷移數據庫,首次執行命令migrate時,將讓Django確保數據庫與項目的當前狀態匹配。在使用SQLite的新項目中首次執行這個命令時,Django將新建一個數據庫。
18.1.8 查看項目
下面核實Django是否正確地創建了項目。為此,可執行命令runserver:
python manage.py runserver
Django通過檢查確認正確地創建了項目;指出了使用的Django版本以及當前使用的設置文件的名稱;它指出了項目的URL。
Django啟動一個服務器,讓你能夠查看系統中的項目,了解它們的工作情況。
現打開一款Web瀏覽器,並輸入URL:http://localhost:8000/;如果不管用,請輸入http://127.0.0.1:8000/
18.2 創建應用程序
Django項目由一系列應用程序組成,它們協同工作,讓項目成為一個整體。我們暫時只創建一個應用程序,它將完成項目的大部分工作。
當前,在前面打開的終端窗口中應該還運行着runserver。請再打開一個終端窗口(或標簽頁),並切換到manage.py所在的目錄。激活虛擬環境,再執行命令startapp:
python manage.py startapp learning_logs
命令startapp appname讓Django建立創建應用程序所需的基礎設施。項目目錄增加一個文件夾learning_logs。打開這個文件夾,其中最重要的文件是models.py、admin.py和views.py。我們將使用models.py來定義我們要在應用程序中管理的數據。
18.2.1 定義模型
打開文件models.py,下面表示用戶將要存儲的主題的模型:
from django.db import models # 定義了一個名為Topic的類,它繼承了Model—Django中一個定義了模型基本功能的類 # 屬性text是一個CharField—由字符或文本組成的數據。需要存儲少量的文本,如名稱、標題或城市時,可以使用 # date_added是一個DateTimeField—記錄日期和時間的數據。 class Topic(models.Model): """用戶學習主題""" text = models.CharField(max_length=200) date_added = models.DateTimeField(auto_now_add=True) def __str__(self): """返回模型的字符串表示""" return self.text
注意,要或許可在模型中使用的各種字段,請參閱Django Model Field Reference(Django模型字段參考),其網址為https://docs.djangoproject.com/en/1.8/ref/models/fields/
18.2.2 激活模型
要使用模型,必須讓Django將應用程序包含到項目中。為此,打開dettings.py,你將看到下面的片段,這是一個元組,告訴Django是由哪些元組組成的。添加learning_logs。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # My apps 'learning_logs', ]
接下來,需要讓Django修改數據庫,使其能夠存儲與模型Topic相關的信息。為此在終端窗口執行命令:
python manage.py makemigrations learning_logs
輸出表明Django創建了一個名為0001_initial.py的遷移文件,這個文件將在數據庫中為模型Topic創建一個表。
下面來應用這種遷移。讓Django替我們修改數據庫:
python manage.py migrate
每當需要修改“學習筆記”管理的數據時,都采取如下三個步驟:修改models.py;對learning_logs調用makemigrations;讓Django遷移項目。
18.2.3 Django管理網站
為應用程序定義模型,Django提供的管理網站讓你能夠輕松地處理模型。網站的管理員可使用管理網站,但普通用戶不能使用。
1、創建超級用戶
python manage.py createsuperuser
昨天的數據丟失啦,只能重新創建一個管理員了,密碼需要數字和字母的結合,email地址可為空。
2、向管理網站注冊模型
Django自動在管理網站中添加了一些模型,如User和Group,但對於我們創建的模型,必須手工注冊。
打開admin.py文件,為向管理網站注冊Topic,請輸入以下代碼:
from django.contrib import admin from learning_logs.models import Topic admin.site.register(Topic)
現在,使用超級用戶賬戶訪問管理網站:http://localhost:8000/admin,這個網頁讓你能夠添加和修改用戶和用戶組,還可以管理與剛才定義的模型Topic相關的數據。
3、添加主題
18.2.4 定義模型Entry
要記錄學到的國際象棋和攀岩知識,需要為用戶可在學習筆記中添加的條目定義模型。每個條目都與特定主題相關聯,這種關系被稱為多對一關系,即多個條目可關聯到同一主題。
下面是模型Entry的代碼:
class Entry(models.Model): """學到的有關某個主題的具體知識""" # ForeignKey外鍵,引用了數據庫中的另一條記錄; # 每個主題創建時,都給它分配了一個鍵(或ID)。 # 嵌套Meta類,Meta存儲用於管理模型的額外信息。 topic = models.ForeignKey(Topic,on_delete=models.CASCADE) text = models.TextField() date_added = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = 'entries' def __str__(self): return self.text[:50]+"..."
18.2.5 遷移模型Entry
由於我們添加了一個新模型,因此需要再次遷移數據庫。你將慢慢地對這個過程了如指掌:修改models.py,執行命令python manage.py makemigrations app_name,再執行命令python manage.py migrate。
下面來遷移數據庫並查看輸出:
18.2.6 向管理網站注冊Entry
from django.contrib import admin from learning_logs.models import Topic,Entry admin.site.register(Topic) admin.site.register(Entry)
返回到http://localhost:8000/admin/(注意需要重新開啟服務器)
下面添加條目:
18.2.7 Django shell
輸入一些數據,就可以通過交互終端會話以編程方式查看這些數據了。這種交互式環境稱為Django shell,是測試項目和排除其他故障的理想之地。
返回一個列表,稱為查詢集(queryset)
下面演示了如何查看分配給每個主題對象的ID:
知道對象的ID后,就可獲取該對象並查看其任何屬性。下面來看看主題Chess的屬性text和date_added的值:
我們還可以查看與主題相關聯的條目。前面我們給模型Entry定義了屬性topic,這是一個ForeignKey,將條目與主題關聯起來。利用這種關聯,Django能夠獲取與特定主題相關聯的所有條目:
為通過外鍵關系獲取數據,可使用相關模型的小寫名稱、下划線和單詞set。
注意,每次修改模型后,你都需要重啟shell,這樣才能看到修改的效果。如果想要退出shell會話,Windows系統可以按ctrl+Z,再按回車鍵。
p369 18-2簡短的條目,使得50字以內不顯示省略號。
class Meta: verbose_name_plural = 'entries' def __str__(self): if (len(self.text))>50: return self.text[:50]+"..." else: return self.text
18.3 創建網頁:學習筆記主頁
使用Django創建網頁的過程通常分三個階段:定義URL、編寫視圖和編寫模塊。首先,你必須定義URL模式。URL模式描述了URL是如何設計的,讓Django知道如何將瀏覽器請求於網站URL匹配,以確定返回哪個網頁。
每個URL都被映射到特定的視圖——視圖函數獲取並處理網頁所需的數據。視圖通常調用一個模板,后者生成瀏覽器能夠理解的網頁。
18.3.1 映射URL
當前,基礎URL(http://localhost:8000/)返回默認的Django網站,讓我們知道正確地建立了項目。我們將修改這一點,將這個基礎URL映射帶“學習筆記”主頁。
打開項目主文件夾learning_log中的文件urls.py:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ]
前兩行導入為項目和管理網站URL的函數和模塊。這個文件的主題定義了變量urlpatterns。在這個針對整個項目的urls.py文件中,變量urlpatterns包含項目中的應用程序的URL。我們需要包含learning_logs的URL:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'',include('learning_logs.urls',namespace='learning_logs')), ]
添加了一行代碼,讓我們能夠將learning_logs的URL同項目中的其他URL區分開來,這在項目開始擴展時很有幫助。
默認的urls.py包含在文件夾learning_log中,現在我們需要在文件夾learning_logs中創建另一個urls.py文件:
"""定義learning_logs的URL模式""" from django.conf.urls import url from .import views urlpatterns = [ # 主頁 url(r'^$',views.index,name='index') ]
實際的URL模式是一個對函數url()的調用,這個函數接受三個實參。第一個是一個正則表達式。r'^$',其中r讓Python將接下來的字符串視為原始字符串,而引號告訴Python正則表達式始於和終於何處。脫字符(^)讓Python查看字符串的開頭,而美元符號讓Python查看字符串的末尾。總體而言,這個正則表達式讓Python查找開頭和末尾之間沒有任何東西的URL。url的第二個實參指定了要調用的視圖函數。第三個實參將這個URL模式的名稱指定為index,讓我們能夠在代碼的其他地方引用它。
18.3.2 編寫視圖
視圖函數接受請求中的信息,准備好生成網頁所需的數據,再將這些數據發送給瀏覽器。
learning_logs中的文件views.py是你執行命令python manage.py startapp時自動生成的,當前其內容如下:
from django.shortcuts import render # Create your views here.
為主頁編寫視圖:
from django.shortcuts import render # Create your views here. def index(request): """學習筆記的主頁""" return render(request,'learning_logs/index.html')
URL請求與我們剛才定義的模式匹配時,Django將在文件views.py中查找函數index,再將請求對象傳遞給這個視圖函數。render()提供了兩個實參:原始請求對象以及一個可用於創建網頁的模板。下面來編寫這個模板。
18.3.3 編寫模板
在文件夾learning_logs中新建一個文件夾,並將其命名為templates。在文件夾templates中,再創建一個文件夾,並將其命名為learning_logs,在最里面的文件夾learning_logs中,新建一個文件,並將其命名為index.html,再在這個文件中編寫如下代碼:
<p>Learning Log</p> <p>Learning Log helps you keep track of your learning,for any topic you're learning about</p>
現在,如果你請求這個項目的基礎URL——http://localhost:8000/,將看到剛才創建的網頁,而不是磨人的Django網頁。
18.4 創建其他網頁
我們將創建兩個顯示數據的網頁,其中一個列出所有的主題,另一個顯示特定主題的所有條目。對於每個網頁我們都將指定URL模式,編寫一個視圖函數,並編寫一個模板。但這樣做之前,先創建一個父模板,項目中的其他模板都繼承它。
18.4.1 模板繼承
1、父模板
首先創建一個名為base.html的模板,並將其存儲在index.html所在目錄中。這個文件包含所有頁面都有的元素;其他模板都繼承base.html。
<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> </p> {% block content %}{% endblock content %}
這個文件的第一部分創建一個包含項目名的段落,該段落也是一個到主頁的鏈接。為創建鏈接,我們使用了一個模板標簽,它是用大括號和百分號表示的。
在簡單的HTML頁面中,鏈接是使用錨標簽定義的:
<a href='link_url>link text</a>
插入了塊標簽,這個快名為content,是一個占位符,其中包含的信息將由子模板指定。
2、子模板
現在需要重新編寫index.html,使其繼承base.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 %}
18.4.2 顯示所有主題的頁面
1、URL模式
首先,定義顯示所有主題的頁面的URL。修改learning_logs/urls.py:
"""定義learning_logs的URL模式""" from django.conf.urls import url from .import views urlpatterns = [ # 主頁 url(r'^$',views.index,name='index'), # 顯示所有的主題 url(r'^topics/$',views.topics,name='topics'), ]
我們只是在正則表達式中添加了topics/。Django檢查請求的URL時,這個模式與這樣的URL匹配:基礎URL后面跟着topics。可以在末尾包含斜杠,也可以省略它,但單詞topics后面不能有任何東西,否則就與該模式不匹配。其URL與該模式匹配的請求都將交給views.py中的函數topics()進行處理。
2、視圖
函數topics()需要從數據庫中獲取一些數據,並將其發送給模板。我們需要在views.py中添加的代碼如下:
from django.shortcuts import render from .models import Topic # Create your views here. def index(request): """學習筆記的主頁""" return render(request,'learning_logs/index.html') def topics(request): """顯示所有的主題""" topics = Topic.objects.order_by('date_added') context = {'topics':topics} return render(request,'learning_logs/topics.html',context)
3、模板
創建一個文件,將其命名為topics.html,並存儲到index.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 %}
這個網頁的主體是一個項目列表,其中列出了用戶輸入的主題。在標准HTML中,項目列表被稱為無序列表,用標簽<ul></ul>表示。
在模塊中,每個for循環都必須使用{% endfor %}標簽來顯示地指出其結束的位置。因此在模塊中,循環類似於下面這樣:
{% for item in list %} do something witn each item {% endfor %}
現在需要修改父模板,使其包含到顯示所有主題的頁面的鏈接:
<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> - <a href="{% url 'learning_logs:topics'%}">Topics</a> </p> {% block content %}{% endblock content %}
我們在主頁的鏈接后面添加了一個連字符,然后添加了一個到顯示所有主題的頁面的鏈接。
現在如果刷新瀏覽器的主頁,將看到鏈接Topics。單擊這個鏈接,將看到:
18.4.3 顯示特定主題的頁面
接下來,我們需要創建一個專注於特定主題的頁面——顯示該主題的名稱及該主題的所有條目。
1、URL模式
"""定義learning_logs的URL模式""" from django.conf.urls import url from .import views urlpatterns = [ # 主頁 url(r'^$',views.index,name='index'), # 顯示所有的主題 url(r'^topics/$',views.topics,name='topics'), # 顯示特定主題的詳細頁面 url(r'^topics/(?P<topic_id>\d+)/$',views.topic,name='topic'), ]
2、視圖
def topic(request,top_id): """顯示單個主題及其所有的條目""" topic = Topic.objects.get(id=top_id) entries = topic.entry_set.order_by('-date_added') context = {'topic':topic,'entries':entries} return render(request,'learning_logs/topic.html',context)
date_added前面的減號指定降序排序。
3、模板
{% 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 %}
顯示當前的主題,它存儲在模板變量{{topic}}中。為什么使用變量topic呢?因為它包含在字典context中。
每個項目列表都將列出兩項信息:條目的時間戳和完整的文本。未列出時間戳,我們顯示屬性gate_added的值。在Django模板中,豎線表示模板過濾器——對模板變量的值進行修改的函數。過濾器linebreaks將包含換行符的長條目轉換為瀏覽器能夠理解的格式,一面顯示為一個不間斷的文本塊。
4、將顯示所有主題的頁面中的每個主題都設置為連接。
在瀏覽器中查看特定主題的頁面前,我們需要修改模板topics.html,讓每個主題都鏈接到相應的網頁:
{% extends "learning_logs/base.html" %} {% block content %} <p>Topics</p> <ul> {% for topic in topics %} <li> <a href="{% url 'learning_logs:topic.id%}">{{ topic }}</a> </li> {% empty %}} <li>No topics have been added yet.</li> {% endfor %} </ul> {% endblock content %}
---恢復內容結束---