编写视图
视图函数(或简称视图)是一种接受 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><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外,还有很多常见的 HTTP 状态代码。你可以在 request/response 文档中找到所有可用子类的列表。返回这些子类中某个子类的实例而不是 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
时提供。
当 DEBUG 为 True
时,你可以提供 Http404
信息,并且在标准的 404 调试模板里显示。使用这些信息来调试;它们通常不适合在生产环境下的404模板。
自定义报错视图
Django 中的默认报错视图应该能够满足大多数 Web 应用程序的需求,但如果您需要任何自定义行为,也可以轻松覆盖。 在 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)
异步视图
除了同步函数,视图也可以是异步(“async”)函数,通常使用 Python 的 async def
语法定义。Django 会自动检测这些函数,并在异步上下文中运行它们。但是,你需要使用基于 ASGI 的异步服务器来获得它们的性能优势。
下面是一个异步视图的例子:
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 的异步支持,以及如何最好的使用异步视图。