编写视图

视图函数,简称视图,是一个 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 包含一个TIME_ZONE设置,默认为America/Chicago。这可能不是你的所在地,因此你可能需要在设置文件中更改它。

将 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时,将提供此模板。

DEBUGTrue时,你可以向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 异步支持以及如何最好地使用异步视图的信息。

返回顶部