Django 6.1 编写视图:HTTP 响应、错误处理与异步视图

视图函数(简称“视图”)是接受 Web 请求并返回 Web 响应的 Python 函数。响应可以是网页的 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 错误状态码的辅助类。HttpResponse 的子类覆盖了许多常见的非 200 状态码,完整列表见请求与响应文档。需要返回错误时,可以返回相应子类的实例,例如:

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 构造函数传入 status 参数,创建使用任意状态码的响应。下面返回 201(已创建)状态码:

from django.http import HttpResponse


def my_view(request):
    # ...

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

404 是最常见的 HTTP 错误之一,Django 还提供了更简便的处理方式。

Http404 异常

class django.http.Http404

如果直接返回 HttpResponseNotFound 等错误响应,需要自己提供错误页面的 HTML:

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

为便于全站使用一致的 404 页面,Django 提供 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。只有 DEBUG 为 False 时,才会使用这个模板。

当 DEBUG 为 True 时,传给 Http404 的消息可以显示在标准的 404 调试页面中。这些消息用于调试,通常不适合显示在生产环境的 404 模板中。

自定义错误视图

Django 内置的错误视图通常足以满足大多数 Web 应用的需求。如需自定义行为,可以在 URLconf 中指定相应的处理器;放在其他位置不会生效。应在根 URLconf 中配置这些处理器。

使用 handler404 覆盖 page_not_found():

handler404 = "mysite.views.my_custom_page_not_found_view"

使用 handler500 覆盖 server_error():

handler500 = "mysite.views.my_custom_error_view"

使用 handler403 覆盖 permission_denied():

handler403 = "mysite.views.my_custom_permission_denied_view"

使用 handler400 覆盖 bad_request():

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)

代码注释说明:ROOT_URLCONF 必须指向包含 handler403 = ... 定义的模块;随后对响应做断言。示例中的 assertContains() 同时检查响应内容和 403 状态码。

异步视图

除了同步函数,视图也可以是异步函数,通常使用 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 异步支持以及如何恰当使用异步视图的信息,参见异步支持。

原文版权声明:© 2005–2026 Django Software Foundation 及各位贡献者。Django 是 Django Software Foundation 的注册商标。本文为基于官方简体中文版本的中文校订转载,非 Django 官方发布。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容