教程[3]Views and templates"/>
Django 系列官方教程[3]Views and templates
续第二章,这里开始创建视图
一、概述
视图是Django应用程序中的一种“类型”的网页,通常提供特定的功能并具有特定的模板。例如,在博客应用程序中,可能有以下视图:
博客主页–显示最新的几个条目。
条目“详细信息”页面–单个条目的永久链接页面。
基于年份的归档页面–显示给定年份中包含条目的所有月份。
基于月份的存档页面–显示给定月份中包含条目的所有日期。
基于日期的存档页面–显示给定日期的所有条目。
评论操作–处理向给定条目发布评论。
在我们的投票应用程序中,我们将有以下四种视图:
问题的“索引”页面–显示最新的几个问题。
问题“详细信息”页面–显示问题文本,没有结果,但带有投票表格。
问题“结果”页面–显示特定问题的结果。
投票操作–处理对特定问题中特定选项的投票。
在Django中,视图形成网页。每个视图都由一个Python函数(或方法,在基于类的视图中)表示。Django将通过检查请求的URL(准确地说,是URL中域名后的部分)来选择视图。
现在,在你的网络时代,你可能会遇到像ME2/Sites/dirmod.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B这样华丽的链接。Django都是可以识别的。
为了从URL到视图,Django使用了所谓的“URLconfs”。URLconf将URL模式映射到视图。
二、创建视图
打开polls/views.py
.
def detail(request, question_id):return HttpResponse("问题展示: %s." % question_id)def results(request, question_id):response = "这个问题的答案有: %s."return HttpResponse(response % question_id)def vote(request, question_id):return HttpResponse("正在投票的问题是 %s." % question_id)
同时在polls.urls中添加
path()调用
from django.urls import pathfrom . import viewsurlpatterns = [path('', views.index, name='index'),path('<int:question_id>/', views.detail, name='detail'),path('<int:question_id>/results/', views.results, name='results'),path('<int:question_id>/vote/', views.vote, name='vote'),
]
这时我们可以在
http://127.0.0.1:8000/polls/1/
http://127.0.0.1:8000/polls/1/results/
http://127.0.0.1:8000/polls/1/vote/
分别看到我们创建的三个界面
Django会先在mysite.urls
中找到polls/,并将1/results发送到polls/urls,所以polls.urls
中为<int:question_id>/results/
三、创建视图内容
每个视图只有两种可能,返回HttpResponse对象或404.
视图可以从数据库中读取记录,也可以不读取。
可以使用Django之类的模板系统,也可以不使用第三方Python模板系统。
可以生成一个PDF文件,输出XML,动态创建一个ZIP文件,
使用任何你想要的Python库。
Django想要的只是HttpResponse
现在我们使用自带的数据库操作API来编写视图
打开polls/views.py,修改上半部分,detial、results和votes不变
from django.http import HttpResponsefrom .models import Questiondef 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)
现在问题来了,我们还需要更改页面的外观,这也需要通过修改python指令实现,所以我们使用了Django的模板系统,将视图和外观分离。
首先,在polls目录中创建一个名为templates的目录。Django将在那里寻找模板。
项目的模板设置描述Django将如何加载和呈现模板。默认设置文件配置一个DjangoTemplates后端,其APP_DIRS选项设置为True。按照惯例,DjangoTemplates会在每个已安装的应用程序中查找“templates”子目录。
在刚刚创建的templates目录中,创建另一个名为polls的目录,并在其中创建一个名为index.html的文件。换句话说,模板应该位于polls/templates/polls/index.html。由于app_目录模板加载器的工作原理如上所述,您可以在Django中将该模板称为polls/index.html.
现在我们更新polls/views.py,
from django.http import HttpResponse
from django.template import loaderfrom .models import Questiondef 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的模板。并将其传递给context.。context.是将模板变量名映射到Python对象的字典。
通过将浏览器指向“/polls/”加载页面,您应该会看到一个项目符号列表,其中包含教程2中的各类问题。链接指向问题的详细页面。
加载模板、填充context.并返回带有呈现模板结果的HttpResponse对象是一种非常常见的习惯用法。
四、配置404错误
首先继续修改polls/views.py
from django.http import Http404
from django.shortcuts import renderfrom .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})
为了快速验证我们添加页面polls/detail.html
{{ question }}
访问127.0.0.1:8000/polls/9999/验证。
五、get_object_or_404的简单写法
继续修改polls/views.py
from django.shortcuts import get_object_or_404, renderfrom .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})
为什么我们要使用帮助函数get_object_or_404(),而不是在更高级别上自动捕获ObjectDoesNotExist异常,或者让模型API引发Http404而不是ObjectDoesNotExist?
因为这会将模型层耦合到视图层。Django最重要的设计目标之一是保持松散耦合。
get_list_or_404() 是filter()层面的该指令,get_object_or_404()是get()的.
六、使用模板系统
现在我们来完善detail.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
模板系统使用点查找语法来访问变量属性。在{question.question_text}的例子中,首先Django对对象问题进行字典查找。如果做不到这一点,它会尝试属性查找——在本例中,这是有效的。如果属性查找失败,它会尝试列表索引查找。
{% for %} 循环方法调用,question.choice_set.all
会被编译器修改为question.choice_set.all()
,从而返回Choice
objects。
七、删除模板中的硬编码链接。在polls/index.html中,
链接被硬编码为:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
这种硬编码、紧密耦合的方法的问题是,在具有大量模板的项目上更改URL会很复杂。但是,由于我们在polls.urls中的path()函数中定义了name参数。在URL模块中,我们可以使用{%URL%}模板标记删除对URL配置中定义的特定URL路径的依赖:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
我们可以在polls.urls中看到这个定义:
path('<int:question_id>/', views.detail, name='detail'),
八、设定名称域
真实的项目中,我们可能会遇到很多个app而不是仅有一个polls,那么{% url %}要怎么识别每个应用的detail页面呢?
所以我们需要设置一个姓名域。我们需要在polls/urls.py中添加app_name
from django.urls import pathfrom . import viewsapp_name = 'polls'
urlpatterns = [path('', views.index, name='index'),path('<int:question_id>/', views.detail, name='detail'),path('<int:question_id>/results/', views.results, name='results'),path('<int:question_id>/vote/', views.vote, name='vote'),
]
现在将polls/index.html模板由:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
修改为:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
更多推荐
Django 系列官方教程[3]Views and templates
发布评论