Django教程:第一个Django应用程序(3)
2013-10-08 磁针石
#承接软件自动化实施与培训等gtalk:ouyangchongwu#gmail.comqq 37391319
#博客:http://blog.csdn.net/oychw
#版权所有,转载刊登请来函联系
# 深圳测试自动化python项目接单群113938272深圳广州软件测试开发 6089740
#深圳湖南人业务户外群 66250781武冈洞口城步新宁乡情群49494279
#参考资料:https://docs.djangoproject.com/en/1.5/intro/tutorial01/
# http://django-chinese-docs.readthedocs.org/en/latest/intro/tutorial01.html
#本文的图片没有上传,完整的文档参见:python模块笔记:http://t.cn/z8ggk71
本节关注创建公共界面 –视图(views)。
哲学
在 Django 应用中,视图是一“类”具有特定功能和模板的网页。 例如,在博客应用中,你可能会有以下视图:
§ 博客首页 – 显示最新发表的博客。
§ 博客详细页面 – 单个博客的固定连接。
§ 基于年份的归档页 – 显示指定年份所有月份的博客。
§ 基于月份的归档页 – 显示指定月份所有日期的博客。
§ 基于日期的归档页 –显示指定日期所有博客。
§ 评论 – 为指定博客处理评论。
在我们的投票应用中,将有以下四个视图:
§ Poll“index” 页 – 显示最新投票。
§ Poll“detail” 页 – 显示投票,无投票结果,但是可以投票。
§ Poll“results” 页 – 显示指定的投票结果。
§ 投票 – 处理投票。
在 Django 中,网页及其他内容是由视图展现。视图就是简单的 Python 函数(或方法)。Django 会通过检查URL(确切地说是域名之后的那部分 URL)来匹配一个视图。
URL 模式是URL的通用形式- 比如: /newsarchive/<year>/<month>/.
Django 通过‘URLconfs’把URL 模式 (正则表达式)映射到视图。本教程中介绍URLconfs 的基本指令,更多信息参见django.core.urlresolvers。
第一个视图
编辑polls/views.py:
from django.http importHttpResponse
defindex(request):
returnHttpResponse("Hello, world. You're at the poll index.")
然后配置URLconf 。在 polls 目录下创建一个名为 urls.py 的 URLconf 文档。
from django.conf.urls importpatterns,url
from polls importviews
urlpatterns=patterns('',
url(r'^$',views.index,name='index')
)
配置 mysite/urls.py 调用polls.urls:
fromdjango.conf.urls import patterns, include, url
fromdjango.contrib import admin
admin.autodiscover()
urlpatterns= patterns('',
url(r'^polls/', include('polls.urls')),
url(r'^admin/', include(admin.site.urls)),
)
启动开发服务器:python manage.py runserver 192.168.4.13:8000。访问:http://192.168.4.13:8000/polls/,将可以看到:Hello, world.You're at the poll index。
现在你在 URLconf 中配置了 index 视图。通过浏览器访问 http://localhost:8000/polls/ ,如同你在 index 视图中定义的一样,你将看到“Hello, world. You’re at the poll index.” 文字。
url() 两个必选参数: regex 和view, 两个可选参数:kwargs和name。
regex是regularexpression 的简写,这是字符串模式匹配的语法,在 Django 中就是url 模式。 Django 将请求的URL 从上至下依次匹配列表中的正则表达式,直到匹配为止。
注意这些正则表达式不会匹配 GET 和 POST 参数以及域名。 例如:针对请求http://www.example.com/myapp/,URLconf 将只查找 myapp/。而在http://www.example.com/myapp/?page=3 也是如此。
当 Django 匹配了正则表达式就会调用响应的view函数, HttpRequest作为第一个参数和正则表达式 “捕获” 值的作为其他参数。 如果是简单正则捕获,将按顺序位置传参数;如果是命名正则捕获,将按关键字传参数值。
kwargs任意关键字参数,可传一个字典至目标视图。
Name:给你的URL取名,让你在 其他地方尤其是模板中可以更方便地引用它,特别是在模板中。 这一强大的功能可允许你通过一个文件就可修改项目中的全局URL 模式。
更多视图
现在我们再增加一些有参数的视图:
defdetail(request, poll_id):
return HttpResponse("You're looking atpoll %s." % poll_id)
defresults(request, poll_id):
return HttpResponse("You're looking atthe results of poll %s." % poll_id)
defvote(request, poll_id):
return HttpResponse("You're voting onpoll %s." % poll_id)
添加对应的url映射:
fromdjango.conf.urls import patterns, url
frompolls import views
urlpatterns= patterns('',
# ex: /polls/
url(r'^$', views.index, name='index'),
# ex: /polls/5/
url(r'^(?P<poll_id>\d+)/$',views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<poll_id>\d+)/results/$',views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<poll_id>\d+)/vote/$',views.vote, name='vote'),
)
在你的浏览器中访问 http://192.168.4.13:8000/polls/34/ 。将运行detail()方法并显示URL 中提供的ID 。/polls/34/results和/polls/34/vote/也有类似显示。
访问网站页面时,比如/polls/34/时,Django 会加载mysite.urls模块(settings中的ROOT_URLCONF = 'mysite.urls'),然后找到urlpatterns变量并依次匹配正则表达式。include()表示导入其他 URL配置。include()中的正则表达式没有$(字符串结尾的匹配符),尾部是一个反斜杠。当 Django 解析include()时,它截取匹配部分而把剩余的字符串交由子URLconf 作进一步处理。这样include()使 URLs 即插即用。
当用户访问 “/polls/34/”:
§ Django 匹配'^polls/'
§ Django 截取匹配文本polls/,发送34/ 到‘polls.urls’ URLconf ,后者匹配r'^(?P<poll_id>\d+)/$' 导致如下调用
detail(request=<HttpRequestobject>, poll_id='34')
添加些实际的功能
每个视图返回一个包含请求页面的内容HttpResponse对象或者抛出一个异常,例如 Http404。
视图可以选择是否读取数据库记录,是否使用Django或python第三方模板系统。视图可以生成PDF 文件,输出 XML ,创建 ZIP 文件等。可以使用任何 Python 库。
下面index视图显示系统中最新发布的 5 个调查问卷,以逗号分割并按发布日期排序::
fromdjango.http import HttpResponse
from polls.modelsimport Poll
def index(request):
latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
output = ','.join([p.question for p in latest_poll_list])
returnHttpResponse(output)
通过模板可以分离python和设计。
在polls目录下创建templates目录。Django 将会在那寻找模板。
Django 的TEMPLATE_LOADERS配置中查找模板的方法。 django.template.loaders.app_directories.Loader 就会在INSTALLED_APPS的templates子目录下查找模板。
在你刚创建的templates目录下,创建polls(防止不同应用有重名的模板)的目录,并在其中创建文件index.html。你的模板位于polls/templates/polls/index.html 。简写为polls/index.html就可。
{% iflatest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li><a href="/polls/{{poll.id }}/">{{ poll.question }}</a></li>
{% endfor %}
</ul>
{% else%}
<p>No polls are available.</p>
{%endif %}
现在让我们在 index 视图中使用这个模板:
from django.http import HttpResponse
from django.template import Context, loader
from polls.models import Poll
def index(request):
latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = Context({
'latest_poll_list': latest_poll_list,
})
return HttpResponse(template.render(context))
代码将加载 polls/index.html 模板并传递 context。context是一个映射模板变量为Python 对象的字典。
在你的浏览器中加载 “/polls/” 页,你应该看到一个列表,包含了在教程 第1部分 中创建的 “What’sup” 调查。而链接指向 poll 的具体页面。
上述加载模板过程很常用,为此Django提供了快捷方式:render(),用于加载模板,填充上下文并返回一个含有模板渲染结果的HttpResponse对象。
from django.shortcuts import render
from polls.models import Poll
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
context = {'latest_poll_list': latest_poll_list}
return render(request, 'polls/index.html', context)
render() 函数中第一个参数是 request 对象,第二个参数是一个模板名称,第三个是一个字典类型的可选参数。它将返回根据给定模板和上下文渲染的HttpResponse对象。
抛出 404 异常
显示具体投票的视图detail:
from django.http import Http404
# ...
def detail(request, poll_id):
try:
poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render(request, 'polls/detail.html', {'poll': poll})
poll 的 ID 不存在,视图将抛出Http404异常。我们稍后讨论如何设置polls/detail.html模板,若是你想快速运行上面的例子,在模板文件中添加如下代码:
{{ poll }}
同样这也有个快捷方式。
from django.shortcuts import render, get_object_or_404
# ...
def detail(request, poll_id):
poll = get_object_or_404(Poll, pk=poll_id)
return render(request, 'polls/detail.html', {'poll': poll})
get_object_or_404()使用Django 模型作为第一个参数,还有一些任意数量的传递到模型管理器的get()的关键字参数,若对象不存在时就抛出Http404异常。
为什么不在更高层自动捕获 ObjectDoesNotExist异常, 或者由模型 API 抛出 Http404异常?
因为那样会使模型层与视图层耦合在一起。保持松耦合Django 最重要的设计目标之一。一些耦合控制在 django.shortcuts 模块中介绍。
get_list_or_404()与get_object_or_404()类似– 不过执行的是 filter() 而不是 get() 。若返回的是空列表将抛出 Http404 异常。
编写404 ( 页面未找到 ) 视图
Django 载入特定的视图来处理 404 错误,根据你的 root URLconf (仅root URLconf)中设置的handler404变量来查找视图。
一般不需要编写 404 视图。若没有设置handler404,默认使用内置的django.views.defaults.page_not_found()视图。或者在你的模板目录根目录
编写一个 500 ( 服务器错误 ) 视图
类似的,你可以在 root URLconf 中定义 handler500 变量,在服务器发生错误时调用对应的视图。视图代码产生的运行时错误会发生服务器错误。
同样,在模板根目录下创建一个500.html模板并且添加些像“出错了”之类的内容。
使用模板系统
修改polls/detail.html :
<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
模板系统使用了“变量.属性”的语法访问变量的属性值。 例如 {{ poll.question }} , 首先 Django 对 poll 对象做字典查询。 失败之后尝试属性查询 – 在本例中属性查询成功了。 如果属性查询失败将尝试列表索引查询。
在{% for %}循环中有方法调用: poll.choice_set.all即Python 代码poll.choice_set.all(),它将返回一组可迭代的Choice对象。
更多模板的信息参见 templateguide 。
移除模板中硬编码的 URLS
polls/index.html中,polls/{{ poll.id }}等是硬编码:
<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
可以在 url 配置中使用 {% url %} 模板标记来移除特定的 URL 路径依赖:
<li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>
其原理就是在 polls.urls 模块中寻找指定的URL 定义。 你知道命名为 ‘detail’ 的 URL 就如下所示那样定义的一样::
...
# 'name' 的值由 {% url %} 模板标记来引用
url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
...
如果你想将 polls 的 detail 视图的 URL 改成polls/specifics/12,那不需要在模板(或者模板集)中修改而只要在 polls/urls.py 修改:
...
# 新增 'specifics'
url(r'^specifics/(?P<poll_id>\d+)/$', views.detail, name='detail'),
...
URL命名空间:
如果多个应用都有名字为 detail的 视图,需要在 root URLconf 配置中添加命名空间。修改mysite/urls.py文件:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^polls/', include('polls.urls', namespace="polls")),
url(r'^admin/', include(admin.site.urls)),
)
修改polls/index.htm从:
<li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>
为包含命名空间的 detail 视图:
<li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>