鍍金池/ 教程/ Python/ 編寫你的第一個(gè) Django 程序 第3部分
點(diǎn)擊劫持保護(hù)
安全問題歸檔
Model 類參考
將遺留數(shù)據(jù)庫整合到Django
關(guān)聯(lián)對(duì)象參考
內(nèi)建基于類的視圖的API
聚合
Django 中的用戶認(rèn)證
django.contrib.humanize
Django管理文檔生成器
分頁
使用Django輸出CSV
加密簽名
文件儲(chǔ)存API
安全
Django中的測(cè)試
國(guó)際化和本地化
為Django編寫首個(gè)補(bǔ)丁
條件表達(dá)式
日志
模型元選項(xiàng)
部署靜態(tài)文件
執(zhí)行查詢
使用Django認(rèn)證系統(tǒng)
基于類的視圖
中間件
編寫自定義的django-admin命令
Django 的設(shè)置
格式本地化
數(shù)據(jù)庫訪問優(yōu)化
錯(cuò)誤報(bào)告
基于類的內(nèi)建通用視圖
編寫自定義存儲(chǔ)系統(tǒng)
編寫你的第一個(gè) Django 程序 第3部分
編寫數(shù)據(jù)庫遷移
使用表單
編寫你的第一個(gè) Django 程序 第2部分
編寫你的第一個(gè) Django 程序 第1部分
如何使用會(huì)話
系統(tǒng)檢查框架
新手入門
信號(hào)
編寫視圖
如何使用WSGI 部署
編寫你的第一個(gè)Django應(yīng)用,第6部分
常見的網(wǎng)站應(yīng)用工具
Widgets
內(nèi)建的視圖
模型實(shí)例參考
視圖層
Django中的密碼管理
高級(jí)教程:如何編寫可重用的應(yīng)用
國(guó)際化和本地化
"本地特色"附加功能
TemplateResponse 和 SimpleTemplateResponse
模式編輯器
文件上傳
快速安裝指南
部署 Django
表單 API
表單素材 ( <code>Media</code> 類)
管理文件
其它核心功能
查找 API 參考
表單
Admin
數(shù)據(jù)庫函數(shù)
自定義查找
使用基于類的視圖處理表單
管理操作
開發(fā)過程
編寫你的第一個(gè)Django應(yīng)用,第5部分
進(jìn)行原始的sql查詢
模型層
多數(shù)據(jù)庫
編寫你的第一個(gè) Django 程序 第4部分
Django安全
Django 初探
Django異常
重定向應(yīng)用
按需內(nèi)容處理
管理器
視圖裝飾器
驗(yàn)證器
使用Django輸出PDF
File對(duì)象
Django 的快捷函數(shù)
基于類的通用視圖 —— 索引
為模型提供初始數(shù)據(jù)
模板層
URL調(diào)度器
中間件
模型

編寫你的第一個(gè) Django 程序 第3部分

本教程上接 教程 第2部分 。我們將繼續(xù) 開發(fā) Web-poll 應(yīng)用并且專注在創(chuàng)建公共界面 – “視圖 (views )”。

哲理

在 Django 應(yīng)用程序中,視圖是一“類”具有特定功能和模板的網(wǎng)頁。 例如,在一個(gè)博客應(yīng)用程序中,你可能會(huì)有以下視圖:

  • 博客首頁 – 顯示最新發(fā)表的博客。
  • 博客詳細(xì)頁面 – 一篇博客的獨(dú)立頁面。
  • 基于年份的歸檔頁 – 顯示給定年份中發(fā)表博客的所有月份。
  • 基于月份的歸檔頁 – 顯示給定月份中發(fā)表博客的所有日期。
  • 基于日期的歸檔頁 – 顯示給定日期中發(fā)表的所有的博客。
  • 評(píng)論功能 – 為一篇給定博客發(fā)表評(píng)論。

