第三章 Django之动态网页基础(1)
前一章中,我们解释了如何建立一个 Django 项目并启动 Django 开发服务器。当然,那个网站实际并没有干什么有用的事情,它所做的只是显示 It worked!消息。让我们来做些改变。本章将介绍如何使用 Django 创建动态网页。
第一份视图:动态内容
我们的第一个目标是创建一个显示当前日期和时间的网页。这是一个不错的动态网页范例,因为该页面的内容不是静态的。相反,其内容是随着计算(本例中是对当前时间的计算)的结果而变化的。这个简单的范例既不涉及数据库,也不需要任何用户输入,仅输出服务器的内 部时钟。
我们将编写一个视图函数以创建该页面。所谓的视图函数(或视图),只不过是一个接受 Web 请求并返回 Web 响应的 Python 函数。实际上,该响应可以是一份网页的 HTML 内 容、一次重定向、一条 404 错误、一份 XML 文档、一幅图片,或其它任何东西。视图本身包含返回该响应所需的任意逻辑。该段代码可以随意放置,只要在 Python 的路径设置中就可以了。没有其它要求——也可以说是没有任何奇特之处。为了给这些代码一个存身之处, 让我们在上一章所创建的 mysite 目录中新建一份名为 views.py 的文件。
以下是一个以 HTML 方式返回当前的日期与时间的视图 (view),:
1 from django.http import HttpResponse 2 import datetime 3 4 def current_datetime(request): 5 now = datetime.datetime.now() 6 html = "<html><body>It is now %s.</body></html>" % now 7 return HttpResponse(html)
我们逐行逐句地分析一遍这段代码:
首先,我们从 django.http 模块导入(import)HttpResponse 类。参阅附录 H 了解更多关于 HttpRequest 和 HttpResponse 的细节。
然后我们从 Python 标准库(Python自带的实用模块集合)中导入(import) datetime 模块。
datetime 模块包含几个处理日期和时间的函数(functions)和类(classes),其中就包括返回当前时间的函数。
接下来,我们定义了一个叫做 current_datetime 的函数。这就是所谓的视图函数(view function)。每个视图函数都以一个 HttpRequest 对象为第一个参数,该参数通常命名为 request 。
注意视图函数的名称并不重要;并不一定非得以某种特定的方式命名才能让 Django 识别它。此处,我们称之为 current_datetime,只是因为该名字明确地指出了它的功能,而它也可以被命名为 super_duper_awesome_current_time 或者其它同样莫名其妙的名字。Django 并不关心其名字。下一节将解释 Django 如何查找该函数。
函数中的第一行代码计算当前日期和时间,并以 datetime.datetime 对象的形式保存为局部变量 now 。
函数的第二行代码用 Python 的格式化字符串(format-string)功能构造了一段 HTML 响应。字符串里面的 %s 是占位符,字符串之后的百分号表示使用变量 now 的值替换 %s。(是的,这段 HTML 不合法,但我们只不过是想让范例尽量保持简短而已。)
最后,该视图返回一个包含所生成响应的 HttpResponse 对象。每个视图函数都负责返回一个 HttpResponse 对象。(也有例外,但是我们稍后才会接触到。)
Django 时区 (Time Zone)
Django 包含一个默认为 America/Chicago 的 TIME_ZONE 设置。这可能不是你所居住的时区, 因此你可以在 settings.py 文件中修改它。
将 URL 映射到视图
那么概括起来,该视图函数返回了包含当前日期和时间的一段 HTML 页面。但是如何告诉 Django 使用这段代码呢?这就是 URLconfs 粉墨登场的地方了。
URLconf 就像是 Django 所支撑网站的目录。它的本质是 URL 模式以及要为该 URL 模式调用的视图函数之间的映射表。你就是以这种方式告诉 Django,对于这个 URL 调用这段代码,对于那个 URL 调用那段代码。但必须记住的是视图函数必须位于 Python 搜索路径之中。
Python 搜索路径
Python 搜索路径就是使用 import 语句时,Python 所查找的系统目录清单。
举例来说,假定你将 Python 路径设置为 ['','/usr/lib/python2.4/sitepackages','/home/username/djcode/']。如果执行代码 from foo import bar,Python 将会首先在当前目录查找 foo.py 模块( Python 路径第一 项的空字符串表示当前目录)。如果文件不存在,Python 将查找 /usr/lib/python2.4/site-packages/foo.py 文件。如果文件也不存在,它将尝试/home/username/djcode/foo.py。最后,如果这个文件还不存在,它将引发 ImportError 异常。
如果对了解 Python 搜索路径值感兴趣,可以启动 Python 交互式解释程序,输入 import sys ,接着输入 print sys.path 。
通常,你不必关心 Python 搜索路径的设置。Python 和 Django 会在后台自动帮你处理好。(如果有兴趣了解的话,Python 搜索路径的设置工作是 manage.py 文件的职能之一。)
前一章中执行 django-admin.py startproject 时,该脚本会自动为你建了一份 URLconf(即 urls.py 文件)。让我们编辑一下这份文件。缺省情况下它是下面这个样子:
1 from django.conf.urls.defaults import * 2 3 urlpatterns = patterns( 4 '', 5 # Example: 6 # (r'^mysite/', include('mysite.apps.foo.urls.foo')), 7 # Uncomment this for admin: 8 # (r'^admin/',include('django.contrib.admin.urls')), 9 )
让我们逐行逐句分析一遍这段代码:
- 第一行从 django.conf.urls.defaults 模块引入了所有的对象,其中包括了叫做 patterns 的函数。
- 第二行调用 patterns() 函数并将返回结果保存到 urlpatterns 变量。patterns()函数只传入了一个空字符串参数。其他代码行都被注释掉了。(该字符串可用作视图 函数的通用前缀,但目前我们将略过这种高级用法。)
- 当前应该注意是 urlpatterns 变量,Django 期望能从 ROOT_URLCONF 模块中找到它。该变量定义了 URL 以及用于处理这些 URL 的代码之间的映射关系。
默认情况下,URLconf 所有内容都被注释起来了——Django 应用程序还是白版一块。(旁注:这也就是上一章中 Django 显示“It worked!”页面的原因。如果 URLconf 为空,Django 会认定你才创建好新项目,因此也就显示那种信息。)
现在编辑该文件以展示我们的 current_datetime 视图:
1 from django.conf.urls.defaults import * 2 from mysite.views import current_datetime 3 4 urlpatterns = patterns( 5 '', 6 (r'^time/$', current_datetime), 7 ) 我们做了两处修改。首先,我们从模块(在 Python 的 import 语法中,mysite/views.py 转译为 mysite.views)中引入了 current_datetime 视图。接着,我们加入了 (r'^time/$', current_datetime),这一行。该行就是所谓的 URLpattern,它是一个 Python 元组,其第一个元素是简单的正则表达式,第二个元素是为该模式应用的视图函数。
简单来说,我们只是告诉 Django,所有指向 URL /time/的请求都应由 current_datetime 这个视图函数来处理。
下面是一些需要注意的地方:
注意,该例中,我们将 current_datetime 视图函数作为对象传递,而不是调用它。这是 Python (及其它动态语言的) 的一个重要特性:函数是一级对象(first-class objects),
也就是说你可以像传递其它变量一样传递它们。很酷吧?
r'^time/$' 中的 r 表示 '^time/$' 是一个原始字符串。这样一来就可以避免正则表达式有过多的转义字符。
不必在 '^time/$' 前加斜杠(/)来匹配 /time/ ,因为 Django 会自动在每个表达式前添加一个斜杠。乍看起来,这好像有点奇怪,但是 URLconfs 可能由其它的 URLconfs 所引用,所以不加前面的斜杠可让事情简单一些。
上箭头 ^ 和美元符号 $ 符号非常重要。上箭头要求表达式对字符串的头部进行匹配,美元符号则要求表达式对字符串的尾部进行匹配。
最好还是用范例来说明一下这个概念。如果我们用 '^time/' (结尾没有$), 那么以 time/ 开始的 任意 URL 都会匹配,比如 /time/foo 和 /time/bar , 不仅仅是 /time/ 。同样的, 如果我们去掉最前面的 ^ ( 'time/$' ), Django 一样会匹配由 time/ 结束的 任意 URL /time/ ,比如 /foo/bar/time/ 。 因此,我们必须同时用上 ^ 和 $ 来精确匹配 URL /time/ 。不能多也不能少。
你可能想如果有人请求 /time 也可以同样处理。如果 APPEND_SLASH 的 设置是 True 的话, 系统会重定向到 /time/ ,这样就可以一样处理了。 (有关内容请查看附录 E )
启动 Django 开发服务器来测试修改好的 URLconf, 运行命令行 python manage.py runserver 。 (如果你让它一直运行也可以,开发服务器会自动监测代码改动并自动重新载 入,所以不需要手工重启) 开发服务器的地址是 http://127.0.0.1:8000/ ,打开你的浏览 器访问 http://127.0.0.1:8000/time/ 。 你就可以看到输出结果了。
正则表达式
正则表达式 (或 regexes ) 是通用的文本模式匹配的方法。Django URLconfs 允许你 使用 任意的正则表达式来做强有力的 URL 映射,不过通常你实际上可能只需要使用很少的一 部分 功能。下面就是一些常用通用模式:
符号 |
匹配 |
. | 任意字符 |
\d | 任意数字 |
[A-Z] | 任意字符,A-Z(大写) |
[a-z] | 任意字符,a-z(小写) |
[A-Za-z] | 任意字符(不区分大小写) |
+ | 匹配一个或多个 |
[^/]+ | 匹配不是/的任意字符 |
* | 匹配0个或多个(注意与+区分) |
{1,3} | 匹配1个到3个(包括3) |
有关正则表达式的更多内容,请访问 http://www.djangoproject.com/r/python/re-module/.
引用原文:《The Django Book》 http://djangobook.py3k.cn/