基於類別的視圖

視圖是一個可呼叫的對象,它接受請求並返回響應。這不僅僅是一個函數,Django 提供了一些可以用作視圖的類別範例。這些類別允許您通過利用繼承和混入來構建視圖並重複使用程式碼。還有一些用於稍後我們將會介紹的任務的通用視圖,但您可能希望設計自己的可重複使用視圖結構,以適合您的用例。有關完整詳細資訊,請參閱基於類別的視圖參考文件

基本範例

Django 提供了適用於各種應用程式的基本視圖類別。所有視圖都繼承自View類別,該類別處理將視圖連結到 URL、HTTP 方法調度和其它常見功能。RedirectView提供 HTTP 重定向,而TemplateView擴展了基底類別,使其也渲染模板。

在您的 URLconf 中的用法

使用通用視圖最直接的方式是在您的 URLconf 中直接建立它們。如果您只更改基於類別的視圖上的幾個屬性,您可以將它們傳遞到 as_view() 方法呼叫本身中

from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path("about/", TemplateView.as_view(template_name="about.html")),
]

傳遞給 as_view() 的任何引數都會覆蓋在類別上設定的屬性。在此範例中,我們在 TemplateView 上設定了 template_name。類似的覆蓋模式可用於 RedirectView 上的 url 屬性。

子類化通用視圖

使用通用視圖的第二種更強大的方式是從現有視圖繼承並覆蓋屬性(例如 template_name)或方法(例如 get_context_data)在您的子類別中以提供新的值或方法。例如,考慮一個只顯示一個模板 about.html 的視圖。Django 有一個通用視圖可以做到這一點 - TemplateView - 因此我們可以子類化它並覆蓋模板名稱

# some_app/views.py
from django.views.generic import TemplateView


class AboutView(TemplateView):
    template_name = "about.html"

然後我們需要將這個新的視圖添加到我們的 URLconf 中。TemplateView 是一個類別,而不是一個函數,因此我們將 URL 指向 as_view() 類別方法,該方法為基於類別的視圖提供類似函數的入口

# urls.py
from django.urls import path
from some_app.views import AboutView

urlpatterns = [
    path("about/", AboutView.as_view()),
]

有關如何使用內建通用視圖的更多資訊,請參閱下一個關於通用基於類別的視圖的主題。

支援其他 HTTP 方法

假設有人想使用視圖作為 API 通過 HTTP 存取我們的圖書庫。API 客戶端會不時連接並下載自上次訪問以來發行的圖書的圖書數據。但是,如果從那時起沒有出現新書,則從資料庫中提取圖書、渲染完整響應並將其發送給客戶端是浪費 CPU 時間和頻寬。最好詢問 API 最近一次出版的圖書的時間。

我們在 URLconf 中將 URL 對應到圖書列表視圖

from django.urls import path
from books.views import BookListView

urlpatterns = [
    path("books/", BookListView.as_view()),
]

以及視圖

from django.http import HttpResponse
from django.views.generic import ListView
from books.models import Book


class BookListView(ListView):
    model = Book

    def head(self, *args, **kwargs):
        last_book = self.get_queryset().latest("publication_date")
        response = HttpResponse(
            # RFC 1123 date format.
            headers={
                "Last-Modified": last_book.publication_date.strftime(
                    "%a, %d %b %Y %H:%M:%S GMT"
                )
            },
        )
        return response

如果從 GET 請求存取視圖,則響應中返回一個物件列表(使用 book_list.html 模板)。但是,如果客戶端發出 HEAD 請求,則響應具有空的主體,並且 Last-Modified 標頭指示最近出版的圖書的時間。根據此資訊,客戶端可能會或可能不會下載完整的物件列表。

非同步的基於類別的視圖

除了已經顯示的同步 (def) 方法處理常式之外,View 子類別可以定義非同步 (async def) 方法處理常式,以利用使用 await 的非同步程式碼

import asyncio
from django.http import HttpResponse
from django.views import View


class AsyncView(View):
    async def get(self, request, *args, **kwargs):
        # Perform io-blocking view logic using await, sleep for example.
        await asyncio.sleep(1)
        return HttpResponse("Hello async world!")

在單個視圖類別中,所有使用者定義的方法處理常式必須是同步的,使用 def,或者都是非同步的,使用 async def。如果混合使用了 defasync def 宣告,則會在 as_view() 中引發 ImproperlyConfigured 例外。

Django 將自動偵測非同步視圖並在非同步上下文中執行它們。您可以在非同步支援中閱讀更多關於 Django 的非同步支援以及如何最佳使用非同步視圖的資訊。

返回頂部