在Django中创建动态视图的教程


Posted in Python onJuly 15, 2015

在我们的`` current_datetime`` 视图范例中,尽管内容是动态的,但是URL ( /time/ )是静态的。 在 大多数动态web应用程序,URL通常都包含有相关的参数。 举个例子,一家在线书店会为每一本书提供一个URL,如:/books/243/、/books/81196/。

让我们创建第三个视图来显示当前时间和加上时间偏差量的时间,设计是这样的: /time/plus/1/ 显示当前时间+1个小时的页面 /time/plus/2/ 显示当前时间+2个小时的页面 /time/plus/3/ 显示当前时间+3个小时的页面,以此类推。

新手可能会考虑写不同的视图函数来处理每个时间偏差量,URL配置看起来就象这样:

urlpatterns = patterns('',
  ('^time/$', current_datetime),
  ('^time/plus/1/$', one_hour_ahead),
  ('^time/plus/2/$', two_hours_ahead),
  ('^time/plus/3/$', three_hours_ahead),
  ('^time/plus/4/$', four_hours_ahead),
)

很明显,这样处理是不太妥当的。 不但有很多冗余的视图函数,而且整个应用也被限制了只支持 预先定义好的时间段,2小时,3小时,或者4小时。 如果哪天我们要实现 5 小时,我们就 不得不再单独创建新的视图函数和配置URL,既重复又混乱。 我们需要在这里做一点抽象,提取 一些共同的东西出来。

关于漂亮URL的一点建议

如果你有其它web平台的开发经验(如PHP或Java),你可能会想:嘿!让我们用查询字符串参数吧! 就像/time/plus?hours=3里面的小时应该在查询字符串中被参数hours指定(问号后面的是参数)。

你 可以 在Django里也这样做 (如果你真的想要这样做,我们稍后会告诉你怎么做), 但是Django的一个核心理念就是URL必须看起来漂亮。 URL /time/plus/3/ 更加清晰, 更简单,也更有可读性,可以很容易的大声念出来,因为它是纯文本,没有查询字符串那么 复杂。 漂亮的URL就像是高质量的Web应用的一个标志。

Django的URL配置系统可以使你很容易的设置漂亮的URL,而尽量不要考虑它的 反面 。

那么,我们如何设计程序来处理任意数量的时差? 答案是:使用通配符(wildcard URLpatterns)。正如我们之前提到过,一个URL模式就是一个正则表达式。因此,这里可以使用d+来匹配1个以上的数字。

urlpatterns = patterns('',
  # ...
  (r'^time/plus/\d+/$', hours_ahead),
  # ...
)

这里使用# …来表示省略了其它可能存在的URL模式定义。 这个URL模式将匹配类似 /time/plus/2/ , /time/plus/25/ ,甚至 /time/plus/100000000000/ 的任何URL。 更进一步,让我们把它限制在最大允许99个小时, 这样我们就只允许一个或两个数字,正则表达式的语法就是 \d{1,2} :

(r'^time/plus/\d{1,2}/$', hours_ahead),

备注

在建造Web应用的时候,尽可能多考虑可能的数据输入是很重要的,然后决定哪些我们可以接受。 在这里我们就设置了99个小时的时间段限制。

另外一个重点,正则表达式字符串的开头字母“r”。 它告诉Python这是个原始字符串,不需要处理里面的反斜杠(转义字符)。 在普通Python字符串中,反斜杠用于特殊字符的转义。比如n转义成一个换行符。 当你用r把它标示为一个原始字符串后,Python不再视其中的反斜杠为转义字符。也就是说,“n”是两个字符串:“”和“n”。由于反斜杠在Python代码和正则表达式中有冲突,因此建议你在Python定义正则表达式时都使用原始字符串。 从现在开始,本文所有URL模式都用原始字符串。

现在我们已经设计了一个带通配符的URL,我们需要一个方法把它传递到视图函数里去,这样 我们只用一个视图函数就可以处理所有的时间段了。 我们使用圆括号把参数在URL模式里标识 出来。 在这个例子中,我们想要把这些数字作为参数,用圆括号把 \d{1,2} 包围起来:

