基于类的视图

视图是可调用的,能接受用户的请求并返回响应。视图远不只是个函数,Django提供了一些可用作视图的类的示例,允许你通过继承和复用构建自己的视图并且复用这些代码。虽然接下来还会介绍一些用于任务的通用视图,但你可能想自己设计可复用的视图结构,以便针对某些特殊场景。详情请见 class-based views reference documentation</ref/class-based-views/index> 。

基础示例

Django 提供了适用于很多应用的基本视图类。所有视图继承自 View 类,它处理视图链接到 URLs,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()),
]

有关如何使用内建通用视图的更多信息,请查阅在 generic class-based views 的下一个主题。

支持其他 HTTP 方法

如果某人想将视图作为 API 来访问图书馆。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 请求,那么将响应一个空 body 和 Last-Modified 头将标识最新书籍的出版时间。基于这些信息,客户端可以选择是否下载一个完整的对象类。

Asynchronous class-based views

As well as the synchronous (def) method handlers already shown, View subclasses may define asynchronous (async def) method handlers to leverage asynchronous code using 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!")

Within a single view-class, all user-defined method handlers must be either synchronous, using def, or all asynchronous, using async def. An ImproperlyConfigured exception will be raised in as_view() if def and async def declarations are mixed.

Django will automatically detect asynchronous views and run them in an asynchronous context. You can read more about Django's asynchronous support, and how to best use async views, in 异步支持.