Django 1.10中文文檔-第一個應用Part3-視圖和模板

来源:http://www.cnblogs.com/jhao/archive/2017/01/18/6297797.html
-Advertisement-
Play Games

本教程上接Django 1.10中文文檔-第一個應用Part2-模型和管理站點。我們將繼續開髮網頁投票這個應用,主要講如何創建一個對用戶開放的界面。 概覽 視圖是Django應用中的一“類”網頁,它通常使用一個特定的函數提供服務,並且具有一個特定的模板。例如,在博客應用中,可能有以下視圖: 博客首頁 ...


本教程上接Django 1.10中文文檔-第一個應用Part2-模型和管理站點。我們將繼續開髮網頁投票這個應用,主要講如何創建一個對用戶開放的界面。

概覽

視圖是Django應用中的一“類”網頁,它通常使用一個特定的函數提供服務,並且具有一個特定的模板。例如,在博客應用中,可能有以下視圖:

  • 博客首頁 —— 顯示最新發表的博客;

  • 博客“詳細”頁面 —— 每博客的鏈接頁面;

  • 基於年份的歸檔頁面 —— 顯示特定年內所有月份發表過的博客;

  • 基於月份的歸檔頁面 —— 顯示特定月份內每天發表過博客;

  • 基於日期的歸檔頁面 —— 顯示特定日期內發表過的所有博客;

  • 評論:處理針對某篇博客發佈的評論。

在我們的投票應用中,我們將建立下麵的四個視圖:

  • Question首頁 —— 顯示最新發佈的幾個Question;

  • Question“詳細”頁面 —— 顯示單個Question的具體內容,提供一個投票的表單,但不顯示該議題的當前投票結果;

  • Question“結果”頁面 —— 顯示特定的Question的投票結果;

  • 投票功能 —— 處理對Question中Choice的投票。

在Django中,網頁的頁面和其他內容都是由視圖(views.py)來傳遞的(視圖對WEB請求進行回應)。每個視圖都是由一個Python函數(或者是基於類的視圖的方法)表示。Django通過對比請求的URL地址來選擇對應的視圖。

在你平時的網頁上,你可能經常會碰到類似“ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”的url。慶幸的是Django支持使用更加簡介的URL模式(patterns),而不需要編寫上面那種複雜的url。

URL模式就是一種URL的通用模式 —— 例如: /newsarchive/<year>/<month>/

Django使用‘URLconfs’的配置來為URL匹配視圖函數。 URLconf使用正則表達式將URL匹配到視圖上。

本教程提供URLconfs基本使用,更多信息請參考django.url

編輯視圖

下麵,讓我們打開polls/views.py文件,添加下列代碼:

# 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.py文件中加入下麵的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里提供的ID。訪問“/polls/34/results/”和“/polls/34/vote/”,將分別顯示預定義的偽結果和投票頁面。

上面訪問的路由過程如下:當有人訪問“/polls/34/”地址時,Django將首先載入mysite.urls模塊,因為它是settings文件里設置的ROOT_URLCONF配置文件。在模塊里找到urlpatterns變數,按順序對各項進行正則匹配。當它匹配到了^polls/,就剝離出url中匹配的文本polls/,然後將剩下的文本“34/”,傳遞給“polls.urls”進行下一步的處理。在polls.urls,又匹配到了r’^(?P<question_id>[0-9]+)/$’,最終結果就是調用該模式對應的detail()視圖,將34作為參數傳入:

detail(request=<HttpRequest object>, question_id='34')

question_id=’34’的部分來自(?P <question_id> [0-9])。使用模式周圍的括弧“捕獲”該模式匹配到的文本,並將其作為參數發送到視圖函數;?P<question_id> 定義一個名字用於標識匹配的模式;[0-9]+是匹配一串數字的正則表達。

因為URL模式是正則表達式,你如何使用它們沒有什麼限制。 不需要添加像.html這樣繁瑣的URL —— 除非你執意這麼做,在這種情況下你可以這樣做:

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

但是,不要這樣做。這比較愚蠢。

編寫擁有實際功能的視圖

每個視圖函數只負責處理兩件事中的一件:返回一個包含所請求頁面內容的HttpResponse對象,或拋出一個諸如Http404異常。該如何去做這兩件事,就看你自己的想法了。

