内容太多了断个章接着记笔记…

编辑更多视图

让我们向 polls/views.py 中添加更多视图:

1
2
3
4
5
6
7
8
9
10
11
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)


def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)


def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)

将这些视图添加进 polls.urls 模块里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.urls import path

from . import views

urlpatterns = [
# ex: /polls/
path("", views.index, name="index"),
# ex: /polls/5/
path("<int:question_id>/", views.detail, name="detail"),
# ex: /polls/5/results/
path("<int:question_id>/results/", views.results, name="results"),
# ex: /polls/5/vote/
path("<int:question_id>/vote/", views.vote, name="vote"),
]

之后我们若转到 /polls/34/Django 将会运行 detail() 方法并且展示你在 URL 里提供的问题 ID

更好的视图

每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse 对象,或者抛出一个异常,比如 Http404

你的视图可以从数据库里读取记录,可以使用一个模板引擎(比如 Django 自带的,或者其他第三方的),可以生成一个 PDF 文件,可以输出一个 XML,创建一个 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 库。

让我们在在 index() 函数里插入一些新内容,让它能展示数据库里以发布日期排序的最近 5 个投票问题,以空格分割:

1
2
3
4
5
6
7
8
9
10
11
12
from django.http import HttpResponse

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
output = ", ".join([q.question_text for q in latest_question_list])
return HttpResponse(output)


# Leave the rest of the views (detail, results, vote) unchanged

这里有个问题:页面的设计写死在视图函数的代码里的。如果你想改变页面的样子,就需要编辑 Python 代码。所以让我们使用 Django 的模板系统,只要创建一个视图,就可以将页面的设计从代码中分离出来。

首先,在你的 polls 目录里创建一个 templates 目录。Django 将会在这个目录里查找模板文件。项目的 TEMPLATES 配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates 后端,并将 APP_DIRS 设置成了 True。这一选项将会让 DjangoTemplates 在每个 INSTALLED_APPS 文件夹中寻找 “templates“ 子目录。这就是为什么尽管我们没有像在第二部分中那样修改 DIRS 设置,Django 也能正确找到 polls 的模板位置的原因。

在刚刚创建的 templates 目录里,再创建一个目录 polls,然后在其中新建一个文件 index.html

将以下代码输入到模版文件中:

1
2
3
4
5
6
7
8
9
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

然后,让我们更新一下 polls/views.py 里的 index 视图来使用模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.http import HttpResponse
from django.template import loader

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
template = loader.get_template("polls/index.html")
context = {
"latest_question_list": latest_question_list,
}
return HttpResponse(template.render(context, request))

上述代码的作用是,载入 polls/index.html 模板文件,并且向它传递一个上下文(context)。这个上下文是一个字典,它将模板内的变量映射为 Python 对象。

render() 函数

「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。于是 Django 提供了一个快捷函数,我们用它来重写 index() 视图:

1
2
3
4
5
6
7
8
9
from django.shortcuts import render

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
context = {"latest_question_list": latest_question_list}
return render(request, "polls/index.html", context)

抛出 404 错误

现在,来处理投票详情视图——它会显示指定投票的问题标题。下面是这个视图的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.http import Http404
from django.shortcuts import render

from .models import Question


# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, "polls/detail.html", {"question": question})

现在,如果指定问题 ID 所对应的问题不存在,这个视图就会抛出一个 Http404 异常。

get_object_or_404() 函数

尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 detail() 视图代码:

1
2
3
4
5
6
7
8
9
from django.shortcuts import get_object_or_404, render

from .models import Question


# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})