撰寫視圖¶
視圖函式(簡稱視圖)是一個 Python 函式,它接收一個 Web 請求並返回一個 Web 回應。此回應可以是網頁的 HTML 內容、重定向、404 錯誤、XML 文件或圖片... 或任何東西。視圖本身包含返回該回應所需的任何任意邏輯。只要程式碼位於你的 Python 路徑上,這個程式碼可以放在任何你想要的地方。沒有其他要求,可以說沒有「魔法」。為了將程式碼放在某個地方,慣例是將視圖放在一個名為 views.py
的檔案中,並放置在你的專案或應用程式目錄中。
一個簡單的視圖¶
這是一個返回當前日期和時間的視圖,以 HTML 文件形式呈現。
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = '<html lang="en"><body>It is now %s.</body></html>' % now
return HttpResponse(html)
讓我們逐行查看此程式碼
首先,我們從
django.http
模組匯入HttpResponse
類別,以及 Python 的datetime
函式庫。接下來,我們定義一個名為
current_datetime
的函式。這是視圖函式。每個視圖函式都會接收一個HttpRequest
物件作為其第一個參數,通常命名為request
。請注意,視圖函式的名稱並不重要;它不需要以特定方式命名才能讓 Django 識別它。我們在這裡將其命名為
current_datetime
,因為該名稱清楚地表明了它的作用。視圖返回一個包含產生回應的
HttpResponse
物件。每個視圖函式都負責返回一個HttpResponse
物件。(有一些例外,但我們稍後會討論這些例外。)
Django 的時區
Django 包含一個預設為 America/Chicago
的 TIME_ZONE
設定。這可能不是你居住的地方,因此你可能需要在你的設定檔中更改它。
將 URL 對應到視圖¶
總結一下,這個視圖函式返回一個包含當前日期和時間的 HTML 頁面。要在特定的 URL 顯示此視圖,你需要建立一個 URLconf;請參閱 URL 分派器 以取得說明。
返回錯誤¶
Django 提供幫助返回 HTTP 錯誤代碼。除了 200(表示「OK」)之外,還有許多常見 HTTP 狀態代碼的 HttpResponse
子類別。你可以在 請求/回應 文件中找到可用的子類別的完整清單。返回這些子類別之一的實例,而不是普通的 HttpResponse
,以表示錯誤。例如
from django.http import HttpResponse, HttpResponseNotFound
def my_view(request):
# ...
if foo:
return HttpResponseNotFound("<h1>Page not found</h1>")
else:
return HttpResponse("<h1>Page was found</h1>")
並非每個可能的 HTTP 回應代碼都有專門的子類別,因為其中許多代碼並不常見。但是,如 HttpResponse
文件中所述,你也可以將 HTTP 狀態代碼傳遞給 HttpResponse
的建構函式,為你想要的任何狀態代碼建立一個返回類別。例如
from django.http import HttpResponse
def my_view(request):
# ...
# Return a "created" (201) response code.
return HttpResponse(status=201)
因為 404 錯誤是迄今為止最常見的 HTTP 錯誤,所以有一種更簡單的方法來處理這些錯誤。
Http404
例外¶
- class django.http.Http404¶
當你返回錯誤(例如 HttpResponseNotFound
)時,你負責定義結果錯誤頁面的 HTML。
return HttpResponseNotFound("<h1>Page not found</h1>")
為了方便起見,並且因為在你的網站上使用一致的 404 錯誤頁面是個好主意,Django 提供了一個 Http404
例外。如果你在視圖函式中的任何地方引發 Http404
,Django 將會捕獲它並返回你的應用程式的標準錯誤頁面,以及 HTTP 錯誤代碼 404。
範例用法
from django.http import Http404
from django.shortcuts import render
from polls.models import Poll
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404("Poll does not exist")
return render(request, "polls/detail.html", {"poll": p})
為了在 Django 返回 404 時顯示自訂 HTML,你可以建立一個名為 404.html
的 HTML 範本,並將其放置在你的範本樹的最上層。然後,當 DEBUG
設定為 False
時,將會提供此範本。
當 DEBUG
為 True
時,你可以向 Http404
提供訊息,它將會出現在標準的 404 偵錯範本中。將這些訊息用於偵錯目的;它們通常不適合在生產環境的 404 範本中使用。
自訂錯誤視圖¶
Django 中的預設錯誤視圖應足以滿足大多數 Web 應用程式的需求,但如果需要任何自訂行為,可以輕鬆地覆寫它們。在你的 URLconf 中指定處理常式,如下所示(將它們設定在其他任何地方都不會產生任何效果)。
page_not_found()
視圖會被 handler404
覆寫。
handler404 = "mysite.views.my_custom_page_not_found_view"
server_error()
視圖會被 handler500
覆寫。
handler500 = "mysite.views.my_custom_error_view"
permission_denied()
視圖會被 handler403
覆寫。
handler403 = "mysite.views.my_custom_permission_denied_view"
bad_request()
視圖會被 handler400
覆寫。
handler400 = "mysite.views.my_custom_bad_request_view"
另請參閱
使用 CSRF_FAILURE_VIEW
設定來覆寫 CSRF 錯誤視圖。
測試自訂錯誤視圖¶
若要測試自訂錯誤處理常式的回應,請在測試視圖中引發適當的例外。例如
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.test import SimpleTestCase, override_settings
from django.urls import path
def response_error_handler(request, exception=None):
return HttpResponse("Error handler content", status=403)
def permission_denied_view(request):
raise PermissionDenied
urlpatterns = [
path("403/", permission_denied_view),
]
handler403 = response_error_handler
# ROOT_URLCONF must specify the module that contains handler403 = ...
@override_settings(ROOT_URLCONF=__name__)
class CustomErrorHandlerTests(SimpleTestCase):
def test_handler_renders_template_response(self):
response = self.client.get("/403/")
# Make assertions on the response here. For example:
self.assertContains(response, "Error handler content", status_code=403)
非同步視圖¶
除了同步函式之外,視圖也可以是非同步(「async」)函式,通常使用 Python 的 async def
語法定義。Django 會自動偵測到這些函式並在非同步內容中執行它們。但是,你需要使用基於 ASGI 的非同步伺服器才能獲得它們的效能優勢。
以下是一個非同步視圖的範例
import datetime
from django.http import HttpResponse
async def current_datetime(request):
now = datetime.datetime.now()
html = '<html lang="en"><body>It is now %s.</body></html>' % now
return HttpResponse(html)
你可以在 非同步支援 中閱讀更多關於 Django 的非同步支援,以及如何最佳使用非同步視圖的資訊。