您的視圖可以從資料庫讀取記錄,也可以不讀取。它可以使用模板系統:如Django的或第三方Python模板系統 或不。可以生成PDF文件,輸出XML,即時創建ZIP文件,任何你想要的,使用任何你想要的Python庫。Django只要求返回的是一個HttpResponse。 或者拋出一個異常。

為了方便,讓我們使用Part1中介紹的Django自己的資料庫API。 下麵是一個新的index()視圖,它顯示系統中最新發佈的5條questions記錄,並用逗號分隔:

# 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)

# 保持其他的視圖 (detail, results, vote) 不變

這裡有一個問題:頁面的設計被硬編碼在視圖中。 如果你想更改頁面的外觀,就得編輯這段Python代碼。 因此,我們使用Django的模板系統,通過創建一個視圖能夠調用的模板,將頁面的設計從Python中分離出來。

首先,在你的polls目錄下創建一個叫做 templates的目錄。Django將在這裡查找模板。

項目的settings.py中的templates配置決定了Django如何載入渲染模板。將APP_DIRS設置為True。DjangoTemplates將在INSTALLED_APPS所包含的每個應用的目錄下查找名為”templates”子目錄。

在剛剛創建的templates目錄中,創建另一個名為polls的目錄,併在其中創建一個名為index.html的文件。換句話說,你的模板應該是polls/templates/polls/index.html。由於app_directories模板載入器如上所述工作,因此您可以在Django中簡單地引用此模板為polls/index.html(省掉前面的路徑)。

模板命名空間: 如果我們把模板直接放在polls/templates中(而不是創建另一個polls子目錄),但它實際上是一個壞主意。 Django將選擇它找到的名字匹配的第一個模板,如果你在不同的應用程式中有一個相同名稱的模板,Django將無法區分它們。我們需要能夠將Django指向正確的一個,確保這一點的最簡單的方法是通過命名空間。也就是說,將這些模板放在為應用程式本身命名的另一個目錄中。

將以下的代碼放入模板文件:

#  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中的index視圖來使用模板:

# polls/views.py

from django.http import HttpResponse
from django.template import RequestContext, 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 = RequestContext(request, {
        'latest_question_list': latest_question_list,
    })
    return HttpResponse(template.render(context))

該代碼載入名為polls/index.html的模板,並傳給它一個context。Context是一個字典,將模板變數的名字映射到Python對象。

然後你可以通過瀏覽器打開http://127.0.0.1:8000/polls 查看效果。

快捷方式:render()

常見的習慣是載入一個模板、填充一個context 然後返回一個含有模板渲染結果的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)

註意,一旦我們在所有這些視圖中完成這個操作,我們不再需要import loader和HttpResponse(如果您仍然有detail, results, and vote方法,您將需要保留HttpResponse)。

render()函數接受request對象作為其第一個參數,模板名稱作為其第二個參數,字典作為其可選的第三個參數。它返回一個HttpResponse對象,含有用給定的context 渲染後的模板。

404錯誤

現在,讓我們處理Question 詳細頁面的視圖 —— 顯示Question內容的頁面:

# 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})

這裡的新概念:如果具有所請求的ID的問題不存在,則該視圖引發Http404異常。

我們將在以後討論你可以在polls/detail.html模板文件里放些什麼代碼,但如果你想快點運行上面的例子,僅僅只需要:

# polls/templates/polls/detail.html

{{ question }}

快捷方式: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_object_or_404()而不是在更高層自動捕獲ObjectDoesNotExist異常,或者讓模型的API 引發 Http404 而不是ObjectDoesNotExist?
因為那樣做將會使模型層與視圖層耦合在一起。 Django最重要的一個設計目標就是保持松耦合。 一些可控的耦合將會在django.shortcuts 模塊中介紹。

還有一個get_list_or_404()函數,它的工作方式類似get_object_or_404() —— 差別在於它使用filter()而不是get()。如果列表為空則引發Http404。

使用模板系統

回到我們投票應用的detail()視圖。 根據context 變數question,下麵是polls/detail.html模板可能的樣子:

# polls/templates/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對對象問題進行字典查找。如果沒有,它嘗試一個屬性查找 - 在這種情況下工作。如果屬性查找失敗,它將嘗試列表索引查找。

方法調用發生在{% for %}迴圈中:question.choice_set.all被解釋為Python的代碼question.choice_set.all(),它返回一個由Choice對象組成的可迭代對象,並將其用於{% for %}標簽。訪問模板指南來瞭解更多關於模板的信息。