在我們的 poll 應(yīng)用程序中,將有以下四個(gè)視圖:

  • Poll “index” 頁 – 顯示最新發(fā)布的民意調(diào)查。
  • Poll “detail” 頁 – 顯示一項(xiàng)民意調(diào)查的具體問題,不顯示該項(xiàng)的投票結(jié)果但可以進(jìn)行投票的 form 。
  • Poll “results” 頁 – 顯示一項(xiàng)給定的民意調(diào)查的投票結(jié)果。
  • 投票功能 – 為一項(xiàng)給定的民意調(diào)查處理投票選項(xiàng)。

在 Django 中,網(wǎng)頁及其他內(nèi)容是由視圖來展現(xiàn)的。而每個(gè)視圖就是一個(gè)簡(jiǎn)單的 Python 函數(shù)(或方法, 對(duì)于基于類的視圖情況下)。Django 會(huì)通過檢查所請(qǐng)求的 URL (確切地說是域名之后的那部分 URL)來匹配一個(gè)視圖。

平時(shí)你上網(wǎng)的時(shí)候可能會(huì)遇到像 “ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core-Pages&gid=A6CD4967199A42D9B65B1B” 這種如此美麗的 URL。 但是你會(huì)很高興知道 Django 允許我們使用比那優(yōu)雅的 URL 模式 來展現(xiàn) URL。

URL 模式就是一個(gè)簡(jiǎn)單的一般形式的 URL - 比如: /newsarchive/<year>/<month>/.

Django 是通過 ‘URLconfs’ 從 URL 獲取到視圖的。而 URLconf 是將 URL 模式 ( 由正則表達(dá)式來描述的 ) 映射到視圖的一種配置。

本教程中介紹了使用 URLconfs 的基本指令,你可以查閱 django.core.urlresolvers 來獲取更多信息。

編寫你的第一個(gè)視圖

讓我們編寫第一個(gè)視圖。打開文件 polls/views.py 并在其中輸入以下 Python 代碼

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the poll index.")

在 Django 中這可能是最簡(jiǎn)單的視圖了。為了調(diào)用這個(gè)視圖,我們需要將它映射到一個(gè) URL – 為此我們需要配置一個(gè)URLconf 。

在 polls 目錄下創(chuàng)建一個(gè)名為 urls.py 的 URLconf 文檔。 你的應(yīng)用目錄現(xiàn)在看起來像這樣

polls/
    __init__.py
    admin.py
    models.py
    tests.py
    urls.py
    views.py

在 polls/urls.py 文件中輸入以下代碼:

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='index')
)

下一步是將 polls.urls 模塊指向 root URLconf 。在 mysite/urls.py 中插入一個(gè) include() 方法,最后的樣子如下所示

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

現(xiàn)在你在 URLconf 中配置了 index 視圖。通過瀏覽器訪問 http://localhost:8000/polls/ ,如同你在 index 視圖中定義的一樣,你將看到 “Hello, world. You’re at the poll index.” 文字。

url() 函數(shù)有四個(gè)參數(shù),兩個(gè)必須的: regex 和 view, 兩個(gè)可選的: kwargs, 以及 name。 接下來,來探討下這些參數(shù)的意義。

url() 參數(shù): regex

regex 是 regular expression 的簡(jiǎn)寫,這是字符串中的模式匹配的一種語法, 在 Django 中就是是 url 匹配模式。 Django 將請(qǐng)求的 URL 從上至下依次匹配列表中的正則表達(dá)式,直到匹配到一個(gè)為止。

需要注意的是,這些正則表達(dá)式不會(huì)匹配 GET 和 POST 參數(shù),以及域名。 例如:針對(duì) http://www.example.com/myapp/ 這一請(qǐng)求,URLconf 將只查找 myapp/。而在http://www.example.com/myapp/?page=3 中 URLconf 也僅查找 myapp/ 。

