W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
Django 中的視圖的概念是「一類具有相同功能和模板的網(wǎng)頁的集合」。比如,在一個博客應(yīng)用中,你可能會創(chuàng)建如下幾個視圖:
而在我們的投票應(yīng)用中,我們需要下列幾個視圖:
在 Django 中,網(wǎng)頁和其他內(nèi)容都是從視圖派生而來。每一個視圖表現(xiàn)為一個 Python 函數(shù)(或者說方法,如果是在基于類的視圖里的話)。Django 將會根據(jù)用戶請求的 URL 來選擇使用哪個視圖(更準(zhǔn)確的說,是根據(jù) URL 中域名之后的部分)。
URL 樣式是 URL 的一般形式 - 例如:?/newsarchive/<year>/<month>/
?。
為了將 URL 和視圖關(guān)聯(lián)起來,Django 使用了 '?URLconfs
?' 來配置。URLconf 將 URL 模式映射到視圖。
現(xiàn)在讓我們向 ?polls/views.py
? 里添加更多視圖。這些視圖有一些不同,因為他們接收參數(shù):
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)
把這些新視圖添加進(jìn) ?polls.urls
? 模塊里,只要添加幾個 ?url()
? 函數(shù)調(diào)用就行:
from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
然后看看你的瀏覽器,如果你轉(zhuǎn)到 "/polls/5/" ,Django 將會運行 ?detail()
? 方法并且展示你在 URL 里提供的問題 ID。再試試 "/polls/5/results/" 和 "/polls/5/vote/" ——你將會看到暫時用于占位的結(jié)果和投票頁。
當(dāng)某人請求你網(wǎng)站的某一頁面時——比如說, "/polls/5/" ,Django 將會載入 ?mysite.urls
? 模塊,因為這在配置項 ?ROOT_URLCONF
中設(shè)置了。然后 Django 尋找名為 ?urlpatterns
變量并且按序匹配正則表達(dá)式。在找到匹配項 ?'polls/'
?,它切掉了匹配的文本(?"polls/"
?),將剩余文本——?"5/"
?,發(fā)送至 'polls.urls' URLconf 做進(jìn)一步處理。在這里剩余文本匹配了 ?'<int:question_id>/'
?,使得我們 Django 以如下形式調(diào)用 ?detail()
?:
detail(request=<HttpRequest object>, question_id=34)
問題 ?question_id=34
? 來自 ?<int:question_id>
?。使用尖括號 "獲得" 網(wǎng)址部分后發(fā)送給視圖函數(shù)作為一個關(guān)鍵字參數(shù)。字符串的 ?question_id
部分定義了要使用的名字,用來識別相匹配的模式,而 ?int
?部分是一種轉(zhuǎn)換形式,用來確定應(yīng)該匹配網(wǎng)址路徑的什么模式。冒號 (?:
?) 用來分隔轉(zhuǎn)換形式和模式名。
每個視圖必須要做的只有兩件事:返回一個包含被請求頁面內(nèi)容的 ?HttpResponse
?對象,或者拋出一個異常,比如 ?Http404
?。
你的視圖可以從數(shù)據(jù)庫里讀取記錄,可以使用一個模板引擎(比如 Django 自帶的,或者其他第三方的),可以生成一個 PDF 文件,可以輸出一個 XML,創(chuàng)建一個 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 庫。
Django 只要求返回的是一個 ?HttpResponse
,或者拋出一個異常。
因為 Django 自帶的數(shù)據(jù)庫 API 很方便,我們曾在 教程第 2 部分 中學(xué)過,所以我們試試在視圖里使用它。我們在 ?index()
? 函數(shù)里插入了一些新內(nèi)容,讓它能展示數(shù)據(jù)庫里以發(fā)布日期排序的最近 5 個投票問題,以空格分割:
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
這里有個問題:頁面的設(shè)計寫死在視圖函數(shù)的代碼里的。如果你想改變頁面的樣子,你需要編輯 Python 代碼。所以讓我們使用 Django 的模板系統(tǒng),只要創(chuàng)建一個視圖,就可以將頁面的設(shè)計從代碼中分離出來。
首先,在你的 ?polls
?目錄里創(chuàng)建一個 ?templates
?目錄。Django 將會在這個目錄里查找模板文件。
你項目的 ?TEMPLATES
?配置項描述了 Django 如何載入和渲染模板。默認(rèn)的設(shè)置文件設(shè)置了 ?DjangoTemplates
?后端,并將 ?APP_DIRS
?設(shè)置成了 True。這一選項將會讓 ?DjangoTemplates
?在每個 ?INSTALLED_APPS
?文件夾中尋找 "templates" 子目錄。這就是為什么盡管我們沒有像在第二部分中那樣修改 ?DIRS
?設(shè)置,Django 也能正確找到 polls 的模板位置的原因。
在你剛剛創(chuàng)建的 ?templates
目錄里,再創(chuàng)建一個目錄 ?polls
?,然后在其中新建一個文件 ?index.html
? 。換句話說,你的模板文件的路徑應(yīng)該是 ?polls/templates/polls/index.html
? 。因為?``app_directories``
? 模板加載器是通過上述描述的方法運行的,所以 Django 可以引用到 ?polls/index.html
? 這一模板了。
將下面的代碼輸入到剛剛創(chuàng)建的模板文件中:
{% 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
? 里的 ?index
視圖來使用模板:
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
? 模板文件,并且向它傳遞一個上下文(context)。這個上下文是一個字典,它將模板內(nèi)的變量映射為 Python 對象。
用你的瀏覽器訪問 "/polls/" ,你將會看見一個無序列表。
「載入模板,填充上下文,再返回由它生成的 ?HttpResponse
?對象」是一個非常常用的操作流程。于是 Django 提供了一個快捷函數(shù),我們用它來重寫 ?index()
?視圖:
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)
注意到,我們不再需要導(dǎo)入 ?loader
和 ?HttpResponse
?。不過如果你還有其他函數(shù)(比如說 ?detail
?, ?results
?, 和 ?vote
?)需要用到它的話,就需要保持 ?HttpResponse
?的導(dǎo)入。
現(xiàn)在,我們來處理投票詳情視圖——它會顯示指定投票的問題標(biāo)題。下面是這個視圖的代碼:
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})
這里有個新原則。如果指定問題 ID 所對應(yīng)的問題不存在,這個視圖就會拋出一個 ?Http404
?異常。
我們稍后再討論你需要在 ?polls/detail.html
? 里輸入什么,但是如果你想試試上面這段代碼是否正常工作的話,你可以暫時把下面這段輸進(jìn)去:
{{ question }}
這樣你就能測試了。
嘗試用 ?get()
? 函數(shù)獲取一個對象,如果不存在就拋出 ?Http404
?錯誤也是一個普遍的流程。Django 也提供了一個快捷函數(shù),下面是修改后的詳情 ?detail()
? 視圖代碼:
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()
? 函數(shù)將 Django 模型作為其第一個參數(shù)和任意數(shù)量的關(guān)鍵字參數(shù),并將其傳遞給模型管理器的 ?get()
? 函數(shù)。 如果對象不存在,它會引發(fā) ?Http404
?。
也有 ?get_list_or_404()
? 函數(shù),工作原理和 ?get_object_or_404()
? 一樣,除了 ?get()
? 函數(shù)被換成了 ?filter()
? 函數(shù)。如果列表為空的話會拋出 ?Http404
異常。
回過頭去看看我們的 ?detail()
? 視圖。它向模板傳遞了上下文變量 ?question
?。下面是 ?polls/detail.html
? 模板里正式的代碼:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
模板系統(tǒng)統(tǒng)一使用點符號來訪問變量的屬性。在示例 ?{{ question.question_text }}
? 中,首先 Django 嘗試對 ?question
?對象使用字典查找(也就是使用 ?obj.get(str)
? 操作),如果失敗了就嘗試屬性查找(也就是 ?obj.str
? 操作),結(jié)果是成功了。如果這一操作也失敗的話,將會嘗試列表查找(也就是 ?obj[int]
? 操作)。
在 ?{% for %}
? 循環(huán)中發(fā)生的函數(shù)調(diào)用:?question.choice_set.all
? 被解釋為 Python 代碼 ?question.choice_set.all()
? ,將會返回一個可迭代的 ?Choice
?對象,這一對象可以在? {% for %}
?標(biāo)簽內(nèi)部使用。
還記得嗎,我們在 ?polls/index.html
里編寫投票鏈接時,鏈接是硬編碼的:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
問題在于,硬編碼和強(qiáng)耦合的鏈接,對于一個包含很多應(yīng)用的項目來說,修改起來是十分困難的。然而,因為你在 ?polls.urls
? 的 ?url()
? 函數(shù)中通過 ?name
參數(shù)為 URL 定義了名字,你可以使用 ?{% url %}
?標(biāo)簽代替它:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
這個標(biāo)簽的工作方式是在 ?polls.urls
? 模塊的 URL 定義中尋具有指定名字的條目。你可以回憶一下,具有名字 ?'detail'
? 的 URL 是在如下語句中定義的:
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
如果你想改變投票詳情視圖的 URL,比如想改成 ?polls/specifics/12/
?,你不用在模板里修改任何東西(包括其它模板),只要在 ?polls/urls.py
? 里稍微修改一下就行:
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
教程項目只有一個應(yīng)用,?polls
。在一個真實的 Django 項目中,可能會有五個,十個,二十個,甚至更多應(yīng)用。Django 如何分辨重名的 URL 呢?舉個例子,?polls
應(yīng)用有 ?detail
視圖,可能另一個博客應(yīng)用也有同名的視圖。Django 如何知道 ?{% url %}
? 標(biāo)簽到底對應(yīng)哪一個應(yīng)用的 URL 呢?
答案是:在根 URLconf 中添加命名空間。在 ?polls/urls.py
? 文件中稍作修改,加上? app_name
? 設(shè)置命名空間:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
現(xiàn)在,編輯 ?polls/index.html
? 文件,從:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
修改為指向具有命名空間的詳細(xì)視圖:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: