urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), ]
(\d{4})匹配出了
2005,但2005任然会被当做字符串传递给year_archive
year_archive(year='2005')
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), url(r'^list/(?P<name>\S*)/(?P<id>\d*)/$', list), url(r'^list/(?P<name>\S*)/$', list,{"id":123}), #如果不提供第二个参数,则自动输入123 ]
我们做一个显示当前日期和时间的页面。这个例子足够简单, 不涉及数据库或者用户输入,仅仅是将服务器上的时间显示到页面上。
这个视图需要做两件事:计算当前的日期和时间,以及返回一个包含这个值的 HttpResponse。如果你有过Python的经验,你也许知道Python有一个 datetime 模块可以用来计算日期。 下面我们来看看如何用它:
>>> import datetime >>> print(datetime.datetime.now()) 2015-01-27 09:54:03.891556很简单,也并没有涉及到Django。它仅仅是Python的代码。(我们希望你注意哪些是纯Python代码,哪些 是有Django特性的代码,这样,在你学习Django的过程中,你也可以学到一些Python的知识,并用到其他的 不用Django的Python项目中。)
要想我们的Django视图显示当前的日期和时间,我们仅需把语句 datetime.datetime.now() 放到 视图函数里面,然后返回一个 HttpResponse 。代码如下:
import datetime from django.http import HttpResponse def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
如果没有必要,我们就不再重复列出先前的代码。你应该能识别出哪些是先前的代码,哪些是新的代码。
我们来回顾一下刚刚添加 current_datetime 时做的更改。
首先,我们在文件顶端添加了一条语句 import datetime , 这样我们就可以计算日期了。
current_datetime 函数计算当前的日期和时间,以 datetime.datetime 的形式 保存在 now 这个局部变量中。
函数的第二行,我们用Python的格式化字符串(format-string)构造了一段HTML。 字符串中的 %s 是一个占位符,字符串后面的百分号(%)表示用变量 now 的值代替前面 字符串中的 %s 。now
是一个 datetime.datetime 而不是一个字符 串, %s (格式化字符)会把它转换 "2014-11-27 17:28:31.002425" 这样的字符串表现形式。所以,最后会输出 "It is now 2014-11-27 17:28:31.002425." 这样的HTML字符串。
我们现在的HTML是有错误的,我们这样做是为了保持例子的简短。
最后,我们的视图和刚刚的 hello 视图一样返回一个 HttpResponse 对象,包含了刚刚生成的响应。
在 views.py 中添加视图之后,我们还要在 urls.py 中添加URLpattern来告诉Django由哪个URL来处理 这个视图。用 /time 之类的字眼会比较容易理解:
from django.conf.urls.defaults import patterns, include, url from mysite.views import hello, current_datetime urlpatterns = patterns('', url(r'^hello/$', hello), url(r'^time/$', current_datetime), )
这里,我们修改了两个地方,首先,在顶部导入了 current_datetime 函数。 然后,更重要的一步是我们 添加了一个URL /time 关联到这个新视图。理解了吗?
写好了视图,添加了URLpattern,现在运行 runserver 并访问在浏览器里面访问 http://127.0.0.1:8000/time/
,你将会看到当前的时间和日期。
在我们的上一个视图 current_datetime ,尽管内容是动态的,但是URL (/time/) 是静态的。 在大多数动态的Web应用程序中,URL通常可以包含一些参数可以控制页面的输出。比如一个在线书店会 给每本书分配一个URL,如 /books/243/ , /books/81196/ 这样。
那让我们来创建下一个个视图,显示当前时间加上一个偏移量的时间。我们的目标是 /time/plus/1/ 显示当前时间+1个小时的页面, /time/plus/2/ 显示当前时间+2个小时的 页面, /time/plus/3/ 显示+3个小时的页面,以此类推。
关于漂亮URL的一点建议
如果你有其他Web平台的开发经验(比如PHP或Java), 你可能会想:嘿!让我们用查询字符串参数 吧!像 /time/plus?hours=3 这样,里面的小时应该在查询字符串中被参数 hours 指定(问号后面的部分)。
你可以这样做,但是Django的一个核心理念是URL看起来必须漂亮。像 /time/plus/3/ 这样的URL更清晰,更简单,也更具可读性,可以很容易被大声念出来。 漂亮的URL就是高质量的Web应用的一个标志。
那么,我们要怎样来处理任意小时的偏差呢?我们要用到通配符。我们前面有提到,一个URL模式就是一 个正则表达式,因此,我们可以在这里用\d+来匹配一个以上的数字。
urlpatterns = patterns('', # ... url(r'^time/plus/\d+/$', hours_ahead), # ... )
这个URLpattern可以匹配任意类似 /time/plus/2/ , /time/plus/25/ 甚至是 /time/plus/100000000000/ 这样的URL。更进一步,让我们把它限制在最大允许99个小时,这样 我们就只允许一个或两个数字,正则表达式的语法是 \d{1,2}:
url(r'^time/plus/\d{1,2}/$', hours_ahead),
注意 当我们编写Web应用的时候,尽可能考虑可能的数据输入是很重要的,然后决定哪些我们可以接受, 这里,我们就显示了99个小时的时间差。
我们已经为我们的URL配置好了通配符,我们还需要把它的值传到view function里去,这样我们才能只用一个 view function去处理任意的时间偏移数。我们要做的是在URLpattern里用括号把我们需要的数据括起来。 我们这个例子里,我们需要那个数字作为参数,所以我们把 \d{1,2} 括起来:
url(r'^time/plus/(\d{1,2})/$', hours_ahead), #注意\d两边的小括号
搞定这些后,让我们来写 hours_ahead 视图了。
hours_ahead 和前面那个 current_datetime 很相似。只有一点不同:它还接受一个参数, 即偏移的小时数 offset 。 代码如下:
from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset): try: offset = int(offset) except ValueError: #如果这个值不能被转换成整数,Python会抛出一个 ValueError 异常。 raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) #计算时间增减用 datetime.timedelta html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html)
精明的读者可能会问:我们在URLpattern的正则表达式中已经用了 (\d{1,2}) 来约束它仅接受 数字了,怎么可能还会有出现 ValueError 的情况呢? 捕获值不是只可能是由数字组成的吗? 答案是: 我们不会这么做,因为URLpattern提供的是“适度但有用”级别的输入校验。万一这个视图 函数被其它方式调用,我们仍需自行检查ValueError。 实践证明,在实现视图函数时,不臆测参数值的做法是比较好的。 松散耦合,还记得么?
在完成视图函数和URL配置编写后,启动Django开发服务器,用浏览器访问 http://127.0.0.1:8000/time/plus/3/
来确认它工作正常。 然后是http://127.0.0.1:8000/time/plus/5/
。再然后是http://127.0.0.1:8000/time/plus/24/
。
最后,访问http://127.0.0.1:8000/time/plus/100/
来检验URL配置里设置的模式是否只 接受一个或两个数字;Django会显示一个 Page not found error 页面, 和以前看到的 404 错误一样。 访问URLhttp://127.0.0.1:8000/time/plus/
(没有 定义时间差) 也会抛 出404错误。
编码顺序 这个例子中,我们先写了URLpattern,然后才写视图,但是上一个例子中我们是先写视图,才是URLpattern。 哪一种方式更好呢?
如果你是一个喜欢从总体上来把握的人,你应该更喜欢在项目开始的时候就写下所有的URL配置。 然后再去编写每个对应的视图。这种方式的一个好处是它会给你一个很清晰的列表,一个to-do list, 还明确地定义了你需要编写的视图函数的参数。
如果你更像一个自底向上的开发者,你可能更喜欢先写视图,然后把他们和URL联系起来。这样也是没问题的。
上一讲:Python网络编程05----django与数据库的交互
下一讲:Python网络编程08----Django模版
欢迎收听我的微信公众号