- 浏览: 2677826 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
80后的童年2:
深入浅出MongoDB应用实战开发网盘地址:https://p ...
MongoDB入门教程 -
shliujing:
楼主在不是精通java和php的前提下,请不要妄下结论。
PHP、CakePHP哪凉快哪呆着去 -
安静听歌:
希望可以一给一点点注释
MySQL存储过程之代码块、条件控制、迭代 -
qq287767957:
PHP是全宇宙最强的语言!
PHP、CakePHP哪凉快哪呆着去 -
rryymmoK:
深入浅出MongoDB应用实战开发百度网盘下载:链接:http ...
MongoDB入门教程
The Django Book:第3章 动态Web页面基础
revised by xin_wang
上一章我们解释了怎样开始一个Django项目和运行Django服务器
当然了,这个站点实际上什么也没有做------除了显示了"It worked"这条信息以外。
这一章我们介绍怎样使用Django创建动态网页
你的第一个视图:动态内容
让我们创建一个显示当前日期和时间的Web页面来作为你的第一个目标
这是一个动态Web页面的例子,因为页面内容根据计算当前时间而变化
这个例子不需要数据库和任何用户输入,只是输出服务器内部时钟
我们将写一个视图方法,它只是一个Python方法,接受Web请求并返回Web应答
这个应答可以是HTML内容、重定向、404错误、XML文档、图像等等
视图本身包含任意必要的逻辑来返回应答
在这里视图作为HTML文档返回当前日期和时间
让我们来看看代码
1,首先,我们从django.http模块import HttpResponse类
2,然后,我们从Python标准库import datetime模块
datetime模块包含一些处理日期和时间的类和方法,并且包含一个返回当前时间的方法
3,然后,我们定义current_datetime方法
这是一个视图方法,它使用一个HttpRequest对象作为它的第一个参数
每个视图方法都使用HttpRequest对象作为自己的第一个参数
在这个方法里,我们把这个参数叫做request
Django并不关心视图方法的名字,我们也不必遵循某种特定的命名方式供Django鉴别。我们以current_datetime命名这个方法
纯粹是因为它正好可以明确的表达方法的意图,你可以任意地命名view方法,current_datetime清楚的表明了它会做什么事情
一会我们会解释Django怎样找到这个方法
4,该方法的第一行代码计算当前日期和时间,并存储在本地变量now中
5,该方法的第二行代码使用Python的格式化string能力构建了一个HTML应答
string里面的%s是一个占位符,string后面的百分号表示使用now变量的值代替%s
(给html纯化论者们:我们没有写DOCTYPE申明,没有<head>标签,等等等等,我们只是尽量让这个页面简洁明了。)
6,最后,视图返回一个包含生成的HTML的HttpResponse对象
每个视图方法都会返回一个HttpResponse对象,例外的情况我们后面会解释
你的第一个URL配置
这个视图方法返回了一个包含当前日期和时间的HTML页面
但是这些代码应该放在哪?怎样告诉Django使用这些代码呢?
第一个问题的答案是:你可以把view的代码放在任何位置,只要它是在你的Python PATH下,没有任何其他的要求----没有"魔术"。
我们将这些代码保存在views.py里面,并将views.py放在mysite目录下
Python PATH是一个你系统的目录列表,当你使用Python import语句时Python会查看这些目录
例如你的Python PATH设置成['', '/usr/lib/python2.4/site-packages', '/home/mycode']
如果你执行代码from foo import bar,Python将首先在当前目录下查找叫foo.py的模块
第一个Python PATH为空string,这表示当前目录
如果找不到foo.py,Python将尝试查找/usr/lib/python2.4/site-packages/foo.py
最后,如果foo.py还是找不到,Python将报ImportError
如果你有兴趣查看Python PATH,进入Python交互环境并输入import sys和print sys.path
一般来说你不必担心设置Python PATH,Python和Django会暗中自动为你做这些事情
如果你实在好奇,设置Python PATH是manage.py的一个工作
我们怎么告诉Django使用这些视图代码?答案是URL配置
URLConf就像是一张Django web站点的内容表格。基本上,这个配置是一个URL模式和对应的view函数的映射,这些函数会在请求某个符合特定模式的URL时被调用。
URLconf就是告诉Django,"对于这个URL,调用这些代码,对于那个URL,调用那些代码..."
URL配置就像是你的Django项目的目录
基本上,它是URL模式和URL模式调用的视图方法的映射
django-admin.py startproject会自动生成一个URL配置文件urls.py,默认情况下它是这样的:
让我们来看看这些代码
1,第一行import django.conf.urls.defaults模块的所有对象,包括一个叫patterns的方法
2,第二行调用patterns()方法并将接过保存到urlpatterns变量,patterns()方法只传了一个空string作为参数
其它行被注释掉了
这里主要看的就是变量urlpatterns,它定义了URL和处理URL的代码的映射
默认情况下所有的URL配置被注释掉了,这意味着你的Django项目是空的,这让Django得知显示“It worked!”页面
如果你的URL配置是空的,Django假设你刚开始一个新的项目,这样就显示这条信息
让我们编辑urls.py来暴露current_datetime视图:
我们做了两处改动。首先,我们从mysite/views.py模块import current_datetime视图
该模块在Python的import语法中被转换成mysite.views
然后我们增加一行(r'^now/$', current_datetime),它指向一个URL模式
这是一个Python元组,第一个元素是一个正则表达式,第一个是视图方法
这样,我们就告知Django对URL /now/的请求应该被current_datetime视图方法处理
注意几个地方:
1,在例子中,我们把视图方法current_datetime当成对象传递而不是调用这个方法
这是Python及其它动态语言的特性,函数是第一类对象,可以像其它变量一样传递,cool吧?
2,不必在'^now/$'前面增加斜线来匹配/now/,Django自动在每个表达式前面添加斜线
3,'^'和'$'符号很重要,前者表示“匹配string的开始的模式”,后者表示“匹配string结束的模式”
这个例子很好的解释了概念问题,如果我们使用模式'^now/',则/now/,/now/foo,/now/bar都将匹配
如果我们使用模式'now/$'则/now/,/foo/bar/now/等也将匹配
所以我们使用'^now/$',则不多不少只有/now/匹配
现在测试一下我们对URLConf的修改。运行python manage.py runserver来启动Django的开发服务器
(如果让它一直运行也没有问题,服务器会自动探测Python代码的修改,在必要的时候重新载入,所以没有必要一修改就重起)
浏览器访问http://127.0.0.1:8000/now/测试一下
万岁!你已经开发了你的第一个Django-powered Web页面
Django怎样处理请求
Django怎样处理Web请求?让我们来看看事实真相
1,命令python manage.py runserver寻找settings.py,这个文件包含了这个Django实例的所有配置选项
最重要的设置是ROOT_URLCONF,它告诉Django使用哪个Python模块作为当前站点的URL配置
2,当一个请求进来如/now/,Django载入URL配置,然后按顺序检查每个URL模式直到找到一个匹配的URL请求模式
然后Django调用那个模式匹配的方法,并传递一个HttpRequest对象作为第一个参数
3,视图方法负责返回一个HttpResponse对象
这样你就了解了Django-powerd页面的基础,它很简单,只需写视图方法和通过URL配置映射到URL
URL配置和松耦合
现在是指出URL配置和Django后面的哲学的良好时机:松耦合原则
松耦合是具有使得部分模块可替换的价值的软件开发方法
如果两个模块是松耦合的,那么对一个模块做改动不会或很少对另一个有影响
Django的URL配置是这个原则的很好的例子
在Django Web程序中,URL定义和视图方法是松耦合的,开发人员可以替换其中一个而不会对另一个产生影响
对比之下,其他的web开发平台耦合了URL和程序,例如在basic php中,应用的URL取决于代码在文件系统中的位置,
在CherryPy框架中,URL和应用中的方法名称是相对应的。这些方式看来非常方便,但是长远来看会造成难以管理的问题
举例来说,考虑我们刚刚的那个显示当前时间的函数。如果我们想改变这个应用的URL,比如从/now/变成/currenttime/
我们可以对URLconf做一个非常快捷的修改,不用担心隐藏在这个URL之后的函数实现。类似的,如果我们想修改view函数
修改它的逻辑,我们用不着影响URL就可以做到。
更进一步,如果我们想把这个当前时间的方法暴露到多个URL上,我们也可以通过修改URLconf轻易完成,而无需影响view的代码。
404错误
在我们当前的URLconf里面只有一个处理/now/的URL模式。如果我们请求一个不同的URL会发生什么呢?
当访问一个没有在URLconf里面定义过的URL时,你将看到一个"Page not found"的信息,因为这个URL还没有定义在URLconf里。
这个页面的用途其实不仅仅是显示404错误信息:它精确的告诉我们Django使用了哪一个URLconf,以及这个配置里的每一个URL匹配模式。
通过这个页面我们可以轻易的得知为什么请求的URL抛出了404错误。
当然了,这些信息的初衷是为了方便web开发者。如果这是一个实际的internet站点,我们不希望这些信息被泄露出去。
出于这个原因,这个"Page not found"页面只显示在debug模式下。
你的第二个视图:动态URL
第一个视图例子中,页面内容当前日期和时间是动态的,但是URL("/now/")是静态的
大多数动态Web程序中,URL包含了影响输出页面的参数
下面的例子中我们使用一个数字来显示为了几小时的日期和时间
如/now/plus1hour/显示未来1小时的时间,/now/plus3hour/显示未来3小时的时间
先修改URL配置:
显然这样的模式有缺陷,不仅会产生大量的视图方法,还将程序局限在预先定义的小时范围内
如果我们想显示5小时后的时间,我们还得再添加一行
所以我们应该在这里做出一点抽象
关于良好的URL
如果你使用过PHP或Java,你可能会说“让我们使用一个查询参数”,类似于像/now/plus?hours=3
你也可以使用Django这样做,但是Django的一个核心哲学是,URL应该是优雅的
/now/plus3hours/更干净、更简单、更可读、更朗朗上口
良好的URL是Web程序质量的一个显示
Django的URL配置系统提供容易配置的良好的URL定义
URL模式通配符
继续我们的例子,让我们在URL模式中添加一个通配符
上面提到,URL模式是一个正则表达式,这里我们可以使用\d+来匹配1个或多个数字:
这个URL模式可以匹配任何URL,例如/now/plus2hours/,/now/plus25hours/,甚至/now/plus100000000000hours/
让我们限制最多99小时,即我们只允许1个或2个数字,在正则表达式里就是\d{1,2}:
(r'^now/plus\d{1,2}hours/$', hours_ahead),
当我们构建web程序的时候,考虑可能出现的不合常理的输入, 并且决定是否处理这些输入是非常重要的。
我们在这里限制时间的偏移量<=99小时。顺便啰嗦一句,Outlandishness Curtailers是个超级棒的乐队。
正则表达式是一个在文本里面指定模式的简洁方式
Django的URL配置允许任意的正则表达式来提供强大的URL匹配能力,下面是一些常用的模式:
更多的正则表达式信息请查看Appendix 9,正则表达式
好了,我们已经在URL里设计了一个通配符,但我们需要把信息传递给视图方法
这样我们才能使用一个单独的视图方法来处理任意的小时参数
我们把我们在URL模式里希望保存的数据用括号括起来,即把\d{1,2}括起来
(r'^now/plus(\d{1,2})hours/$', hours_ahead),
如果你熟悉正则表达式,你会觉得非常亲切:我们正是在使用括号从匹配的文本中获得我们想要的数据。
最终的URL配置如下:
下面我们定义hours_ahead方法:
告诫:关于编码的顺序
在这个例子里面,我们先定义了URL模式,然后才开始撰写view代码,但是在前一个例子里,编码的顺序正好相反。那么哪一种方式更好呢?
当然,每一个开发人员都有不一样的习惯。
如果你是一个大局观很好的人,一次性就定义好所有的URL模式,然后再来实现view的代码,这是非常不错的。
这种方式能够展现一个非常清晰的to-do list,因为它从根本上定义了将要实现的view函数所需的参数。
如果你是一个有着自底向上的习惯的程序员,你也许更愿意写一个view,然后把它和某一个URL模式绑定起来。这样做也不错。
两种方式当然都是正确的,使用哪一个取决于哪一种更加符合你思考的模式。
我们还是一次一行的解读这些代码:
跟我们在current_datetime里所做的一样,我们导入了django.http.HttpResponse和datetime模块
view函数hours_ahead接受两个参数:request和offset。
request是一个HttpRequest对象,和在current_datetime中一样。我们要重申一点:每一个view函数的第一个参数总是HttpRequest对象。
offset是一个string,它的值是通过URL模式里的那一对括号从请求的URL中得到的。比如请求的URL是/now/plus3hours/
offset的值就是一个string‘3’。请注意从URL中得到的值始终是string而不是integer,即使这个string是由纯数字构成的。
我们把这个变量命名为offset,但是你可以用任何合法的Python变量名来命名它。变量的名字并不重要,但是必须是view函数的第二个参数。
在函数里我们做的第一件事就是调用int(),把offset转换成整形。
如果一个值不能被转换成为一个整型数(像字符串'foo'), Python将会抛出ValueError。
但是我们对此并不担心,因为我们可以肯定offset一定可以被转换,正则表达式\d{1,2}一定会从URL中获得数字。
这也从另一个侧面证明了URLconf的优雅:它相当清楚地提供了一个对输入的校验。
程序的下一行揭示了我们对offset做类型转换的原因,这行代码计算了当前的时间加上一个时间偏移量,这个偏移量的值就是offset
保存计算的结果在变量dt.datetime.timedelta函数需要的输入参数就是整型。
下一行我们构造一个html的输出,和在current_datetime函数中类似。
最后,和current_datetime函数一样,我们返回一个HttpResponse对象。
好了,我们访问http://127.0.0.1:8000/now/plus3hours/可以验证它工作了
然后我们试试http://127.0.0.1:8000/now/plus100hours/,Django显示“Page not found”错误
http://127.0.0.1:8000/plushours/也会显示404错误,因为我们只接受1个或2个数字的参数
Django良好的出错页面
我们将offset = int(offset)注释掉
# offset = int(offset)
然后重新访问/now/plus3hours,你将看到一个很多信息的出错页面,包括TypeError信息在最上面:
“unsupported type for timedelta hours component: str”
发生了什么?
datetime.timedelta函数预期hours参数为integer类型,但我们注释掉了把offset转化为integer的代码
这导致datetime.timedelta产生TypeError,只是典型的每个程序员容易出现的小bug
中一些需要注意的地方:
1,页面的顶端显示的是关于异常的主要信息:异常的类型,异常的参数,导致异常的文件和行数
2,接下来页面显示完整的异常的Python traceback,在stack的每个frame里Django都显示了文件名、方法名、行数和该行代码
点击暗灰色的代码,你可以看到出错行前后的几行代码,让你得到上下文
点击“Local vars”可以看到所有的本地变量的列表,变量值,出错点等,这个debug信息是很有价值的
3,点击在“Traceback”下面的“Switch to copy-and-paste view”将切换到可以很容易复制粘贴的版本
当你想同他人分享异常信息或得到技术支持时(Django IRC聊天室或者Django用户邮件列表)可以很好的利用它
4,“Request information”包括大量的产生错误的Web请求的信息,GET和POST信息,cookie值和meta信息如CGI头部等
下面的“Settings”部分列出了当前Django安装的所有设置信息,后面我们会慢慢解释这些
Django错误页面在模板语法错误等情况下会显示更丰富的信息,现在去掉注释offset=int(offset)
你是那种喜欢用print语句debug 的程序员吗?使用Django错误页面就可以做到这点,不需要print语句
你可以临时插入assert False来触发错误页面,后面我们会解释更高级的debug方法
很显然大部分这些错误信息是敏感的,它暴露了你的Python代码和Django配置的五脏六腑
把这些信息显示到网上是愚蠢的,心怀恶意的人可能会在你的网站里面做肮脏的事情
无论如何,后面我们会提到怎样去除debug模式
练习
这里是一些巩固本章知识的练习,我们在这里介绍了一些新的技巧
1,创建另一个视图hours_behind,类似于hours_ahead,只不过显示过去的时间偏移量
这个视图应该绑定到/now/minusXhours/,这里X是偏移量小时数
2,一旦你做完练习1,一个良好的程序员会发现hours_ahead和hours_behind非常类似,这显得多余了
把这两个方法合并到单独的一个方法hour_offset,URL还是保持/now/minusXhours/和/now/plusXhours/不变
别忘了根据偏移量是正还是负来改变HTML代码,“In X hour(s)”或者“X hour(s) ago”
3,让我们更专业一点,允许/now/plus1hour/和/now/plus2hours/,但是不允许/now/plus1hours/和/now/plus2hour/
4,在HTML的显示里,如果偏移量是个位数,使用hour,否则使用hours
答案
1,hours_behind视图:
URL模式:
2,hour_offset视图:
URL模式:
3,URL模式:
其中“|”表示“or”,上面的模式表示匹配模式[2-9]或者\d\d
即匹配一个2到9的数字或者匹配两个数字
4,hour_offset视图:
难道不能把展现层代码从Python代码里分离出去吗?呵呵,这预示着......
这样写似乎已经不行了,似乎不能以函数对象作为参数了
AttributeError at /now/
'function' object has no attribute 'rindex'
Request Method: GET
Request URL: http://127.0.0.1:8000/now/
Exception Type: AttributeError
Exception Value: 'function' object has no attribute 'rindex'
Exception Location: E:\TRAC\PYTHON23\lib\site-packages\django-0.95.1-py2.3.egg\django\core\urlresolvers.py in get_mod_func, line 23
revised by xin_wang
上一章我们解释了怎样开始一个Django项目和运行Django服务器
当然了,这个站点实际上什么也没有做------除了显示了"It worked"这条信息以外。
这一章我们介绍怎样使用Django创建动态网页
你的第一个视图:动态内容
让我们创建一个显示当前日期和时间的Web页面来作为你的第一个目标
这是一个动态Web页面的例子,因为页面内容根据计算当前时间而变化
这个例子不需要数据库和任何用户输入,只是输出服务器内部时钟
我们将写一个视图方法,它只是一个Python方法,接受Web请求并返回Web应答
这个应答可以是HTML内容、重定向、404错误、XML文档、图像等等
视图本身包含任意必要的逻辑来返回应答
在这里视图作为HTML文档返回当前日期和时间
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html)
让我们来看看代码
1,首先,我们从django.http模块import HttpResponse类
2,然后,我们从Python标准库import datetime模块
datetime模块包含一些处理日期和时间的类和方法,并且包含一个返回当前时间的方法
3,然后,我们定义current_datetime方法
这是一个视图方法,它使用一个HttpRequest对象作为它的第一个参数
每个视图方法都使用HttpRequest对象作为自己的第一个参数
在这个方法里,我们把这个参数叫做request
Django并不关心视图方法的名字,我们也不必遵循某种特定的命名方式供Django鉴别。我们以current_datetime命名这个方法
纯粹是因为它正好可以明确的表达方法的意图,你可以任意地命名view方法,current_datetime清楚的表明了它会做什么事情
一会我们会解释Django怎样找到这个方法
4,该方法的第一行代码计算当前日期和时间,并存储在本地变量now中
5,该方法的第二行代码使用Python的格式化string能力构建了一个HTML应答
string里面的%s是一个占位符,string后面的百分号表示使用now变量的值代替%s
(给html纯化论者们:我们没有写DOCTYPE申明,没有<head>标签,等等等等,我们只是尽量让这个页面简洁明了。)
6,最后,视图返回一个包含生成的HTML的HttpResponse对象
每个视图方法都会返回一个HttpResponse对象,例外的情况我们后面会解释
你的第一个URL配置
这个视图方法返回了一个包含当前日期和时间的HTML页面
但是这些代码应该放在哪?怎样告诉Django使用这些代码呢?
第一个问题的答案是:你可以把view的代码放在任何位置,只要它是在你的Python PATH下,没有任何其他的要求----没有"魔术"。
我们将这些代码保存在views.py里面,并将views.py放在mysite目录下
Python PATH是一个你系统的目录列表,当你使用Python import语句时Python会查看这些目录
例如你的Python PATH设置成['', '/usr/lib/python2.4/site-packages', '/home/mycode']
如果你执行代码from foo import bar,Python将首先在当前目录下查找叫foo.py的模块
第一个Python PATH为空string,这表示当前目录
如果找不到foo.py,Python将尝试查找/usr/lib/python2.4/site-packages/foo.py
最后,如果foo.py还是找不到,Python将报ImportError
如果你有兴趣查看Python PATH,进入Python交互环境并输入import sys和print sys.path
一般来说你不必担心设置Python PATH,Python和Django会暗中自动为你做这些事情
如果你实在好奇,设置Python PATH是manage.py的一个工作
我们怎么告诉Django使用这些视图代码?答案是URL配置
URLConf就像是一张Django web站点的内容表格。基本上,这个配置是一个URL模式和对应的view函数的映射,这些函数会在请求某个符合特定模式的URL时被调用。
URLconf就是告诉Django,"对于这个URL,调用这些代码,对于那个URL,调用那些代码..."
URL配置就像是你的Django项目的目录
基本上,它是URL模式和URL模式调用的视图方法的映射
django-admin.py startproject会自动生成一个URL配置文件urls.py,默认情况下它是这样的:
from django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^mysite/', include('mysite.apps.foo.urls.foo')), # Uncomment this for admin: # (r'^admin/', include('django.contrib.admin.urls')), )
让我们来看看这些代码
1,第一行import django.conf.urls.defaults模块的所有对象,包括一个叫patterns的方法
2,第二行调用patterns()方法并将接过保存到urlpatterns变量,patterns()方法只传了一个空string作为参数
其它行被注释掉了
这里主要看的就是变量urlpatterns,它定义了URL和处理URL的代码的映射
默认情况下所有的URL配置被注释掉了,这意味着你的Django项目是空的,这让Django得知显示“It worked!”页面
如果你的URL配置是空的,Django假设你刚开始一个新的项目,这样就显示这条信息
让我们编辑urls.py来暴露current_datetime视图:
from django.conf.urls.defaults import * form mysite.views import current_datetime urlpatterns = patterns('', (r'^now/$', current_datetime), )
我们做了两处改动。首先,我们从mysite/views.py模块import current_datetime视图
该模块在Python的import语法中被转换成mysite.views
然后我们增加一行(r'^now/$', current_datetime),它指向一个URL模式
这是一个Python元组,第一个元素是一个正则表达式,第一个是视图方法
这样,我们就告知Django对URL /now/的请求应该被current_datetime视图方法处理
注意几个地方:
1,在例子中,我们把视图方法current_datetime当成对象传递而不是调用这个方法
这是Python及其它动态语言的特性,函数是第一类对象,可以像其它变量一样传递,cool吧?
2,不必在'^now/$'前面增加斜线来匹配/now/,Django自动在每个表达式前面添加斜线
3,'^'和'$'符号很重要,前者表示“匹配string的开始的模式”,后者表示“匹配string结束的模式”
这个例子很好的解释了概念问题,如果我们使用模式'^now/',则/now/,/now/foo,/now/bar都将匹配
如果我们使用模式'now/$'则/now/,/foo/bar/now/等也将匹配
所以我们使用'^now/$',则不多不少只有/now/匹配
现在测试一下我们对URLConf的修改。运行python manage.py runserver来启动Django的开发服务器
(如果让它一直运行也没有问题,服务器会自动探测Python代码的修改,在必要的时候重新载入,所以没有必要一修改就重起)
浏览器访问http://127.0.0.1:8000/now/测试一下
万岁!你已经开发了你的第一个Django-powered Web页面
Django怎样处理请求
Django怎样处理Web请求?让我们来看看事实真相
1,命令python manage.py runserver寻找settings.py,这个文件包含了这个Django实例的所有配置选项
最重要的设置是ROOT_URLCONF,它告诉Django使用哪个Python模块作为当前站点的URL配置
2,当一个请求进来如/now/,Django载入URL配置,然后按顺序检查每个URL模式直到找到一个匹配的URL请求模式
然后Django调用那个模式匹配的方法,并传递一个HttpRequest对象作为第一个参数
3,视图方法负责返回一个HttpResponse对象
这样你就了解了Django-powerd页面的基础,它很简单,只需写视图方法和通过URL配置映射到URL
URL配置和松耦合
现在是指出URL配置和Django后面的哲学的良好时机:松耦合原则
松耦合是具有使得部分模块可替换的价值的软件开发方法
如果两个模块是松耦合的,那么对一个模块做改动不会或很少对另一个有影响
Django的URL配置是这个原则的很好的例子
在Django Web程序中,URL定义和视图方法是松耦合的,开发人员可以替换其中一个而不会对另一个产生影响
对比之下,其他的web开发平台耦合了URL和程序,例如在basic php中,应用的URL取决于代码在文件系统中的位置,
在CherryPy框架中,URL和应用中的方法名称是相对应的。这些方式看来非常方便,但是长远来看会造成难以管理的问题
举例来说,考虑我们刚刚的那个显示当前时间的函数。如果我们想改变这个应用的URL,比如从/now/变成/currenttime/
我们可以对URLconf做一个非常快捷的修改,不用担心隐藏在这个URL之后的函数实现。类似的,如果我们想修改view函数
修改它的逻辑,我们用不着影响URL就可以做到。
更进一步,如果我们想把这个当前时间的方法暴露到多个URL上,我们也可以通过修改URLconf轻易完成,而无需影响view的代码。
404错误
在我们当前的URLconf里面只有一个处理/now/的URL模式。如果我们请求一个不同的URL会发生什么呢?
当访问一个没有在URLconf里面定义过的URL时,你将看到一个"Page not found"的信息,因为这个URL还没有定义在URLconf里。
这个页面的用途其实不仅仅是显示404错误信息:它精确的告诉我们Django使用了哪一个URLconf,以及这个配置里的每一个URL匹配模式。
通过这个页面我们可以轻易的得知为什么请求的URL抛出了404错误。
当然了,这些信息的初衷是为了方便web开发者。如果这是一个实际的internet站点,我们不希望这些信息被泄露出去。
出于这个原因,这个"Page not found"页面只显示在debug模式下。
你的第二个视图:动态URL
第一个视图例子中,页面内容当前日期和时间是动态的,但是URL("/now/")是静态的
大多数动态Web程序中,URL包含了影响输出页面的参数
下面的例子中我们使用一个数字来显示为了几小时的日期和时间
如/now/plus1hour/显示未来1小时的时间,/now/plus3hour/显示未来3小时的时间
先修改URL配置:
urlpatterns = patterns('', (r'^now/$', current_datetime), (r'^now/plus1hour/$', one_hour_ahead), (r'^now/plus2hour/$', two_hours_ahead), (r'^now/plus3hour/$', three_hours_ahead), {r'^now/plus4hour/$', four_hours_ahead), )
显然这样的模式有缺陷,不仅会产生大量的视图方法,还将程序局限在预先定义的小时范围内
如果我们想显示5小时后的时间,我们还得再添加一行
所以我们应该在这里做出一点抽象
关于良好的URL
如果你使用过PHP或Java,你可能会说“让我们使用一个查询参数”,类似于像/now/plus?hours=3
你也可以使用Django这样做,但是Django的一个核心哲学是,URL应该是优雅的
/now/plus3hours/更干净、更简单、更可读、更朗朗上口
良好的URL是Web程序质量的一个显示
Django的URL配置系统提供容易配置的良好的URL定义
URL模式通配符
继续我们的例子,让我们在URL模式中添加一个通配符
上面提到,URL模式是一个正则表达式,这里我们可以使用\d+来匹配1个或多个数字:
from django.conf.urls.defaults import * from mysite.views import corruent_datetime, hours_ahead urlpatterns = patterns('', (r'^now/$', current_datetime), (r'^now/plus\d+hours/$', hours_ahead), )
这个URL模式可以匹配任何URL,例如/now/plus2hours/,/now/plus25hours/,甚至/now/plus100000000000hours/
让我们限制最多99小时,即我们只允许1个或2个数字,在正则表达式里就是\d{1,2}:
(r'^now/plus\d{1,2}hours/$', hours_ahead),
当我们构建web程序的时候,考虑可能出现的不合常理的输入, 并且决定是否处理这些输入是非常重要的。
我们在这里限制时间的偏移量<=99小时。顺便啰嗦一句,Outlandishness Curtailers是个超级棒的乐队。
正则表达式是一个在文本里面指定模式的简洁方式
Django的URL配置允许任意的正则表达式来提供强大的URL匹配能力,下面是一些常用的模式:
Symbol Matches .(dot) 任意字符 \d 任意数字 [A-Z] 从A到Z的任意字符(大写) [a-z] 从a到z的任意字符(小写) [A-Za-z] 从a到z的任意字符(大小写不敏感) [^/]+ 任意字符直到一个前斜线(不包含斜线本身) + 一个或多个前面的字符 ? 零个或多个前面的字符 {1,3} 1个到3个之间前面的字符(包括1和3)
更多的正则表达式信息请查看Appendix 9,正则表达式
好了,我们已经在URL里设计了一个通配符,但我们需要把信息传递给视图方法
这样我们才能使用一个单独的视图方法来处理任意的小时参数
我们把我们在URL模式里希望保存的数据用括号括起来,即把\d{1,2}括起来
(r'^now/plus(\d{1,2})hours/$', hours_ahead),
如果你熟悉正则表达式,你会觉得非常亲切:我们正是在使用括号从匹配的文本中获得我们想要的数据。
最终的URL配置如下:
from django.conf.urls.defautls import * form mysite.views import current_datetime, hours_ahead urlpatterns = patterns('', (r'^now/$', current_datetime), (r'^now/plus(\d{1,2})hours/$', hours_ahead), )
下面我们定义hours_ahead方法:
告诫:关于编码的顺序
在这个例子里面,我们先定义了URL模式,然后才开始撰写view代码,但是在前一个例子里,编码的顺序正好相反。那么哪一种方式更好呢?
当然,每一个开发人员都有不一样的习惯。
如果你是一个大局观很好的人,一次性就定义好所有的URL模式,然后再来实现view的代码,这是非常不错的。
这种方式能够展现一个非常清晰的to-do list,因为它从根本上定义了将要实现的view函数所需的参数。
如果你是一个有着自底向上的习惯的程序员,你也许更愿意写一个view,然后把它和某一个URL模式绑定起来。这样做也不错。
两种方式当然都是正确的,使用哪一个取决于哪一种更加符合你思考的模式。
from django.http import HttpResponse import datetime def hours_ahead(request, offset): offset = int(offset) dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "In %s hour(s), it will be %s." % (offset, dt) return HttpResponse(html)
我们还是一次一行的解读这些代码:
跟我们在current_datetime里所做的一样,我们导入了django.http.HttpResponse和datetime模块
view函数hours_ahead接受两个参数:request和offset。
request是一个HttpRequest对象,和在current_datetime中一样。我们要重申一点:每一个view函数的第一个参数总是HttpRequest对象。
offset是一个string,它的值是通过URL模式里的那一对括号从请求的URL中得到的。比如请求的URL是/now/plus3hours/
offset的值就是一个string‘3’。请注意从URL中得到的值始终是string而不是integer,即使这个string是由纯数字构成的。
我们把这个变量命名为offset,但是你可以用任何合法的Python变量名来命名它。变量的名字并不重要,但是必须是view函数的第二个参数。
在函数里我们做的第一件事就是调用int(),把offset转换成整形。
如果一个值不能被转换成为一个整型数(像字符串'foo'), Python将会抛出ValueError。
但是我们对此并不担心,因为我们可以肯定offset一定可以被转换,正则表达式\d{1,2}一定会从URL中获得数字。
这也从另一个侧面证明了URLconf的优雅:它相当清楚地提供了一个对输入的校验。
程序的下一行揭示了我们对offset做类型转换的原因,这行代码计算了当前的时间加上一个时间偏移量,这个偏移量的值就是offset
保存计算的结果在变量dt.datetime.timedelta函数需要的输入参数就是整型。
下一行我们构造一个html的输出,和在current_datetime函数中类似。
最后,和current_datetime函数一样,我们返回一个HttpResponse对象。
好了,我们访问http://127.0.0.1:8000/now/plus3hours/可以验证它工作了
然后我们试试http://127.0.0.1:8000/now/plus100hours/,Django显示“Page not found”错误
http://127.0.0.1:8000/plushours/也会显示404错误,因为我们只接受1个或2个数字的参数
Django良好的出错页面
我们将offset = int(offset)注释掉
# offset = int(offset)
然后重新访问/now/plus3hours,你将看到一个很多信息的出错页面,包括TypeError信息在最上面:
“unsupported type for timedelta hours component: str”
发生了什么?
datetime.timedelta函数预期hours参数为integer类型,但我们注释掉了把offset转化为integer的代码
这导致datetime.timedelta产生TypeError,只是典型的每个程序员容易出现的小bug
中一些需要注意的地方:
1,页面的顶端显示的是关于异常的主要信息:异常的类型,异常的参数,导致异常的文件和行数
2,接下来页面显示完整的异常的Python traceback,在stack的每个frame里Django都显示了文件名、方法名、行数和该行代码
点击暗灰色的代码,你可以看到出错行前后的几行代码,让你得到上下文
点击“Local vars”可以看到所有的本地变量的列表,变量值,出错点等,这个debug信息是很有价值的
3,点击在“Traceback”下面的“Switch to copy-and-paste view”将切换到可以很容易复制粘贴的版本
当你想同他人分享异常信息或得到技术支持时(Django IRC聊天室或者Django用户邮件列表)可以很好的利用它
4,“Request information”包括大量的产生错误的Web请求的信息,GET和POST信息,cookie值和meta信息如CGI头部等
下面的“Settings”部分列出了当前Django安装的所有设置信息,后面我们会慢慢解释这些
Django错误页面在模板语法错误等情况下会显示更丰富的信息,现在去掉注释offset=int(offset)
你是那种喜欢用print语句debug 的程序员吗?使用Django错误页面就可以做到这点,不需要print语句
你可以临时插入assert False来触发错误页面,后面我们会解释更高级的debug方法
很显然大部分这些错误信息是敏感的,它暴露了你的Python代码和Django配置的五脏六腑
把这些信息显示到网上是愚蠢的,心怀恶意的人可能会在你的网站里面做肮脏的事情
无论如何,后面我们会提到怎样去除debug模式
练习
这里是一些巩固本章知识的练习,我们在这里介绍了一些新的技巧
1,创建另一个视图hours_behind,类似于hours_ahead,只不过显示过去的时间偏移量
这个视图应该绑定到/now/minusXhours/,这里X是偏移量小时数
2,一旦你做完练习1,一个良好的程序员会发现hours_ahead和hours_behind非常类似,这显得多余了
把这两个方法合并到单独的一个方法hour_offset,URL还是保持/now/minusXhours/和/now/plusXhours/不变
别忘了根据偏移量是正还是负来改变HTML代码,“In X hour(s)”或者“X hour(s) ago”
3,让我们更专业一点,允许/now/plus1hour/和/now/plus2hours/,但是不允许/now/plus1hours/和/now/plus2hour/
4,在HTML的显示里,如果偏移量是个位数,使用hour,否则使用hours
答案
1,hours_behind视图:
def hours_behind(request, offset): offset = int(offset) dt = datetime.datetime.now() - datetime.timedelta(hours=offset) html = "%s hour(s) ago, it was %s." % (offset, dt) return HttpResponse(html)
URL模式:
(r'^now/minus(\d{1,2})hours/$', hours_behind),
2,hour_offset视图:
def hour_offset(request, plus_or_minus, offset): offset = int(offset) if plus_or_minus == 'plus': dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = 'In %s hour(s), it will be %s.' % (offset, dt) else: dt = datetime.datetime.now() - datetime.timedelta(hours=offset) html = '%s hour(s) ago, it was %s.' % (offset, dt) html = '%s' % html return HttpResponse(html)
URL模式:
(r'^now/(plus|minus)(\d{1,2})hours/$', hour_offset),
3,URL模式:
(r'^now/(plus|minus)(1)hour/$', hour_offset), (r'^now/(plus|minus)([2-9]|\d\d)hours/$', hour_offset),
其中“|”表示“or”,上面的模式表示匹配模式[2-9]或者\d\d
即匹配一个2到9的数字或者匹配两个数字
4,hour_offset视图:
def hour_offset(request, plus_or_minus, offset): offset = int(offset) if offset == 1: hours = 'hour' else: hours = 'hours' if plus_or_minus == 'plus': dt = datetime.datetime.now() + datetime.timedelta(hours=offset) output = 'In %s %s, it will be %s.' % (offset, hours, dt) else: dt = datetime.datetime.now() - datetime.timedelta(hours=offset) output = '%s %s ago, it was %s.' % (offset, hours, dt) output = '%s' % output return HttpResponse(output)
难道不能把展现层代码从Python代码里分离出去吗?呵呵,这预示着......
评论
8 楼
lyhapple
2008-08-27
有个问题问一下:
我先配置了一个urlpatterns是这样的:
r'^mydjango/$',helloDemo.hello.index
在index模块中使用到了一个HTML模板.模板中引用到了一个CSS文件(与HTML放在一起的)...并没有为这个CSS文件配置urlpatterns,
在访问http://localhost/mydjango/时,可以显示模板文件生成的内容,但是引用的CSS文件并没有对这个页面产生作用...
类似的JPG文件.GIF文件等等也不能正常显示...
像这种情况要怎么解决..
我先配置了一个urlpatterns是这样的:
r'^mydjango/$',helloDemo.hello.index
在index模块中使用到了一个HTML模板.模板中引用到了一个CSS文件(与HTML放在一起的)...并没有为这个CSS文件配置urlpatterns,
在访问http://localhost/mydjango/时,可以显示模板文件生成的内容,但是引用的CSS文件并没有对这个页面产生作用...
类似的JPG文件.GIF文件等等也不能正常显示...
像这种情况要怎么解决..
7 楼
badpeas
2008-03-04
看这个有几点感触:
1. python对日期的处理要多看看
2. url的映射方式要去习惯它
3. 正则表达式要好好看看
4. 在url获取到参数是一个收获
这些在我做的小项目中之有少量的体现,以后要多注意,第2遍看本章,留个记号!
1. python对日期的处理要多看看
2. url的映射方式要去习惯它
3. 正则表达式要好好看看
4. 在url获取到参数是一个收获
这些在我做的小项目中之有少量的体现,以后要多注意,第2遍看本章,留个记号!
5 楼
limodou
2007-02-13
在urls.py中直接使用函数,需要开发版。0.95是不支持的,在djangobook.com上有强调它需要在trunk分支下的。
4 楼
fengzl
2007-02-12
from django.conf.urls.defaults import *
from mysite.views import current_datetime
urlpatterns = patterns('',
# Example:
# (r'^mysite/', include('mysite.apps.foo.urls.foo')),
# Uncomment this for admin:
# (r'^admin/', include('django.contrib.admin.urls')),
(r'^now/$', current_datetime)
)
上面搞错代码了
from mysite.views import current_datetime
urlpatterns = patterns('',
# Example:
# (r'^mysite/', include('mysite.apps.foo.urls.foo')),
# Uncomment this for admin:
# (r'^admin/', include('django.contrib.admin.urls')),
(r'^now/$', current_datetime)
)
上面搞错代码了
3 楼
fengzl
2007-02-12
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html)
这样写似乎已经不行了,似乎不能以函数对象作为参数了
AttributeError at /now/
'function' object has no attribute 'rindex'
Request Method: GET
Request URL: http://127.0.0.1:8000/now/
Exception Type: AttributeError
Exception Value: 'function' object has no attribute 'rindex'
Exception Location: E:\TRAC\PYTHON23\lib\site-packages\django-0.95.1-py2.3.egg\django\core\urlresolvers.py in get_mod_func, line 23
2 楼
hideto
2007-02-12
原来也可以这样写啊
最简单的方法是提取公共的视图前缀
见http://hideto.iteye.com/blog/44288
Django不久前发布的0.95.1只是fix了以下3个bugs,似乎没有提及URL配置的约束,难不成你每天跟踪svn的最新代码?
Django 0.95.1 released
We've just rolled out Django 0.95.1, a new minor release of Django which includes fixes for several bugs discovered in the original 0.95 release; 0.95.1 includes:
A patch for a small security vulnerability in the script Django's internationalization system uses to compile translation files (changeset 4360 in the "0.95-bugfixes" branch).
A fix for a bug in Django's authentication middleware which could cause apparent "caching" of a logged-in user (changeset 4361).
A patch which disables debugging mode in the flup FastCGI package Django uses to launch its FastCGI server, which prevents tracebacks from bubbling up during production use (changeset 4363).
It's recommended that anyone using the official 0.95 release upgrade to 0.95.1 to get these fixes, or apply the patches from the changesets linked above.
最简单的方法是提取公共的视图前缀
见http://hideto.iteye.com/blog/44288
Django不久前发布的0.95.1只是fix了以下3个bugs,似乎没有提及URL配置的约束,难不成你每天跟踪svn的最新代码?
Django 0.95.1 released
We've just rolled out Django 0.95.1, a new minor release of Django which includes fixes for several bugs discovered in the original 0.95 release; 0.95.1 includes:
A patch for a small security vulnerability in the script Django's internationalization system uses to compile translation files (changeset 4360 in the "0.95-bugfixes" branch).
A fix for a bug in Django's authentication middleware which could cause apparent "caching" of a logged-in user (changeset 4361).
A patch which disables debugging mode in the flup FastCGI package Django uses to launch its FastCGI server, which prevents tracebacks from bubbling up during production use (changeset 4363).
It's recommended that anyone using the official 0.95 release upgrade to 0.95.1 to get these fixes, or apply the patches from the changesets linked above.
1 楼
fengzl
2007-02-11
大哥最新版的django
urls.py要这么写了
urls.py要这么写了
from django.conf.urls.defaults import * #from mysite.views import current_datetime urlpatterns = patterns('', (r'^now/$', 'mysite.views.current_datetime'), )
发表评论
-
DjangoBook第7章翻译
2008-01-14 09:28 1777地址:http://hideto.iteye.com/blog ... -
DjangoBook完整发布了
2007-12-21 10:42 4603janeeyre、ttkk1024、chumpklutz等朋友 ... -
wxPython和PyQt的Hello World例子比较
2007-03-16 12:39 19538wxPython和PyQt分别是wxWidgets和Qt的py ... -
翻译www.djangobook.com之第十九章:国际化
2007-02-03 16:00 6775The Django Book:第19章 国 ... -
翻译www.djangobook.com之第十八章:自定义Django的admin界面
2007-02-03 11:16 11583The Django Book:第18章 自定义Django的 ... -
翻译www.djangobook.com之第十七章:与遗留系统和数据库集成
2007-02-03 11:16 4395The Django Book:第17章 与 ... -
翻译www.djangobook.com之第十六章:中间件
2007-02-03 11:15 5748The Django Book:第16章 中间件 有时你需要对 ... -
翻译www.djangobook.com之第十五章:贡献的其它子框架
2007-02-02 15:59 6196The Django Book:第15章 贡 ... -
翻译www.djangobook.com之第十四章:缓存
2007-01-31 01:45 6326The Django Book:第14章 缓 ... -
翻译www.djangobook.com之第十三章:注释
2007-01-31 01:45 2388not finished yet on www.djangob ... -
翻译www.djangobook.com之第十一章:生成非HTML内容
2007-01-19 23:38 8005The Django Book:第11章 生成非HTML内容 ... -
翻译www.djangobook.com之第十章:深入模板引擎
2007-01-16 19:53 9847The Django Book:第10章 深入模板引擎 大多数 ... -
翻译www.djangobook.com之第九章: Generic views
2007-01-14 20:18 9008The Django Book: 第9章 Generic vi ... -
翻译www.djangobook.com之第八章:高级视图和URL配置
2007-01-08 00:10 8344The Django Book:第8章 高级视图和URL配置 ... -
翻译www.djangobook.com之第七章:表单处理
2007-01-08 00:09 8058The Django Book:第7章 表单处理 翻译:xi ... -
翻译www.djangobook.com之第六章:Django管理系统admin
2007-01-07 17:59 9767The Django Book:第6章 Djang ... -
Django的Apache/mod_python配置
2007-01-05 16:22 7613主要看看httpd.conf: MaxRequestsPe ... -
翻译www.djangobook.com之第五章:与数据库交互:模型
2007-01-04 13:32 12594The Django Book:第5章 与数据库交互:模型 ... -
翻译www.djangobook.com之第四章:Django模板系统
2007-01-03 21:02 13747The Django Book:第4章 Django模板系统 ... -
翻译www.djangobook.com之第二章:Django快速上手
2007-01-03 20:32 11441The Django Book 第2章:Django快速上手 ...
相关推荐
### 第三章:视图和 URL 配置 本章详细阐述了 Django 如何处理 HTTP 请求并返回响应的过程。重点讲解了视图函数的设计方式、如何将视图与 URL 相关联,以及如何利用 URLconf 进行灵活的 URL 分配。 ### 第四章:...
- **第3章:动态网页基础** - 讲解了动态页面的概念,包括请求与响应的工作原理。 - **第4章:Django模板系统** - 深入探讨了Django的模板语言,以及如何创建和管理模板。 - **第5章:数据库交互:模型** - 解释了...
《Django Book》适合有一定Python基础的读者,书中会详细介绍Django的核心概念和功能,以及如何构建实际的Web应用。建议读者按照章节顺序阅读,每读完一章后尝试实践书中的示例。 ### 1.5 所需编程知识 阅读...
第三章重点介绍了如何使用Django来构建动态网页。这部分内容覆盖了如何处理HTTP请求、如何使用Django的URL分发机制以及如何在视图中查询数据库等关键知识点。 ### 四、Django模板系统 第四章深入讲解了Django强大...
这个中文版是基于官方英文原版(http://djangobook.py3k.cn/2.0/)翻译的,记录于2012年3月4日。该压缩包包含了多个章节的文档,覆盖了Django的核心概念和技术,以下是各章标题及其涉及的知识点: 1. **第四章:...
第三章“动态页面基础”涵盖了如何在Django中创建动态网页。这部分内容包括了解路由URL配置、视图函数的编写以及模板的使用,使读者能够构建交互式的Web页面。 第四章“Django的模板系统”深入讲解了Django模板语言...
##### 第3章 动态页面基础 - 解释什么是动态Web页面以及如何在Django中处理动态内容。 ##### 第4章 Django模板系统 - 详细讲解Django的模板引擎,包括模板的创建、继承和数据的展示。 ##### 第5章 数据库:模型 - ...
3. **动态Web页面基础**:讲解了如何创建视图(views),这些视图负责处理HTTP请求并生成响应,同时介绍了URL配置,使用户能够通过特定的URL访问不同的功能。 4. **Django模板系统**:深入解析了Django的模板语言,...
3. **视图和URL配置(第三章)** 讲解了如何定义视图函数来处理HTTP请求,并返回相应的响应。同时,介绍了URL分发器的配置方法,以便更好地组织应用中的路由规则。 4. **模版(第四章)** 模板系统是Django的一...
根据提供的信息,我们可以总结出以下关于《Django Book2中文版》的重要知识点: ### 第一章:介绍Django - **定义与价值**:Django是一个高效、有趣的Web开发框架,帮助开发者用最少的成本构建高质量的Web应用。...
《Django Book》是一部深入探讨Django Web框架的权威指南,专为那些希望利用Python高效构建Web应用的开发者而设计。Django是一个开源的、基于Python的Web开发框架,它强调了可重用性和“干”(Don't Repeat Yourself...
#### 第三章:视图和URL配置 这一部分深入讲解了视图函数的定义方式以及URL路由的配置方法。读者将学会如何设计合理的URL结构,并根据不同的请求类型调用相应的视图处理逻辑。 #### 第四章:模版 模版系统是Django...
《官方DjangoBook中文版》是一份详尽的Django框架学习资料,旨在为初学者和进阶者提供全面的指导。Django是基于Python语言的高性能Web开发框架,以其MVC(Model-View-Controller)设计模式和“ batteries included ...
18. **集成已有的数据库和应用**:这一章讲解了如何将现有数据库和第三方应用与Django项目整合起来,以便重用现有的数据和服务。 19. **国际化**:随着全球化的发展,多语言支持成为现代Web应用不可或缺的一部分。...