编写视图Link to this heading

视图函数(或简称视图)是一种接受 Web 请求并返回 Web 响应的 Python 函数。 该响应可以是网页的 HTML 内容、重定向、404 错误、XML 文档、图像……或者任何东西。 视图本身包含返回该响应所需的任意逻辑。 该代码可以存在于您想要的任何地方,只要它位于您的 Python 路径上即可。 没有其他要求——可以说没有“魔法”。 为了将代码放置在某个地方,惯例是将视图放置在名为 views.py 的文件中,该文件放置在项目或应用程序目录中。

一个简单的视图Link to this heading

这里是一个以 HTML 文档形式返回当前日期和时间的视图:

Code
from django.http import HttpResponse
import datetime


def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><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 对象。(有例外,我们稍后再讲)

将 URL 映射到视图Link to this heading

因此,回顾一下,这个视图函数返回包含当前日期时间的HTML页面。如果在特定的 URL 使用这个视图,你需要创建 URLconf ;查看 URL调度器 的操作说明。

返回错误信息Link to this heading

Django 提供了有关返回 HTTP 错误代码的帮助。HttpResponse 的子类除了200外,还有很多常见的 HTTP 状态代码。你可以在 request/response 文档中找到所有可用子类的列表。返回这些子类中某个子类的实例而不是 HttpResponse 来表示错误。比如:

Code
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 的构造函数,这样就可以为任何状态代码创建返回类。比如:

Code
from django.http import HttpResponse


def my_view(request):
    # ...

    # Return a "created" (201) response code.
    return HttpResponse(status=201)

因为 404 错误是最常见的 HTTP 错误,这里有更简单的方法来处理这些错误。

Http404 异常Link to this heading

class django.http.Http404Link to this definition

当你返回错误,例如 HttpResponseNotFound ,你需要定义错误页面的 HTML 。

Code
return HttpResponseNotFound("<h1>Page not found</h1>")

为方便起见,在你的网站里有个一致的 404 错误页面是个好办法,Django 提供 Http404 异常。如果你在视图的任何地方引发了 Http404 ,Django 会捕捉到它并且返回标准的错误页面,连同 HTTP 错误代码 404 。

用法示例:

Code
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 时提供。

DEBUGTrue 时,你可以提供 Http404 信息,并且在标准的 404 调试模板里显示。使用这些信息来调试;它们通常不适合在生产环境下的404模板。

自定义报错视图Link to this heading

Django 中的默认报错视图应该能够满足大多数 Web 应用程序的需求,但如果您需要任何自定义行为,也可以轻松覆盖。 在 URLconf 中指定处理程序,如下所示(在其他任何地方设置它们将不起作用)。

可以用 handler404: 覆盖 page_not_found() 视图:

Code
handler404 = "mysite.views.my_custom_page_not_found_view"

可以用 handler500: 覆盖 server_error() 视图:

Code
handler500 = "mysite.views.my_custom_error_view"

可以用 handler403: 覆盖 permission_denied() 视图:

Code
handler403 = "mysite.views.my_custom_permission_denied_view"

可以用 handler400: 覆盖 bad_request() 视图:

Code
handler400 = "mysite.views.my_custom_bad_request_view"

测试自定义报错视图Link to this heading

为了测试自定义报错处理的响应,可以适当地在测试视图里引发异常。例如:

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

异步视图Link to this heading

除了同步函数,视图也可以是异步(“async”)函数,通常使用 Python 的 async def 语法定义。Django 会自动检测这些函数,并在异步上下文中运行它们。但是,你需要使用基于 ASGI 的异步服务器来获得它们的性能优势。

下面是一个异步视图的例子:

Code
import datetime
from django.http import HttpResponse


async def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

你可以在 异步支持 中阅读更多关于 Django 的异步支持,以及如何最好的使用异步视图。