第三节:视图(Views)和模板(Templates)
目录
概览
视图是Django应用的网页的“类型”,一般服务于特定的功能并且有特定的模板,在我们的投票应用中,我们有下面四个视图:
- Question "index"页面——展示最新的几个问题。
- Question "detail"页面——显示问题内容,没有结果但是有一个投票表单。
- Question "results"页面——显示一个特定问题的结果
- Vote "action"——处理在一个特定问题的进行具体的选择
在Django中,Web页面和其他内容是通过一个视图提供的,每一个视图由一个简单的Python函数表示(或者是类方法),Django将解析被请求的Url去选择一个视图(准确地说,是url域名后面的部分)。
从一个url到一个视图,Django使用所谓的‘Urlconfs’一个Urlconf映射Url模式到一个视图,本教程提供了Urlconfs使用的基本介绍,你也可以参考django.urls获得更多信息。
编写视图
在polls/views.py添加视图:
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模块中添加url映射:
from django.conf.urls import url from . import views urlpatterns = [
# 例: /polls/
url(r'^$', views.index, name='index'),
# 例: /polls/5/
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# 例: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# 例: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
在浏览器打开“/polls/34”它将调用detail()方法并且显示你在url中提供的ID,同样的可以尝试打开“/polls/34/results”和“/polls/34/vote”。
当有人请求你网站的一个页面时,比如“/polls/34/”,Django将加载 mysite.urls Python模块因为它指定在ROOT_URLCONF配置中(mysite/settings.py)。它查找名为urlpatterns的变量并且按顺序遍历正则表达式。然后发现匹配"^polls/",它会替换掉匹配的文本("polls/")并将剩余的文本-"34/"交给"polls.urls"的url配置做进一步处理。它匹配r'^(?P<question_id>[0-9]+)/$',结果调用detail()视图:
detail(request=<HttpRequest object>, question_id='')
这个question_id='34'部分来自(?P<question_id>[0-9]+)。使用括号通过这个模式在一个“捕获”匹配的文本,并发送它给视图函数作为一个参数。?P<question_id>将被用做匹配模式的标识名称;[0-9]+匹配数字序列的正则表达式。
因为Url模式是正则表达式,所以格式没有任何限制,比如我们设置一个.html后缀的地址:
url(r'^polls/latest\.html$', views.index),
但是没必要这样做。
编辑视图实际做一些事情
每个视图负责两个事情之一,返回HttpResponse对象包含请求页面的内容,或者抛出异常例如Http404。
你的视图可能从数据库读取记录,它可以使用一个模板系统例如Django的,-或者第三方Python模板系统。它可以产生一个PDF文件,输出XML,创建一个ZIP文件,任何你想要的,都可以使用Python库。
因为它的方便,让我们使用Django自己的数据库API,在第二部分教程中已经提到过了,在index()视图,我们显示最新的五条投票问题,以逗号分隔,按发布时间排序(polls/views.py):
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)
这儿有个问题,就是:页面的设计你硬编码到视图中的。如果你想要改变页面外观,你就要编辑python代码,让我们来使用Django的模板系统创建一个模板把设计从Python代码中分离出来。
首先在你的polls目录来创建一个名叫templates的文件夹,Django将在这个路径查找模板。
你的项目的TEMPLATES设置描述了Django将怎样加载和渲染模板,默认的配置文件配置了一个DjangoTemplates 后端其APP_DIRS选项设置为True。按照惯例DjangoTemplates 查找每一个INSTALLED_APPS应用的子目录“templates”。
在你刚刚创建的templates 目录下创建另一个名叫polls的文件夹,并且创建一个名叫index.html的文件,也就是说,你的模板应该放在 polls/templates/polls/index.html
注意:现在我们可能把我们的模板文件直接放在polls/templates(而不是创建另外一个polls子目录),但它实际上不是一个好主意。Django将选择第一个名称相匹配的模板,并且如果你已经有一个在不同应用名称相同的模板,Django是无法区分他们的,我们需要一个正确的指向项目模板并确保他们有简单的命名方式,也就是说通过将模板放置到templates的另一个目录中。
在模板中输入以下代码polls/templates/polls/index.html:
{% 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视图去使用模板:
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变量,context是一个字典映射在模板的变量名。
通过在你的浏览器加载页面“/polls/”,然后你应该可以看到Question的一个列表。
一个快捷方法:render()
它是一个加载模板非常常见的语法,添加一个context并返回呈现模板结果的
HttpResponse对象。Django提供一个快捷方法,现在我们来重写index()视图:
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)
注意我们所有的视图都做到这一点的话,我们不在需要导入loader和HttpResponse。
这个render()函数以请求对象作为第一个参数,第二个参数是模板名称和另外一个参数字典类作为可选参数。它返回一个指定上下文指定模板的HttpResponse对象。
抛出404错误
现在,让我们解决问题的详情视图 - 这个页面显示指定投票的问题文本,编辑视图polls/views.py:
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})
这儿有个新概念:视图抛出Http404异常如果一个问题的ID不存在的话。
为了快速的展示一下上面的示例,在模板templates/polls/detail.html中输入简单的代码:
{{ question }}
一个快捷方法:get_object_or_404()
一个常用的语法去使用并且如果对象不存在抛出Http404异常。修改polls/views.py:
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})
该get_object_or_404()包含一个Django模型参数和另外一个关键字参数,它传递到模型管理的get()函数,如果对象不存在抛出Http404。
还有一个函数get_list_or_404(),工作原理和get_object_or_404()是一样的,使用filter()而不是get(),如果列表为空的话抛出404异常。
使用模板系统
回到我们投票应用的detail()视图。给一个question的context变量,编辑polls/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在一个字典查找question对象,如果属性查找失败,它将尝试列表索引查找。
方法调用发生在{% for %}循环:question.choice_set.all 将被解析为python代码question.choice_set.all(),它返回一个Choice迭代对象并且试用于{% for %}模板标签。
移除在模板中的硬编码网址
请记住,当我们在polls/index.html 模板编写一个链接时,这个链接是这样写的:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
这种硬编码,紧密耦合的问题是,当我们的url需要变化时,将非常麻烦需要修改大量的模板。不过,既然你的polls.urls 中url()方法定义的有名称,那么你可以使用{% url %}模板标签:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
这种方式是通过查找在polls.urls模块中定义的url来工作的,你可以准确的看到名为“detail”url定义如下:
...
# 做为{% url %}模板标签的“name”值
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
如果你想要修改投票的详细视图的url为其他的形式,也许像polls/specifics/12 ,你需要修改它在polls/urls.py:
...
# 增加一个单词 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
本教程的项目仅仅有一个应用,polls。在实际项目中,可能有五个,十个或者更多应用。Django如何区分他们之间的Url名称?例如polls应用有一个detail视图,并且可能同一个项目有一个应用是blog也有一个detail视图。当使用{% url %} 模板标签时Django如何知道url是哪个应用视图的?
答案是在你的url配置中增加命名空间。在polls/urls.py文件中,增加一个app_name 去设置应用的命名空间
from django.conf.urls import url from . import views app_name = 'polls'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>[0-9]+)/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>
第三节:视图(Views)和模板(Templates)的更多相关文章
- 【Django笔记1】-视图(views)与模板(templates)
视图(views)与模板(templates) 1,视图(views) 将接收到的数据赋值给模板(渲染),再传递给浏览器.HTML代码可以直接放在views.py(文件名可任意更换),也可以放在t ...
- Django基础之视图(views)层、模板层
目录 Django基础之视图(views)层.模板层 JsonResponse 向前端返回一个json格式字符串的两种方式 重写Django中的json的某个方法 form表单上传文件 FBV与CBV ...
- django在视图中使用模板
在视图中使用模板 在学习了模板系统的基础之后,现在让我们使用相关知识来创建视图. 重新打开我们在前一章在 mysite.views 中创建的 current_datetime 视图. 以下是其内容 ...
- Django (六) 视图 views
views 1. 视图及HttpRequest 和HttpResponse Django中的视图主要用来接受Web请求,并做出响应. 视图的本质就是一个Python中的函数 视图的响应分为两大类 1) ...
- django重点url,视图函数,模板语言
django重点url,视图函数,模板语言url 1.django重点url无命名分组:re_path() 2.url第一个参:url未命别名分组就不需要views中参数一定,若命别名(?P<y ...
- (day52)四、视图层、模板层
目录 一.视图层 (一)Request和Response对象 (1)Request对象 (2)Response对象 (二)JsonResponse对象 (1)前后端分离 (2)json_dumps_p ...
- Backbone.js 为复杂Javascript应用程序提供模型(models)、集合(collections)、视图(views)的结构
Backbone.js 为复杂Javascript应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和 自定义事件:集合附有可枚举函数 ...
- jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
如何分组管理权限,如何实现不同用户组显示对应视图views中不同的jobs,建议使用Role Strategy Plugin插件. 1.安装Role Strategy Plugin插件. 2.“系统管 ...
- Django学习总结之模板templates
- django模板: templates - 模板分为两个过程: 1, 加载 : loader.get_template('xxx.html') 返回值是一个template对象 2, 渲染 : t ...
- 用 php 实现一个视图组件和模板引擎——基础
只要不是做后端接口开发和一些作为守护进程之类的服务器脚本,大多数时候都是在和浏览器打交道,因此合理组织并展现 html 标签是最为常见的工作.一般大家使用框架时,都会自带有一套视图组件和模板引擎. 我 ...
随机推荐
- python之Excel操作
#coding:utf-8 __author__ = 'similarface' import xlrd book=xlrd.open_workbook('/Users/similarface/Dow ...
- AlwaysOn数据同步问题探究
随着AlwaysOn技术的流行,关于AlwayOn的问题也越来越多,某企业搭建有三副本的AlwaysOn一套,现想修改主节点上某张表的某个数据,看看会出现什么后果,如果结果正常,就同步到其他节点上:如 ...
- mac 文本编辑器 文本编码Unicode utf-8 不适用的问题
在mac上使用默认的文本编辑器打开下载的xx.txt文件,如果文本是gbk的编码可能会出现 文本编码Unicode utf-8 不适用的打开错误,如下图 解决方式: 文本编辑---偏好设置-----打 ...
- selenium eclipse环境搭建
1.python 3.5下载及安装 2.setuptools 与pip 下载地址是:http://pypi.Python.org/pypi/setuptools http://pypi.Python. ...
- 习题-任务2初始ASP.NET MVC项目开发
一.选择题 1.在ASP.NET MVC项目的RouteConfig.cs文件中,( )方法注册了默认的路由配置. A.RegisterMap B.RegisterRoutes C. ...
- px和em
相同点: 都是长度单位 不同点: px是绝对单位,不支持IE的缩放,em是相对单位. px的值是固定的,指定是多少就是多少:em得值不是固定的,并且em会继承父级元素的字体大小 ps: 浏览器的默认字 ...
- codeforces 725D . Contest Balloons(贪心+优先队列)
题目链接:codeforces 725D . Contest Balloons 先按气球数从大到小排序求出初始名次,并把名次排在第一队前面的队放入优先队列,按w-t-1值从小到大优先,然后依次给气球给 ...
- jQuery经典面试题及答案精选(转)
jQuery是一款非常流行的Javascript框架,如果你想要从事Web前端开发这个岗位,那么jQuery是你必须掌握而且能够熟练应用的一门技术.本文整理了一些关于jQuery的经典面试题及答案,分 ...
- 线性布局通过适配器可以动态加载view
因为适配器的getView的返回对象是view, 所以线性布局的对象可以通过addView动态加载适配器的getView 举例: mTestAdapter = new ListAdapter(this ...
- easyui表单多重验证,动态设置easyui控件
要实现的功能:在做添加学生信息的时候,利用easyui的验证功能判断 学号是否重复和学号只能为数字 最终效果如下图: 但在做这个的过程中,遇到了一系列的问题: 扩展validatebox的验证方法,最 ...