如果你需要正則表達(dá)式方面的幫助,請(qǐng)參閱 Wikipedia’s entry 和本文檔中的 re 模塊。 此外,O’Reilly 出版的由 Jeffrey Friedl 著的 “Mastering Regular Expressions” 也是不錯(cuò)的。 但是,實(shí)際上,你并不需要成為一個(gè)正則表達(dá)式的專家,僅僅需要知道如何捕獲簡(jiǎn)單的模式。 事實(shí)上,復(fù)雜的正則表達(dá)式會(huì)降低查找性能,因此你不能完全依賴正則表達(dá)式的功能。

最后有個(gè)性能上的提示:這些正則表達(dá)式在 URLconf 模塊第一次加載時(shí)會(huì)被編譯。 因此它們速度超快 ( 像上面提到的那樣只要查找的不是太復(fù)雜 )。

url() 參數(shù): view

當(dāng) Django 匹配了一個(gè)正則表達(dá)式就會(huì)調(diào)用指定的視圖功能,包含一個(gè) HttpRequest 實(shí)例作為第一個(gè)參數(shù)和正則表達(dá)式 “捕獲” 的一些值的作為其他參數(shù)。 如果使用簡(jiǎn)單的正則捕獲,將按順序位置傳參數(shù);如果按命名的正則捕獲,將按關(guān)鍵字傳參數(shù)值。 有關(guān)這一點(diǎn)我們會(huì)給出一個(gè)例子。

url() 參數(shù): kwargs

任意關(guān)鍵字參數(shù)可傳一個(gè)字典至目標(biāo)視圖。在本教程中,我們并不打算使用 Django 這一特性。

url() 參數(shù): name

命名你的 URL ,讓你在 Django 的其他地方明確地引用它,特別是在模板中。 這一強(qiáng)大的功能可允許你通過一個(gè)文件就可全局修改項(xiàng)目中的 URL 模式。

編寫更多視圖

現(xiàn)在讓我們添加一些視圖到 polls/views.py 中去。這些視圖與之前的略有不同,因?yàn)?它們有一個(gè)參數(shù)::

def detail(request, poll_id):
    return HttpResponse("You're looking at poll %s." % poll_id)

def results(request, poll_id):
    return HttpResponse("You're looking at the results of poll %s." % poll_id)

def vote(request, poll_id):
    return HttpResponse("You're voting on poll %s." % poll_id)

將新視圖按如下所示的 url() 方法添加到 polls.urls 模塊中去::

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<poll_id>\d-)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<poll_id>\d-)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<poll_id>\d-)/vote/$', views.vote, name='vote'),
)

在你的瀏覽器中訪問 http://localhost:8000/polls/34/ 。將運(yùn)行 detail() 方法并且顯示你在 URL 中提供的任意 ID 。試著訪問 http://localhost:8000/polls/34/results/http://localhost:8000/polls/34/vote/ – 將會(huì)顯示對(duì)應(yīng)的結(jié)果頁及投票頁。

當(dāng)有人訪問你的網(wǎng)站頁面如 “ /polls/34/ ” 時(shí),Django 會(huì)加載 mysite.urls 模塊,這是因?yàn)?ROOT_URLCONF 設(shè)置指向它。接著在該模塊中尋找名為urlpatterns 的變量并依次匹配其中的正則表達(dá)式。 include() 可讓我們便利地引用其他 URLconfs 。請(qǐng)注意 include() 中的正則表達(dá)式?jīng)]有 $ (字符串結(jié)尾的匹配符 match character) 而尾部是一個(gè)反斜杠。當(dāng) Django 解析 include() 時(shí),它截取匹配的 URL 那部分而把剩余的字符串交由 加載進(jìn)來的 URLconf 作進(jìn)一步處理。

include() 背后隱藏的想法是使 URLs 即插即用。 由于 polls 在自己的 URLconf(polls/urls.py) 中,因此它們可以被放置在 “/polls/” 路徑下,或 “/fun_polls/” 路徑下,或 “/content/polls/” 路徑下,或者其他根路徑,而應(yīng)用仍可以運(yùn)行。

