Django 学习笔记 (VII)

第八章 高级视图和 URL 配置

如题,本章介绍一些关于 views.py 和 urls.py 相关的一些高级的使用方法,其实也没多难,是此前的一个延伸。

1. urls.py 技巧

此前,设定一个路由大概会依照如下方法: a. import 定义的 view 处理函数; b. 利用 patterns() 函数建立路由规则赋值给 urlpatterns;

举个例子: 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), )

这样的话需要导入的处理函数全部都需要显示地 import 一遍,然后传入相应的函数对象;这样要么要 import 好多次,要么就写很长的模块路径;

要是这些情况改善,教程介绍了以下几种办法,以下单做概括记录: a. patterns 函数的每条路由规则是一个二元的 tuple,其中第二个参数既可以为处理函数对象,也可以为包含完整模块路径的字符串; b. patterns 函数的第一个参数是一个字符串,作为后面所有路由规则第二个参数的公共前缀,这样可以合并重复冗余的函数路径声明; c. 对 urlpatterns 的赋值还可以通过多次的 patterns 函数分别制定,如果后面再要追加路由规则,可以用 += 进行追加;

综上,举个例子说明所有问题: from django.conf.urls.defaults import *

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

urlpatterns += patterns('weblog.views', (r'^tag/(\w+)/$', 'tag'), )

这样,可以看到有什么优势: a. 减少了 import,如果新增了新的 views 处理函数,只需要添加相应的 patterns 块即可,只需要定义字符串引用,而不需要重复添加 import 语句; b. 合并了处理函数的公共前缀,每一个路由规则剪短了,而且可以根据模块的包进行很好的分块,逻辑更加清晰; c. 需要变动的时候所需的修改减少了; d. 可以动态根据条件来选择路由规则,例如仅在调试模式下使某些路由规则生效;

2. 使用命名组

回想之前所讲关于路由传递参数的方式,无非是通过路由的正则匹配,() 内匹配到的参数会依照顺序传到 views 处理函数的 request 参数之后。 事实上有另一种更好的处理办法,就是命名组,也就是对具体匹配的内容指定一个名称,然后在处理函数中利用指明得得参数来获取他。

又是听得有些拗口,其实极为浅显,直接举个例子就完全明白了:

a. 老办法: # 未使用命名组的 urls.py 路由匹配方式 from django.conf.urls.defaults import * from mysite import views

urlpatterns = patterns('', (r'^articles/(\d{4})/$', views.year_archive), (r'^articles/(\d{4})/(\d{2})/$', views.month_archive), )

实际传递到 views.py 的函数调用方式,根据参数顺序来获取匹配到的参数

month_archive(request, '2006', '03')

b. 使用命名组的办法: # 注意正则输出的小括号内添加了命名信息 from django.conf.urls.defaults import * from mysite import views

urlpatterns = patterns('', (r'^articles/(?P\d{4})/$', views.year_archive), (r'^articles/(?P\d{4})/(?P\d{2})/$', views.month_archive), )

然后实际调用的方式就相当于制定了命名参数:

month_archive(request, year='2006', month='03')

好了,效果明白是什么了,反正如果路由规则的正则串指定了命名,然后在视图函数里面就可以定义一个命名参数,即使顺序掉乱也可以匹配正确,总结一下做法:

a. 小括号匹配规则,在左括号之后加上 ?P<var_name> b. 在 views.py 写函数的时候在 request 参数后面加上对应的 var_name 参数列表

基本清晰了,有几点特殊的也要注意: a. 如果正则指定了命名参数,则未指定命名的小括号匹配会忽略输出; b. 如果没有指定命名参数,则所有小括号的匹配会按照顺序参数输出; c. 除了以上的参数还可以在路由规则里面传递其他参数,方式是在路由规则的第三个参数提供一个字典(前面两个参数是路由正则以及视图方法路径或者对象),注意这个字典的值可以是任何类型的 python 对象哦,另外这个第三个指定的参数会优先于捕捉值,也就是在明明冲突的时候会覆盖掉正则匹配到的同名参数;

3. 伪造视图参数

上面将特殊的第三点(可以提供一个额外的参数字典)可以用来伪造试图参数,按照书中的例子,如果有一个路由以及对应的视图函数: (r'^mydata/(?P\w{3})/(?P\d{2})/$', views.myview) 那么在 views.myview 这个视图函数里面就会获取 url 中的 month 和 day 参数来进行命名参数调用; 如果我们有一个另外的 url 想用同样的方式来处理一个内容,例如 mydata/birthday 应该与 mydata/jul/24 显示的一样,那么我们可以用一条路由在前面将其截获,然后再第三个参数将伪造的参数传递给同一个视图函数,也就是在原来的路由规则前面加上这一条进行拦截: (r'^mydata/birthday/$', views.myview, {'month': 'jul', 'day': '24'})

这里没有新的技术,但却是一个极好的技巧!

我们应该尽量使代码复用,创建通用的,参数丰富的视图,然后通过不同的调用方式来利用同一个视图。

4. 视图的请求方法分支

实际操作中会出现当 request 是 get 和 post 时分别使用不同的处理逻辑的情况; 这种情况下,最随手的办法会在一个大的视图函数里面,用一个 if else 来分别写出两种处理办法;但是这样不好,事实上可以通过指定一个转发的视图函数,通过路由规则的第三个参数分别传入 GET 和 POST 分别对应的处理函数,然后进行转发,这样就可以把单独的处理方法独立出来,又或者在原有一个方法的基础上不修改处理函数本身完成重构,添加一个新的处理办法,具体见教材例吧。 注意那个 method splitter 转发方法是通用的,可以被不同的视图使用;

5. include 其他 urls.py

django 支持我们使用多级的 urls.py,假设我们有数个 apps,然后分别在不同的子目录下独立工作,那么我们可以使用 include 函数将 urls.py 的路由规则进行分级: 做法只是将路由规则第二个参数(视图函数)改为 include 一个其他的 url 模块; 这样的话路由处理的时候将会将当前匹配的正则截断并将剩余部分交给 include 的 url 模块,另外的话,所有托管之前捕捉到的命名参数以及指定的额外参数都会原样托管给 include 的那个 url 模块。

这样做大大增强了模块之间的独立性,好处太多了。

这一章就是如此,继续往后冲!


【转载请附】愿以此功德,回向 >>

原文链接:http://www.huangwenchao.com.cn/2014/02/django07.html【Django 学习笔记 (VII)】

发表评论

电子邮件地址不会被公开。 必填项已用*标注