原文地址:https://docs.djangoproject.com/en/1.4/intro/tutorial03/ php
这个教程是从教程2留下的地方开始的。咱们继续这个基于网络调查应用程序而且将关注与建立一个公共接口——“view”。 html
1、哲学 python
一个视图是你Django应用程序中(一种特别的功能和一个特别的模板)“一种”网页。好比说,在一个网络博客应用程序中,你可能有下面的视图: 正则表达式
博客页面——显示最近一些记录; 数据库
进入“细节”页面——单个记录的永久连接; express
基于年存档的页面——显示给定年份带有记录的全部月; django
基于月存档的页面——显示给定月份带有记录的全部日; 浏览器
基于日存档的页面——显示给定日期的全部记录; 安全
评论动做——处理给定记录的留言; 服务器
在咱们的调查应用程序中,咱们有下面的四个视图:
调查“索引”页面——显示最近的一些调查;
调查“细节”页面——显示一个没有结果可是带有投票的表单的调查问题;
调查“结果”页面——显示某一个调查的结果;
投票动做——处理某一个调查的某一个投票;
在Django中,每一个视图由一个简单的python函数表示。
2、设计你的URLs
写视图的第一步是设计你的URL结构。你经过建立一个叫URLconf的python模块来实现它。URLconfs是Django把给定的URL和一个给定的python代码联系起来。
当一个用户要求一个Django支持的页面,系统查看ROOT_URLCONF设置,它包含了一个python点缀语法的字符串。Django载入那个模块而后查找一个叫urlpatterns的模块层变量,它是下列各式的一列元组:
(regular expression, Python callback function [, optional dictionary])Django从第一个正则表达式开始一直往下搜索,而后一直把请求的URL和每条正则表达式比较,直到找到和他匹配的一个。
当你找到匹配的哪一个是,Django调用一个带有HttpResponse对象做为第一个参数的python回调函数,正则表达式中任何“捕获”的值都做为关键字参数,而且任意关键字参数均可以来自字典(一个元组中可选的第三个参数)。
关于更多关于HttpResponse对象的信息,请查看请求和响应对象。更多关于URLconfs,请查看URL分配器。
当你在教程1开头的地方运行django-admin.pu startproject mysite,系统在mysite/urls.py中建立了一个默认的URLconf。它也自动把你的ROOT_URLCONF设置(在setting.py中)指到那个文件:
ROOT_URLCONF = 'mysite.urls'是时候来个例子了。编辑mysite/urls.py让它看起来这样:
from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^polls/$', 'polls.views.index'), url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), url(r'^admin/', include(admin.site.urls)), )这是一个有价值的回顾。当有人从你的网站请求一个页面——好比说,“/poll/23/”,Django会载入这个python模块,由于它被指向了ROOT_URLCONF设置。它找到变量名叫urlpatterns而后按顺序穿过正则表达式。当它找打了一个匹配的正则表达式——r'^poll/(?P<poll_id>\d+)/$'——它从polls/views.py中调用一个detail()函数。最后,它像这样调用detail()函数:
detail(request=<HttpRequest object>, poll_id='23')poll_id='23'部分来自(?P<poll_id>\d+)。在一个模式周围用括号来“捕获”和模式匹配的文本,而后把它做为一个参数传递给视图函数。?P<poll_id>定义了被用来识别匹配模式的名字,\d+是匹配一列数字的正则表达式。
由于URL模式是一个正则表达式,你对它们作的一切都没有限制。所以这里没有必要增长像.php这样的URL使人讨厌的东西——除非你有一个不同凡响的幽默感,这种状况下,你能够这样作:
(r'^polls/latest\.php$', 'polls.views.index'),可是,如今不须要这样作,这看起来真的很蠢。
注意这些正则表达式不搜索GET和POST参数,或者域名。好比说,一个请求:http://www.example.com/myapp/,URLconf将会查找myapp/,在一个请求:http://example.com/myapp/?page=3,URLconf将会查找myapp/。
若是在正则表达式方面须要帮助,请查看维基百科的介绍和re模块的文档。同时,Jeffrey Friedl写的O'Reilly出版的书“掌握正则表达式”也很是精彩。
最后,一个性能注意:这些正则表达式是在你URLconf模块第一次载入的时候编译的,它们的速度是很是快的。
3、写你本身的视图
不过到目前为止咱们尚未建立本身的视图——咱们只是有URLconf。可是咱们让Django来合适的遵循URLconf。
启动Django开发网络服务器:python manage.py runserver。
如今在你的浏览器中浏览“http://localhost:8000/polls/”。你应该看到下面带有鲜艳颜色错误的页面:
ViewDoesNotExist at /polls/ Could not import polls.views.index. View does not exist in module polls.views.这个错误出现的缘由是你尚未写polls/views.py的index函数。
尝试“/polls/23/”,“/polls/23/results/”和“/polls/23/vote/”都同样的,错误消息告诉你Django没有找到视图(查找视图失败,由于你尚未写任何视图)。
显示是时候写第一个视图了。打开polls/views.py文件而后输入下面的python代码:
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the poll index.")这多是最简单的视图。在你的浏览器去看看“/polls/”你的文本。
如今让咱们增长一些更多的视图。这些视图有一点不一样,由于他们带有一个参数(记住,这是从URLconf中正则表达式捕获的传递进来的):
def detail(request, poll_id): return HttpResponse("You're looking at poll %s." % poll_id) def results(request, poll_id): return HttpResponse("You're looking at the results of poll %s." % poll_id) def vote(request, poll_id): return HttpResponse("You're voting on poll %s." % poll_id)
在你的浏览器中查看“/polls/34/”,它运行detail()方法然手显示你在URL中提供的ID。尝试“/polls/34/results/”和“/polls/34/vote/”也是同样的——它们显示结果和投票页面的占的地方。
4、写一个实际能作一些事情的视图
每一个视图都作两件事情中的一件:返回一个包含请求页面内容的HttpResponse对象,或者产生一个错误好比说Http404。剩下的就取决于你。
你的视图能够从数据库读取记录,或者不能够。它能够用一个模板系统好比说Django自带的或者第三方python模板系统,或者不能够。他用你想用的python库能够生成一个PDF文件,输出XML,建立一个动态的ZIP文件,你想的一切均可以。
全部的Django期待的是一个HttpResponse或者是一个溢出。
由于这很方便,让咱们用Django本身的数据库API,这个咱们在教程1中已经涉及到了。这儿是index()视图的一个尝试,它显示系统中按照公开时间的最近五个用逗号分开的调查问题:
from polls.models import Poll from django.http import HttpResponse def index(request): latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] output = ', '.join([p.question for p in latest_poll_list]) return HttpResponse(output)可是这里有一个问题:视图中页面的设计硬编码的。若是你想改变页面的外观,你必须编辑这个python代码。所以让咱们用Django的模板系统来设计从python中分离出来:
from django.template import Context, loader from polls.models import Poll from django.http import HttpResponse def index(request): latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] t = loader.get_template('polls/index.html') c = Context({ 'latest_poll_list': latest_poll_list, }) return HttpResponse(t.render(c))这些代码载入一个叫“polls/index.html”的模板而后把它传递给上下文。上下文是一个把模板变量名字映射到python对象的字典。
从新载入这个页面,如今你会看到一个错误:
TemplateDoesNotExist at /polls/ polls/index.html啊哈,到目前为止尚未模板。首先在你系统的某个Django能够接触到的地方建立一个目录(无论你运行的是什么服务器,Django都运行同样的)。可是不要把它放在你的根文档下面。为安全期间,你不能让他们公开。而后编辑settings.py中的TEMPLATE_DIRS来高速Django在哪能够找到模板——就像在教程2“低昂之管理页面的外观和感受”的部分。
当你已经作完了这些,在你的模板目录下建立一个polls目录。在这个目录里面,建立一个叫index.html。注意咱们的loader.get_template('polls/index.html')代码从上面映射到系统的“[template_directory]/polls/index.html”。
把下面的代码放到模板里:
{% if latest_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 %}在浏览器中载入页面,你能够看到一个包含来自教程1的“What's up”调查的布告栏列表的容器。这个连接指向调查的详细页面。
5、一个快捷方式:render_to_response()
用提供模板的结果载入一个模板,填写上下文,返回一个HttpResponse对象,这些都是很常见的习语。Django提供一个快捷方式。这是咱们的所有重写的index()的视图:
from django.shortcuts import render_to_response from polls.models import Poll def index(request): latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})注意咱们一旦在全部视图中这样作时候,咱们就再也不须要载入loader,Context和HttpResponse。
render_to_response()函数带有一个模板名做为它的第一个参数和一个做为第二个可选参数的字典。它返回一个提供给定上下文的给定模板的HttpResponse对象。
6、产生404错误
如今,咱们来处理调查细节的视图——显示给定调查的问题。下面是视图:
from django.http import Http404 # ... def detail(request, poll_id): try: p = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404 return render_to_response('polls/detail.html', {'poll': p})这里新的内容:若是你请求一个不存的ID,视图产生Http404溢出。
咱们后面讨论你能够在polls/detail.html放什么,可是若是你想快点让例子运行起来,只要:
{{ poll }}就能正式运行了。
7、一个快捷方式:get_object_or_404()
用get(),视图不存在时产生一个Http404错误时很常见的习语。Django提供一个快捷方式。下面是重写的detail()视图:
from django.shortcuts import render_to_response, get_object_or_404 # ... def detail(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) return render_to_response('polls/detail.html', {'poll': p})get_object_or_404()函数把Django的模型做为它的第一个参数和一个任意数量的关键字参数,这些参数是传到模块的get()函数。若是视图不存在就产生一个Http404错误。
(哲学:为何咱们用一个get_object_or_404()帮助函数而不是在更高的层次自动捕获ObjectDoesNotExit溢出或者让模型的API产生Http404而不是ObjectDoesNotExit?由于那样作会耦合模型层和视图层。Django的一个最重要的设计就是实现松耦合。)
这里有一个get_list_or_404()函数,他就像和get_object_or_404()同样工做——除了使用filter()而不是get()。当列表是空的时候就产生Http404错误。
8、写一个404(页面没找到)视图
当你从一个视图产生Http404错误的时候,Django会载入一个致力于处理404错误的特殊视图。它经过在你的根URLconf(只在你的根URLconf下,无论在其余什么地方设置handler404都无效)查找变量handler404,它是一个python点缀语法的字符串——通常URLconf回调函数用相同的格式。一个404视图自己没有什么特别的:它只是一个普通的视图。
通常来讲你不须要烦恼写404视图。若是你没有设置handler404,默认状况下使用内建的django.views.defaults.page_not_found()。这种状况下,你任然有一件事要作:在根模板目录建立一个404.html模板。默认的404视图将会调用适用于全部404错误的模板。若是DEBUG被设置成False(在你的设置文件中),而且你没有建立一个404.html文件,就会产生一个Http500。所以记住建立一个404.html。
关于404视图耦合更多的东西:
若是DEBUG被设置成True(在你的设置文件中),你的404视图将永远不会被用到(所以404.html模板永不被提供)由于此时显示的是错误的追溯。
404视图被称为Django在检查URLconf中正则表达式是没有找到匹配。
9、写一个500(服务器错误)视图
相似地,你的根URLconf能够定义一个handler500,防止服务器错误它指向一个视图。当你视图代码有错误时,服务器错误也可能出现。
10、使用模板系统
回到咱们调查应用程序的detail()视图。鉴于上下文变量poll,下面是咱们“polls/detail.html”模板可能看起来的样子:
<h1>{{ poll.question }}</h1> <ul> {% for choice in poll.choice_set.all %} <li>{{ choice.choice }}</li> {% endfor %} </ul>模板系统用点查看语法来接触变量的属性。在{{ poll.queston }}的例子中,第一个Django在poll对象中查找字典。若是失败的话,它尝试属性查找——在这种状况下,它有效的。若是属性查找也失败了,它将尝试列表索引查找。
在{% for %}循环中会发生方法调用:poll.choice_set.all被翻译成python代码poll.choice_set.all(),它返回Choice对象的迭代而且在{% for %}标签中适合使用。更多关于模板的消息请查看模板指导。
11、简化URLconfs
花点时间来处理视图和模板系统。就像你编辑URLconf同样,你可能注意到这里有点冗余:
urlpatterns = patterns('', url(r'^polls/$', 'polls.views.index'), url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), )也就是说,每一个回调都在polls.views中。
由于这是一个常见的状况,URLconf框架为常见的前缀提供一个快捷方式。你能够分析出常见的前缀而且增长它们做为patterns()的第一个参数,就像下面:
urlpatterns = patterns('polls.views', url(r'^polls/$', 'index'), url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), )他在功能上可以前的格式是彻底同样的,它只是作了点整理。
既然你一般不想一个程序的前缀应用到URLconf的每一个回调中,你能够连接多个patterns()。你mysite/urls.py的所有如今应该看起来是这样的:
from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('polls.views', url(r'^polls/$', 'index'), url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ) urlpatterns += patterns('', url(r'^admin/', include(admin.site.urls)), )12、URLconfs的去耦合
咱们学习他的时候应该花点时间把咱们Django项目配置的调查程序URL去耦合。Django的程序是插件式的——也就是说,每一个特别地程序应该能够用最小的大惊小怪应用到另外一个Django的安装。
多亏了python manage.py startapp建立的严格目录结构,咱们的投票程序在这个时候是至关去耦合化的。可是它的一部分是和Django设置耦合的:URLconf。
咱们已经在mysite/urls.py里编辑,可是一个程序的URL设计只针对一个应用程序,而不是Django的安装——所以让咱们在应用程序目录里把URLs删掉。
把mysite/urls.py拷贝到polls/urls.py,而后改变mysite/urls.py去删除针对调查程序的URLs而后插入一个include(),让它是这样的:
from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^polls/', include('polls.urls')), url(r'^admin/', include(admin.site.urls)), )include()只是简单的参照另一个URLconf。注意正则表达式没有$(匹配结束字符)可是有一个斜杠。当Django面对include()时,它砍掉在这个点上匹配的URL而后把剩下的字符串传给包含的URLconf进行更多的处理。
当一个用户访问系统的“/polls/34/”会发生下面的事情:
Django会找到一个匹配的'^polls/';
而后Django会去掉匹配的文本(“polls/”)而后把剩下的文本——“34”——传递给'polls.urls'URLconf进行更多的处理;
既然咱们已经去耦合了,咱们须要删除每行开头的“polls/”,同时也要删除注册管理站点的那一行。你的poll/urls.py文件如今应该看起来是这样的:
from django.conf.urls import patterns, url urlpatterns = patterns('polls.views', url(r'^$', 'index'), url(r'^(?P<poll_id>\d+)/$', 'detail'), url(r'^(?P<poll_id>\d+)/results/$', 'results'), url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), )
include()后面的想法和URLconf去耦合是为了是让它容易变成插件和运行的URLs。 调查调查已经在URLconf中,他们能够被放置在“/polls/”下,或者“/fun_polls/”下,或者“/content/polls/”下,或者任何根路径,程序一样能工做。
全部的调查程序关心的是相对路径,而不是绝对路径。
当你对写视图感到合适的话,读教程4学习更多关于处理通用视图。
教程3结束!