以下是當(dāng)用戶訪問 “/polls/34/” 路徑時(shí)系統(tǒng)中將發(fā)生的事:

  • Django 將尋找 '^polls/' 的匹配
  • 接著,Django 截取匹配文本 ("polls/") 后剩余的文本 – "34/" – 傳遞到 ‘polls.urls’ URLconf 中作進(jìn)一步處理, 再將匹配 r'^(?P\d-)/$' 的結(jié)果作為參數(shù)傳給 detail() 視圖
detail(request=<HttpRequest object>, poll_id='34')

poll_id='34' 這部分就是來自 (?P\d-) 匹配的結(jié)果。 使用括號(hào)包圍一個(gè) 正則表達(dá)式所“捕獲”的文本可作為一個(gè)參數(shù)傳給視圖函數(shù);?P<poll_id> 將會(huì)定義名稱用于標(biāo)識(shí)匹配的內(nèi)容; 而 \d- 是一個(gè)用于匹配數(shù)字序列(即一個(gè)數(shù)字)的正則表達(dá)式。

因?yàn)?URL 模式是正則表達(dá)式,所以你可以毫無限制地使用它們。但是不要加上 URL 多余的部分如 .html – 除非你想,那你可以像下面這樣::

(r'^polls/latest\.html$', 'polls.views.index'),

真的,不要這樣做。這很傻。

在視圖中添加些實(shí)際的功能

每個(gè)視圖只負(fù)責(zé)以下兩件事中的一件:返回一個(gè) HttpResponse 對(duì)象,其中包含了所請(qǐng)求頁面的內(nèi)容, 或者拋出一個(gè)異常,例如 Http404 。剩下的就由你來實(shí)現(xiàn)了。

你的視圖可以讀取數(shù)據(jù)庫記錄,或者不用。它可以使用一個(gè)模板系統(tǒng),例如 Django 的 – 或者第三方的 Python 模板系統(tǒng) – 或不用。它可以生成一個(gè) PDF 文件,輸出 XML , 即時(shí)創(chuàng)建 ZIP 文件, 你可以使用你想用的任何 Python 庫來做你想做的任何事。

而 Django 只要求是一個(gè) HttpResponse 或一個(gè)異常。

因?yàn)樗芊奖?,那讓我們來使?Django 自己的數(shù)據(jù)庫 API 吧, 在 教程 第1部分 中提過。修改下 index() 視圖, 讓它顯示系統(tǒng)中最新發(fā)布的 5 個(gè)調(diào)查問題,以逗號(hào)分割并按發(fā)布日期排序::

from django.http import HttpResponse

from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
    output = ', '.join([p.question for p in latest_poll_list])
    return HttpResponse(output)

在這就有了個(gè)問題,頁面的設(shè)計(jì)是硬編碼在視圖中的。如果你想改變頁面的外觀,就必須修改這里的 Python 代碼。因此,讓我們使用 Django 的模板系統(tǒng)創(chuàng)建一個(gè)模板給視圖用,就使頁面設(shè)計(jì)從 Python 代碼中 分離出來了。

首先,在 polls 目錄下創(chuàng)建一個(gè) templates 目錄。 Django 將會(huì)在那尋找模板。

Django 的 TEMPLATE_LOADERS 配置中包含一個(gè)知道如何從各種來源導(dǎo)入模板的可調(diào)用的方法列表。 其中有一個(gè)默認(rèn)值是 django.template.loaders.app_directories.Loader ,Django 就會(huì)在每個(gè) INSTALLED_APPS 的 “templates” 子目錄下查找模板 - 這就是 Django 知道怎么找到 polls 模板的原因,即使我們 沒有修改 TEMPLATE_DIRS, 還是如同在 教程 第2部分 那樣。

組織模板

我們 能夠 在一個(gè)大的模板目錄下一起共用我們所有的模板,而且它們會(huì)運(yùn)行得很好。 但是,此模板屬于 polls 應(yīng)用,因此與我們?cè)谏弦粋€(gè)教程中創(chuàng)建的管理模板不同, 我們要把這個(gè)模板放在應(yīng)用的模板目錄 (polls/templates) 下而不是項(xiàng)目的模板目錄 (templates) 。 我們將在 可重用的應(yīng)用教程 中詳細(xì)討論我們 為什么 要這樣做。