移除模板中硬編碼的URLs

我們在polls/index.html模板中編寫一個指向Question的鏈接時,鏈接中一部分是硬編碼的:

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

這種硬編碼、緊耦合的方法有一個問題,就是如果我們想在擁有許多模板文件的項目中修改URLs,那將會變得非常麻煩。 但是,因為你在polls.urls模塊的url()函數中定義了name 參數,所以你可以通過使用{% url %}模板標簽來移除對你的URL配置中定義的特定的URL的依賴:

<li><a href="{% 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'),
...

如果你想把polls應用中detail視圖的URL改成其它樣子比如 polls/specifics/12/,就可以不必在該模板(或者多個模板)中修改它,只需要修改 polls/urls.py:

...
# added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

URL name的命名空間

教程中的這個項目只有一個應用polls。在真實的Django項目中,可能會有五個、十個、二十個或者更多的應用。 Django如何區分它們URL的名字呢? 例如,polls 應用具有一個detail 視圖,相同項目中的博客應用可能也有這樣一個視圖。當使用模板標簽{% url %}時,人們該如何做才能使得Django知道為一個URL創建哪個應用的視圖?

答案是在你的主URLconf下添加命名空間。 在mysite/urls.py文件中,添加命名空間將它修改成:

# mysite/urls.py

from django.conf.urls import include, url
from django.contrib import admin

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

現在將你的polls/index.html改為具有命名空間的詳細視圖:

# polls/templates/polls/index.html

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

歡迎關註微信公眾號: Pythoner每日一報


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Qt使用統一的坐標系統來定位視窗部件的位置和大小。 以屏幕的左上角為原點即(0, 0)點,從左向右為x軸正向,從上向下為y軸正向,這整個屏幕的坐標系統就用來定位頂層視窗; 此外,視窗內部也有自己的坐標系統,它依然以左上角作為原點,從左向右為x軸正向,從上向下為y軸正向,原點、x軸、y軸圍成的區域叫做 ...
  • Flask是一個非常優秀的web框架,到目前為止,我相信關於他的介紹以及非常的多,就算cnblog中,隨便一搜也會有很多內容,但還是拋磚引玉,就當是一個自我的總結 部署環境 安裝python 首先,當然是安裝python環境,去 "官網" 來下載最新的環境(我選擇最新的3.6版本) 然後一路下一步即 ...
  • ECMAScript語言的標準是由Netscape、Sun、微軟、Borland等公司基於JavaScript和JScript錘煉、定義出來的。 ECMAScript可以為不同種類的宿主環境提供核心的腳本編程能力。ECMAScript僅僅是一個描述,定義了腳本語言的所有屬性、方法和對象。 ...
  • Spring_屬性配置細節 1、若字面值包含特殊字元,可以使用<![CDATA[]] 把字面值包裹起來 例 : 2、ref屬性來建立bean之間的引用關係和級聯屬性賦值 2.1 定義User.java(見上一篇文章)和Manager.java Bean 2、2 配置spring xml文件 3、配置 ...
  • 本工作室專註開發南方湛江海南七星彩投註網站系統建設開發,出租,支持帶手機版投註,以及手機APP開發,安裝版本,蘋果版。 QQ私聊:2046 771739 演示圖: ...
  • 操作系統: CentOS 6.5_x64開發語言: Python 適用場景:程式異常退出後需要及時啟動的情況。 源碼地址: https://github.com/mike-zhang/processGuarder 原理 通過ps檢查進程是否存在,如果不存在則啟動 使用 ./processGuarde ...
  • maven-compiler-plugin 編譯Java源碼,一般只需設置編譯的jdk版本 maven-dependency-plugin 用於複製依賴的jar包到指定的文件夾里 maven-jar-plugin 打成jar時,設定manifest的參數,比如指定運行的Main class,還有依賴 ...
  • 今天在牛客網上做了一道題,題意就是求左旋轉字元串。我使用輾轉相除法解之,一次性AC通過。實話說,每次寫演算法一次性通過,甚至一點編譯錯誤都沒有,我覺得這就是對我最好的嘉獎。 題目描述: 彙編語言中有一種移位指令叫做迴圈左移(ROL),現在有個簡單的任務,就是用字元串模擬這個指令的運算結果。對於一個給定 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...