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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...