在你剛才創(chuàng)建的templates 目錄下,另外創(chuàng)建個(gè)名為 polls 的目錄,并在其中創(chuàng)建一個(gè) index.html 文件。換句話說,你的模板應(yīng)該是 polls/templates/polls/index.html 。由于知道如上所述的 app_directories 模板加載器是 如何運(yùn)行的,你可以參考 Django 內(nèi)的模板簡(jiǎn)單的作為 polls/index.html 模板。

模板命名空間

現(xiàn)在我們 也許 能夠直接把我們的模板放在 polls/templates 目錄下 ( 而不是另外創(chuàng)建 polls 子目錄 ) , 但它實(shí)際上是一個(gè)壞注意。 Django 將會(huì)選擇第一個(gè)找到的按名稱匹配的模板, 如果你在 不同 應(yīng)用中有相同的名稱的模板,Django 將無法區(qū)分它們。 我們想要讓 Django 指向正確的模板,最簡(jiǎn)單的方法是通過 命名空間 來確保是 他們的模板。也就是說,將模板放在 另一個(gè) 目錄下并命名為應(yīng)用本身的名稱。

將以下代碼添加到該模板中:

{% if latest_poll_list %}
    <ul>
    {% for poll in latest_poll_list %}
        <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

現(xiàn)在讓我們?cè)?index 視圖中使用這個(gè)模板:

from django.http import HttpResponse
from django.template import Context, loader

from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = Context({
        'latest_poll_list': latest_poll_list,
    })
    return HttpResponse(template.render(context))

代碼將加載 polls/index.html 模板并傳遞一個(gè) context 變量。 The context is a dictionary mapping template variable names to Python 該 context 變量是一個(gè)映射了 Python 對(duì)象到模板變量的字典。

在你的瀏覽器中加載 “/polls/” 頁,你應(yīng)該看到一個(gè)列表,包含了在教程 第1部分 中創(chuàng)建的 “What’s up” 調(diào)查。而鏈接指向 poll 的詳細(xì)頁面。

快捷方式: render()

這是一個(gè)非常常見的習(xí)慣用語,用于加載模板,填充上下文并返回一個(gè)含有模板渲染結(jié)果的 HttpResponse 對(duì)象。 Django 提供了一種快捷方式。這里重寫完整的 index() 視圖

from django.shortcuts import render

from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    context = {'latest_poll_list': latest_poll_list}
    return render(request, 'polls/index.html', context)

請(qǐng)注意,一旦我們?cè)谒幸晥D中都這樣做了,我們就不再需要導(dǎo)入 loader , Context 和 HttpResponse ( 如果你仍然保留了 detail,resutls, 和vote 方法,你還是需要保留 HttpResponse ) 。

render() 函數(shù)中第一個(gè)參數(shù)是 request 對(duì)象,第二個(gè)參數(shù)是一個(gè)模板名稱,第三個(gè)是一個(gè)字典類型的可選參數(shù)。 它將返回一個(gè)包含有給定模板根據(jù)給定的上下文渲染結(jié)果的 HttpResponse 對(duì)象。

拋出 404 異常

現(xiàn)在讓我們解決 poll 的詳細(xì)視圖 – 該頁顯示一個(gè)給定 poll 的詳細(xì)問題。 視圖代碼如下所示::

from django.http import Http404
# ...
def detail(request, poll_id):
    try:
        poll = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render(request, 'polls/detail.html', {'poll': poll})

在這有個(gè)新概念:如果請(qǐng)求的 poll 的 ID 不存在,該視圖將拋出 Http404 異常。

我們稍后討論如何設(shè)置 polls/detail.html 模板,若是你想快速運(yùn)行上面的例子, 在模板文件中添加如下代碼:

{{ poll }}

現(xiàn)在你可以運(yùn)行了。

快捷方式: get_object_or_404()

這很常見,當(dāng)你使用 get() 獲取對(duì)象時(shí) 對(duì)象卻不存在時(shí)就會(huì)拋出 Http404 異常。對(duì)此 Django 提供了一個(gè)快捷操作。如下所示重寫 detail() 視圖:

from django.shortcuts import render, get_object_or_404
# ...
def detail(request, poll_id):
    poll = get_object_or_404(Poll, pk=poll_id)
    return render(request, 'polls/detail.html', {'poll': poll})

get_object_or_404() 函數(shù)需要一個(gè) Django 模型類作為第一個(gè)參數(shù)以及 一些關(guān)鍵字參數(shù),它將這些參數(shù)傳遞給模型管理器中的 get() 函數(shù)。 若對(duì)象不存在時(shí)就拋出 Http404 異常。

哲理

為什么我們要使用一個(gè) get_object_or_404() 輔助函數(shù) 而不是在更高級(jí)別自動(dòng)捕獲 ObjectDoesNotExist 異常, 或者由模型 API 拋出 Http404 異常而不是 ObjectDoesNotExist 異常?

因?yàn)槟菢訒?huì)使模型層與視圖層耦合在一起。Django 最重要的設(shè)計(jì)目標(biāo)之一 就是保持松耦合。一些控制耦合在 django.shortcuts 模塊中介紹。

還有個(gè) get_list_or_404() 函數(shù),與 get_object_or_404() 一樣 – 不過執(zhí)行的是 filter() 而不是 get() 。若返回的是空列表將拋出 Http404 異常。

編寫一個(gè) 404 ( 頁面未找到 ) 視圖

當(dāng)你在視圖中拋出 Http404 時(shí),Django 將載入一個(gè)特定的視圖來處理 404 錯(cuò)誤。Django 會(huì)根據(jù)你的 root URLconf ( 僅在你的 root URLconf 中;在其他任何地方設(shè)置 handler404 都無效 )中設(shè)置的 handler404 變量來查找該視圖,這個(gè)變量是個(gè) Python 包格式字符串 – 和標(biāo)準(zhǔn) URLconf 中的回調(diào)函數(shù)格式是一樣的。 404 視圖本身沒有什么特殊性:它就是一個(gè)普通的視圖。

通常你不必費(fèi)心去編寫 404 視圖。若你沒有設(shè)置 handler404 變量,默認(rèn)情況下會(huì)使用內(nèi)置的 django.views.defaults.page_not_found() 視圖?;蛘吣憧梢栽谀愕哪0迥夸浵碌母夸浿?創(chuàng)建一個(gè) 404.html 模板。當(dāng) DEBUG 值是 False ( 在你的 settings 模塊中 ) 時(shí), 默認(rèn)的 404 視圖將使用此模板來顯示所有的 404 錯(cuò)誤。 如果你創(chuàng)建了這個(gè)模板,至少添加些如“頁面未找到” 的內(nèi)容。

一些有關(guān) 404 視圖需要注意的事項(xiàng) :

  • 如果 DEBUG 設(shè)為 True ( 在你的 settings 模塊里 ) 那么你的 404 視圖將永遠(yuǎn)不會(huì)被使用 ( 因此 404.html 模板也將永遠(yuǎn)不會(huì)被渲染 ) 因?yàn)閷⒁@示的是跟蹤信息。
  • 當(dāng) Django 在 URLconf 中不能找到能匹配的正則表達(dá)式時(shí) 404 視圖也將被調(diào)用。 編寫一個(gè) 500 ( 服務(wù)器錯(cuò)誤 ) 視圖

類似的,你可以在 root URLconf 中定義 handler500 變量,在服務(wù)器發(fā)生錯(cuò)誤時(shí) 調(diào)用它指向的視圖。服務(wù)器錯(cuò)誤是指視圖代碼產(chǎn)生的運(yùn)行時(shí)錯(cuò)誤。

同樣,你在模板根目錄下創(chuàng)建一個(gè) 500.html 模板并且添加些像“出錯(cuò)了”的內(nèi)容。

使用模板系統(tǒng)

回到我們 poll 應(yīng)用的 detail() 視圖中,指定 poll 變量后,polls/detail.html 模板可能看起來這樣 :

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

模板系統(tǒng)使用了“變量.屬性”的語法訪問變量的屬性值。 例如 {{ poll.question }} , 首先 Django 對(duì) poll 對(duì)象做字典查詢。 否則 Django 會(huì)嘗試屬性查詢 – 在本例中屬性查詢成功了。 如果屬性查詢還是失敗了,Django 將嘗試 list-index 查詢。

{% for %} 循環(huán)中有方法調(diào)用: poll.choice_set.all 就是 Python 代碼 poll.choice_set.all(),它將返回一組可迭代的 Choice 對(duì)象,可以用在 {% for %} 標(biāo)簽中。

請(qǐng)參閱 模板指南 來了解模板的更多內(nèi)容。

移除模板中硬編碼的 URLS

記得嗎? 在 polls/index.html 模板中,我們鏈接到 poll 的鏈接是硬編碼成這樣子的:

<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>

問題出在硬編碼,緊耦合使得在大量的模板中修改 URLs 成為富有挑戰(zhàn)性的項(xiàng)目。 不過,既然你在 polls.urls 模塊中的 url() 函數(shù)中定義了 命名參數(shù),那么就可以在 url 配置中使用 {% url %} 模板標(biāo)記來移除特定的 URL 路徑依賴:

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

Note

如果 {% url 'detail' poll.id %} (含引號(hào)) 不能運(yùn)行,但是 {% url detail poll.id %} (不含引號(hào)) 卻能運(yùn)行,那么意味著你使用的 Djang 低于 < 1.5 版。這樣的話,你需要在模板文件的頂部添加如下的聲明::

{% load url from future %}

其原理就是在 polls.urls 模塊中尋找指定的 URL 定義。 你知道命名為 ‘detail’ 的 URL 就如下所示那樣定義的一樣::

...
# 'name' 的值由 {% url %} 模板標(biāo)記來引用
url(r'^(?P<poll_id>\d-)/$', views.detail, name='detail'),
...

如果你想將 polls 的 detail 視圖的 URL 改成其他樣子,或許像 polls/specifics/12/ 這樣子,那就不需要在模板(或者模板集)中修改而只要在 polls/urls.py 修改就行了:

...
# 新增 'specifics'
url(r'^specifics/(?P<poll_id>\d-)/$', views.detail, name='detail'),
...

URL 名稱的命名空間

本教程中的項(xiàng)目只有一個(gè)應(yīng)用:polls 。在實(shí)際的 Django 項(xiàng)目中,可能有 5、10、20 或者 更多的應(yīng)用。Django 是如何區(qū)分它們的 URL 名稱的呢?比如說,polls 應(yīng)用有一個(gè) detail 視圖,而可能會(huì)在同一個(gè)項(xiàng)目中是一個(gè)博客應(yīng)用的視圖。Django 是如何知道 使用 {% url %} 模板標(biāo)記創(chuàng)建應(yīng)用的 url 時(shí)選擇正確呢?

答案是在你的 root URLconf 配置中添加命名空間。在 mysite/urls.py 文件 (項(xiàng)目的 urls.py,不是應(yīng)用的) 中,修改為包含命名空間的定義:

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls', namespace="polls")),
    url(r'^admin/', include(admin.site.urls)),
)

現(xiàn)在將你的 polls/index.html 模板中原來的 detail 視圖:

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

修改為包含命名空間的 detail 視圖:

<li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>

當(dāng)你編寫視圖熟練后,請(qǐng)閱讀 教程 第4部分 來學(xué)習(xí)如何處理簡(jiǎn)單的表單和通用視圖。

譯者:Django 文檔協(xié)作翻譯小組,原文:Part 3: Views and templates。

本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。

Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。