(r'^time/plus/(\d{1,2})/$', hours_ahead),

如果你熟悉正则表达式,那么你应该已经了解,正则表达式也是用圆括号来从文本里 提取 数据的。

最终的URLconf包含上面两个视图,如:

from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = patterns('',
  (r'^hello/$', hello),
  (r'^time/$', current_datetime),
  (r'^time/plus/(\d{1,2})/$', hours_ahead),
)

现在开始写 hours_ahead 视图。

编码次序

这个例子中,我们先写了URLpattern ,然后是视图,但是在前面的例子中, 我们先写了视图,然后是URLpattern 。 哪一种方式比较好?

嗯,怎么说呢,每个开发者是不一样的。

如果你是喜欢从总体上来把握事物(注: 或译为“大局观”)类型的人,你应该会想在项目开始 的时候就写下所有的URL配置。

如果你从更像是一个自底向上的开发者,你可能更喜欢先写视图, 然后把它们挂接到URL上。 这同样是可以的。

最后,取决与你喜欢哪种技术,两种方法都是可以的。 (见上)

hours_ahead 和我们以前写的 current_datetime 很象,关键的区别在于: 它多了一个额外参数,时间差。 以下是view代码:

from django.http import Http404, HttpResponse
import datetime

def hours_ahead(request, offset):
  try:
    offset = int(offset)
  except ValueError:
    raise Http404()
  dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
  html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
  return HttpResponse(html)

