Django快速入門-視圖
視圖是一個網頁「類型」在Django應用程序,提供特定的功能,並且具有特定的模板。例如,在一個博客的應用程序,可能有以下幾個視圖:
博客首頁 - 顯示最後的幾個文章。
進入「detail」頁面- 對單個項目永久鏈接頁面。
年存檔頁 - 顯示所有在給定年份各月的條目。
月存檔頁 - 顯示所有給定月份各天的所有項。
天存檔頁 - 顯示某一天所有條目。
評論操作 - 處理髮布評論的一個給定輸入。
在我們的 poll 應用程序,有以下四個視圖:
問題的「index」頁- 顯示最後幾個問題。
問題的「detail」頁 - 顯示一個問題文本,沒有結果但有一個表單用來投票。
問題的「results」頁面 - 顯示結果一個特定問題。
投票操作 - 處理投票在一個特定的問題進行具體選擇。
在Django中,網頁和其他內容由視圖提供。每個視圖由一個簡單的Python函數來表示(或方法,基於類的視圖)。Django會選擇一個視圖通過考察多數民衆贊成請求的URL(準確地說,在域名之後URL的一部分)。
一個URL模式是一個簡單的URL的一般形式 - 例如:/newsarchive/
編寫更多的視圖
現在,讓我們添加一些視圖在 polls/views.py。這些視圖略有不同,因爲他們需要一個參數:
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
這些新的視圖加入到 polls.urls 模塊中如下的 url() 調用,polls/urls.py文件中的代碼如下:
from django.conf.urls import url
from . import views
urlpatterns = [
# ex: /polls/
url(r'^$', views.index, name='index'),
# ex: /polls/5/
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
您可以在瀏覽器打開「/polls/34/」。它會運行detail()方法,並顯示任何提供的URL內容。 再次嘗試訪問 「/polls/34/results/」 and 「/polls/34/vote/」 – 這將顯示佔位符結果和投票頁面。
include() 可以很容易包含入插件和網址。因爲polls是在它們自己的URL配置(polls/urls.py),它們可以放置在「/polls/」,或 「/fun_polls/」,或在「/content/polls/」,或任何其它路徑的根,應用程序仍然可以工作。
下面是如果用戶進入「/polls/34/」,在這個系統會發生什麼:
Django會找到匹配'^polls/'
然後,Django會去掉匹配的文本("polls/"),併發送剩餘的文本 – "34/" – 到'polls.urls'URL配置用於進一步處理相匹配 r'^(?P<question_id>[0-9]+)/$'從而調用detail() 視圖,如下所示:
detail(request=
, question_id='34')
question_id='34' 是來自 (?P<question_id>[0-9]+)的一部分,用周圍的模式括號「捕捉」匹配該模式文本,並將其作爲參數傳遞給視圖函數; ?P<question_id> 定義了將被用來識別所述匹配的模式的名稱; 以及[0-9]+ 正則表達式匹配一個數字序列(在一個數字)。
由於URL模式是正則表達式,可以使用它來做一些事情,沒有任何限制。而且也沒有必要添加URL爲.html – 除非你想,在這種情況下,你可以這樣做:
url(r'^polls/latest\.html$', views.index),
編寫視圖實現功能
每個視圖負責做兩件事情之一:返回包含所請求的頁面內容的 HttpResponse 對象,或拋出一個異常,如HTTP 404。 修改polls/views.py文件代碼如下:
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
Leave the rest of the views (detail, results, vote) unchanged
在這裏有一個問題就,通過:網頁設計是硬編碼在視圖中。如果想改變頁面的樣子,必須編輯這個 Python 代碼。因此,讓我們使用 Django 模板系統通過創建視圖可以使用模板來分開Python 的代碼。polls/templates/polls/index.html 將下面的代碼:
{% if latest_question_list %}
- {{ question.question_text }}
{% for question in latest_question_list %}
{% endfor %}
{% else %}
No polls are available.
{% endif %}
現在我們來更新首頁視圖 polls/views.py使用以下模板(代碼):
from django.http import HttpResponse
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
該代碼加載模板調用polls/index.html,然後傳遞給它的上下文。上下文是一個字典以Python對象映射模板變量名。現在訪問URL(http://127.0.0.1:8000/polls/)查看結果 :
快捷方式: render()
這是一個非常習慣用法來加載模板,填充上下文中和渲染模板的結果返回一個HttpResponse對象。Django提供了一個捷徑。下面是完整的index() 視圖,改寫polls/views.py爲:
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
請注意,當在各個視圖做到了這一點,我們不再需要導入加載器和HttpResponse對象(想保留HttpResponse,如果仍然有短截 detail, results, 和 vote 方法。
引發404錯誤
現在,讓我們來解決這個問題詳細視圖 - 顯示爲給定的民意調查問題文本的頁面。這裏添加視圖代碼(polls/views.py):
from django.http import Http404
from django.shortcuts import render
from .models import Question
...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
注意這裏:視圖引發HTTP404異常,如果與請求ID的問題並不存在。
我們將討論可以把 polls/detail.html 在後面做一些修改,但如果想快速使用上面的例子,polls/templates/polls/detail.html 文件只需包含:
{{question}}
引發 404 錯誤,現在我們請求一個不存在問題,如:http://127.0.0.1:8000/polls/100/,顯示結果如下:
快捷方式: get_object_or_404()
如果對象不存在的一個非常習慣用法使用get()並引發HTTP404錯誤。Django提供了一個捷徑。下面是 detail() 視圖,polls/views.py 改寫:
from django.shortcuts import get_object_or_404, render
from .models import Question
...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
get_object_or_404()函數接受一個Django模型作爲第一個參數和關鍵字任意參數數量,它傳遞到模型管理的 get()函數。
還有一個get_list_or_404()函數,它的工作原理就像get_object_or_404()- 除了使用 filter()而不是get()方法。如果列表是空的它會引起HTTP404。
使用模板系統
回到我們的 polls 應用程序 detail() 視圖。由於上下文變量的問題,這裏的 polls/detail.html 模板看起來是這樣的:
{{ question.question\_text }}
-
{% for choice in question.choice\_set.all %}
- {{ choice.choice\_text }} {% endfor %}
模板系統採用點查詢語法來訪問變量屬性。在這個例子 {{question.question_text }},第一個Django確實在question對象字典查找。 如果找不到,它再嘗試屬性查詢 – 如果屬性查找失敗,它會嘗試一個列表索引查找。
現在測試我們上面編寫的代碼,在瀏覽器中打開:http://127.0.0.1:8000/polls/5/ 得到結果如下:
刪除模板硬編碼網址
請記住,當我們在 polls/index.html 鏈接到一個問題,鏈接被硬編碼的部分是這樣的:
使用此硬編碼,緊密耦合的方法的問題是:它在更改項目的URL用了很多模板。不過,既然 polls.urls模塊中定義名稱參數url() 函數,您可以通過使用 {% url %}模板刪除標籤在URL配置中定義的特定URL路徑的依賴:
這種工作方式是通過爲polls.urls模塊中指定查找的URL定義。可以準確地看到'detail'的URL名稱定義如下:
...
the 'name' value as called by the {% url %} template tag
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
如果你想要把投票詳細視圖的URL更改成其它的,也許像 polls/specifics/12/ 取代在模板(或templates),需要在 polls/urls.py 改變它:
...
added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
命名空間URL名稱
本教程項目只有一個應用程序 - polls。在實際的Django項目中,可能有五個,十個,二十個或更多的應用程序。Django 如何區分它們的URL的名稱? 例如,投票應用程序有一個詳細視圖,因此可能會在一個博客的同一個項目也有相同的應用程序。如何使用 {% url %} 模板標籤讓Django知道創建一個URL哪些應用有這樣視圖?
答案就是將命名空間添加到URLconf。在polls/urls.py文件,繼續前進,添加應用程序名稱設置應用程序命名空間,打開 polls/urls.py:
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
現在修改 polls/index.html 模板,打開 polls/templates/polls/index.html 文件添加以下代碼:
使其指向在命名空間 detail 視圖,打開 polls/templates/polls/index.html 文件如下: