Django快速入門-檢視


檢視是一個網頁「型別」在Django應用程式,提供特定的功能,並且具有特定的模板。例如,在一個部落格的應用程式,可能有以下幾個檢視:
  • 部落格首頁 - 顯示最後的幾個文章。
  • 進入「detail」頁面- 對單個專案永久連結頁面。
  • 年存檔頁 - 顯示所有在給定年份各月的條目。
  • 月存檔頁 - 顯示所有給定月份各天的所有項。
  • 天存檔頁 - 顯示某一天所有條目。
  • 評論操作 - 處理發布評論的一個給定輸入。
在我們的 poll 應用程式,有以下四個檢視:
  • 問題的「index」頁- 顯示最後幾個問題。
  • 問題的「detail」頁 - 顯示一個問題文字,沒有結果但有一個表單用來投票。
  • 問題的「results」頁面 - 顯示結果一個特定問題。
  • 投票操作 - 處理投票在一個特定的問題進行具體選擇。

在Django中,網頁和其他內容由檢視提供。每個檢視由一個簡單的Python函式來表示(或方法,基於類的檢視)。Django會選擇一個檢視通過考察多數民眾贊成請求的URL(準確地說,在域名之後URL的一部分)。

一個URL模式是一個簡單的URL的一般形式 - 例如:/newsarchive/<year>/<month>/.

編寫更多的檢視

現在,讓我們新增一些檢視在 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=<HttpRequest object>, 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 %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% 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()函式。

如果物件不存在將引發HTTP404。

還有一個get_list_or_404()函式,它的工作原理就像get_object_or_404()- 除了使用 filter()而不是get()方法。如果列表是空的它會引起HTTP404。

使用模板系統

回到我們的 polls 應用程式 detail() 檢視。由於上下文變數的問題,這裡的 polls/detail.html 模板看起來是這樣的:

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

模板系統採用點查詢語法來存取變數屬性。在這個例子 {{question.question_text }},第一個Django確實在question物件字典查詢。 如果找不到,它再嘗試屬性查詢 – 如果屬性查詢失敗,它會嘗試一個列表索引查詢。
現在測試我們上面編寫的程式碼,在瀏覽器中開啟:http://127.0.0.1:8000/polls/5/ 得到結果如下:

刪除模板寫死網址

請記住,當我們在 polls/index.html 連結到一個問題,連結被寫死的部分是這樣的:

<li><ahref="/polls/{{question.id}}/">{{question.question_text}}</a></li>

使用此寫死,緊密耦合的方法的問題是:它在更改專案的URL用了很多模板。不過,既然 polls.urls模組中定義名稱引數url() 函式,您可以通過使用 {% url %}模板刪除標籤在URL組態中定義的特定URL路徑的依賴:

<li><ahref="{%url'detail'question.id%}">{{question.question_text}}</a></li>

這種工作方式是通過為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 檔案新增以下程式碼:

<li><ahref="{%url'detail'question.id%}">{{question.question_text}}</a></li>

使其指向在名稱空間 detail 檢視,開啟 polls/templates/polls/index.html 檔案如下:

<li><ahref="{%url'polls:detail'question.id%}">{{question.question_text}}</a></li>
程式碼下載:http://pan.baidu.com/s/1o7iWsWi