让我们逐行分析一下代码:

    视图函数, hours_ahead , 有 两个 参数: request 和 offset . (见上)

        request 是一个 HttpRequest 对象, 就像在 current_datetime 中一样. 再说一次好了: 每一个视图 总是 以一个 HttpRequest 对象作为 它的第一个参数。 (见上)

        offset 是从匹配的URL里提取出来的。 例如:如果请求URL是/time/plus/3/,那么offset将会是3;如果请求URL是/time/plus/21/,那么offset将会是21。请注意:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。

        (从技术上来说,捕获值总是Unicode objects,而不是简单的Python字节串,但目前不需要担心这些差别。)

        在这里我们命名变量为 offset ,你也可以任意命名它,只要符合Python 的语法。 变量名是无关紧要的,重要的是它的位置,它是这个函数的第二个 参数 (在 request 的后面)。 你还可以使用关键字来定义它,而不是用 位置。

    我们在这个函数中要做的第一件事情就是在 offset 上调用 int() . 这会把这个字符串值转换为整数。

    请留意:如果你在一个不能转换成整数类型的值上调用int(),Python将抛出一个ValueError异常。如:int(‘foo')。在这个例子中,如果我们遇到ValueError异常,我们将转为抛出django.http.Http404异常——正如你想象的那样:最终显示404页面(提示信息:页面不存在)。

    机灵的读者可能会问: 我们在URL模式中用正则表达式(d{1,2})约束它,仅接受数字怎么样?这样无论如何,offset都是由数字构成的。 答案是:我们不会这么做,因为URLpattern提供的是“适度但有用”级别的输入校验。万一这个视图函数被其它方式调用,我们仍需自行检查ValueError。 实践证明,在实现视图函数时,不臆测参数值的做法是比较好的。 松散耦合,还记得么?

    下一行,计算当前日期/时间,然后加上适当的小时数。 在current_datetime视图中,我们已经见过datetime.datetime.now()。这里新的概念是执行日期/时间的算术操作。我们需要创建一个datetime.timedelta对象和增加一个datetime.datetime对象。 结果保存在变量dt中。

    这一行还说明了,我们为什么在offset上调用int()——datetime.timedelta函数要求hours参数必须为整数类型。

    这行和前面的那行的的一个微小差别就是,它使用带有两个值的Python的格式化字符串功能, 而不仅仅是一个值。 因此,在字符串中有两个 %s 符号和一个以进行插入的值的元组: (offset, dt) 。

    最终,返回一个HTML的HttpResponse。 如今,这种方式已经过时了。

在完成视图函数和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 错误一样。 访问URL http://127.0.0.1:8000/time/plus/ (没有 定义时间差) 也会抛出404错误。

Python 相关文章推荐
DJANGO-ALLAUTH社交用户系统的安装配置
Nov 18 Python
python一键升级所有pip package的方法
Jan 16 Python
利用python解决mysql视图导入导出依赖的问题
Dec 17 Python
python实现日常记账本小程序
Mar 10 Python
Python3利用Dlib19.7实现摄像头人脸识别的方法
May 11 Python
基于python的图片修复程序(实现水印去除)
Jun 04 Python
Python实现的简单排列组合算法示例
Jul 04 Python
在numpy矩阵中令小于0的元素改为0的实例
Jan 26 Python
python 读取文件并把矩阵转成numpy的两种方法
Feb 12 Python
python实现在一个画布上画多个子图
Jan 19 Python
浅析python表达式4+0.5值的数据类型
Feb 26 Python
Pyhton模块和包相关知识总结
May 12 Python
Python的Django框架中的URL配置与松耦合
Jul 15 #Python
Django查找网站项目根目录和对正则表达式的支持
Jul 15 #Python
在Django中创建第一个静态视图
Jul 15 #Python
开始着手第一个Django项目
Jul 15 #Python
Python的Django框架可适配的各种数据库介绍
Jul 15 #Python
Python的Django框架安装全攻略
Jul 15 #Python
python实现爬虫下载美女图片
Jul 14 #Python
You might like
php中处理模拟rewrite 效果
2006/12/09 PHP
php 分页类 扩展代码
2009/06/11 PHP
PHP将字符分解为多个字符串的方法
2014/11/22 PHP
PHP过滤黑名单关键字的方法
2014/12/01 PHP
laravel 时间格式转时间戳的例子
2019/10/11 PHP
XP折叠菜单&amp;仿QQ2006菜单
2006/12/16 Javascript
js可突破windows弹退效果代码
2008/08/09 Javascript
jquery 页面全选框实践代码
2010/04/02 Javascript
JavaScript事件处理器中的event参数使用介绍
2013/05/24 Javascript
js调用后台、后台调用前台等方法总结
2014/04/17 Javascript
JS实现鼠标点击展开或隐藏表格行的方法
2015/03/03 Javascript
jQuery 3.0 的变化及使用方法
2016/02/01 Javascript
基于JavaScript FileReader上传图片显示本地链接
2016/05/27 Javascript
Javascript缓存API
2016/06/14 Javascript
全面解析JavaScript中的valueOf与toString方法(推荐)
2016/06/14 Javascript
Actionscript与javascript交互实例程序(修改)
2016/09/22 Javascript
基于jquery实现二级联动效果
2017/03/30 jQuery
JavaScript实现焦点进入文本框内关闭输入法的核心代码
2017/09/20 Javascript
基于es6三点运算符的使用方法(实例讲解)
2017/10/12 Javascript
原生js实现简单的焦点图效果实例
2017/12/14 Javascript
Vue检测屏幕变化来改变不同的charts样式实例
2020/10/26 Javascript
[00:37]食人魔魔法师轮盘吉兆顺应全新至宝将拥有额外款式
2019/12/19 DOTA
Python 的 with 语句详解
2014/06/13 Python
python操作mysql代码总结
2018/06/01 Python
GitHub 热门:Python 算法大全,Star 超过 2 万
2019/04/29 Python
python logging模块的使用总结
2019/07/09 Python
PyCharm 2020 激活到 2100 年的教程
2020/03/25 Python
python进度条显示之tqmd模块
2020/08/22 Python
Pycharm github配置实现过程图解
2020/10/13 Python
Crabtree & Evelyn欧盟:豪华洗浴、身体和护发
2021/03/09 全球购物
以思科路由器为例你写下单臂路由的配置命令
2013/08/03 面试题
简述网络文件系统NFS,并说明其作用
2016/10/19 面试题
公共事业管理本科生求职信
2013/10/07 职场文书
宾馆仓管员岗位职责
2014/07/27 职场文书
2015小学教育教学工作总结
2015/07/21 职场文书
Python+DeOldify实现老照片上色功能
2022/06/21 Python