参考资料:Tutorial03
Overview
Django 中定义了一个特殊的对象,称作 view,它抽象地对应着一个网页,Django 通过一个函数来抽象表示一个 view。同时 Django 提供了叫做 URLconfs 的东西,会将一个个 URL 模式字符串一一对应到每一个 view 中。
Writing more view
我们可以在 polls/views.py
中加入以下代码:
1
2
3
4
5
6
7
8
9
| 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.py
文件中:
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'),
]
|
注意其中 <int:question_id>
这一部分:
<int:
这一部分将 URL 中的请求部分转化成指定的类型,同时决定指向的模式字符串。:question_id>
这一部分给定匹配的模式字符串一个变量名。
PostScript:不建议愚蠢地将像 .html
一样的 URL cruft 添加到 path 中,比如:
1
| path('polls/latest.html', views.index)
|
Write views that actually do something
每个 views 主要完成两件事情:返回包含所请求页面内容的 HttpRsponse
对象,或返回异常。
我们在 polls/views.py
中完成以下的事情(根据发布的日期显示系统中的最新的 5 个投票问题):
1
2
3
4
5
6
7
| 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)
|
这样的返回 Http 是硬核编码在 Python 代码中的,为了使前端代码与 Python 的后端代码分离,我们需要在应用中创建一个 templates
的子目录,进行渲染工作的 DjangoTemplates
会在每个 INSTALLED_APPS
中寻找一个 templates
的子目录。
所以我们创建目录以及文件 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
,更改成以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
| 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))
|
主要到代码的最后一行:加载模板,Python 渲染,返回 Http 响应 → 是一个常用的功能,Django 将这三个功能集成到了一起形成了一个 shortcut,即可以用以下简化的代码表示:
1
2
3
4
5
6
7
8
| 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)
|
Raising a 404 error
Django 定义了一个返回 404 错误码的模块,通过以下方式导入:
1
| from django.http import Http404
|
在应用中,我们使用抛出异常的方式使用导入的 Http404
,如下:
1
| raise Http404("This is a 404 error!")
|
一个实际的应用场景如下:
1
2
3
4
5
6
7
8
9
10
11
| 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})
|
这段代码的意思是,从 Question
对应的所有对象中寻找一个 pk=quesition_id
的对象,如果不存在则抛出 Http404
的异常。
这个功能比较常用,因此 Django 提供了一个 shortcut:get_object_or_404
。一个实例代码如下:
1
2
3
4
5
6
7
| 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})
|
还有一个类似的 shortcut 函数为:get_list_or_404
Removing hardcodeed URLs in templates
在之前编写的 html 模板文件中,href
指向的 url 出现了直接拼接字符串的硬编码方式,我们可以使用以下的方式替换这种写法:
1
2
3
4
5
| <li><a href="{% url 'polls' question.id %}">{{ question.question_text }}</a></li>
<!--
原来的写法:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
--!>
|
这样做的好处是,将这个 href
与 urlpatterns
中对应的模式字符串连接起来,他们的任何改变会相互影响。
Namespacing URL names
在实际的项目中可能存在许许多多的应用,那么使用上面的方法如何知道 URL 指向那个应用呢?
在应用的 urls.py
这个文件中,可以在 urlpattern
列表定义之前,加入:
于是,可以对将应用模板改成如下形式:
1
2
3
4
5
| <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
<!--
原来的写法:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
--!>
|