在Python的Django框架中包装视图函数
我们最终的视图技巧利用了一个高级python技术。假设你发现自己在各个不同视图里重复了大量代码,就像这个例子:
defmy_view1(request): ifnotrequest.user.is_authenticated(): returnHttpResponseRedirect('/accounts/login/') #... returnrender_to_response('template1.html') defmy_view2(request): ifnotrequest.user.is_authenticated(): returnHttpResponseRedirect('/accounts/login/') #... returnrender_to_response('template2.html') defmy_view3(request): ifnotrequest.user.is_authenticated(): returnHttpResponseRedirect('/accounts/login/') #... returnrender_to_response('template3.html')
这里,每一个视图开始都检查request.user是否是已经认证的,是的话,当前用户已经成功登陆站点否则就重定向/accounts/login/(注意,虽然我们还没有讲到request.user,但是14章将要讲到它.就如你所想像的,request.user描述当前用户是登陆的还是匿名)
如果我们能够丛每个视图里移除那些重复代,并且只在需要认证的时候指明它们,那就完美了。我们能够通过使用一个视图包装达到目的。花点时间来看看这个:
defrequires_login(view): defnew_view(request,*args,**kwargs): ifnotrequest.user.is_authenticated(): returnHttpResponseRedirect('/accounts/login/') returnview(request,*args,**kwargs) returnnew_view
函数requires_login,传入一个视图函数view,然后返回一个新的视图函数new_view.这个新的视图函数new_view在函数requires_login内定义处理request.user.is_authenticated()这个验证,从而决定是否执行原来的view函数
现在,我们可以从views中去掉ifnotrequest.user.is_authenticated()验证.我们可以在URLconf中很容易的用requires_login来包装实现.
fromdjango.conf.urls.defaultsimport* frommysite.viewsimportrequires_login,my_view1,my_view2,my_view3 urlpatterns=patterns('', (r'^view1/$',requires_login(my_view1)), (r'^view2/$',requires_login(my_view2)), (r'^view3/$',requires_login(my_view3)), )
优化后的代码和前面的功能一样,但是减少了代码冗余现在我们建立了一个漂亮,通用的函数requires_login()来帮助我们修饰所有需要它来验证的视图
包含其他URLconf
如果你试图让你的代码用在多个基于Django的站点上,你应该考虑将你的URLconf以包含的方式来处理。
在任何时候,你的URLconf都可以包含其他URLconf模块。对于根目录是基于一系列URL的站点来说,这是必要的。例如下面的,URLconf包含了其他URLConf:
fromdjango.conf.urls.defaultsimport* urlpatterns=patterns('', (r'^weblog/',include('mysite.blog.urls')), (r'^photos/',include('mysite.photos.urls')), (r'^about/$','mysite.views.about'), )
admin模块有他自己的URLconf,你仅仅只需要在你自己的代码中加入include就可以了.
这里有个很重要的地方:例子中的指向include()的正则表达式并不包含一个$(字符串结尾匹配符),但是包含了一个斜杆。每当Django遇到include()时,它将截断匹配的URL,并把剩余的字符串发往包含的URLconf作进一步处理。
继续看这个例子,这里就是被包含的URLconfmysite.blog.urls:
fromdjango.conf.urls.defaultsimport* urlpatterns=patterns('', (r'^(\d\d\d\d)/$','mysite.blog.views.year_detail'), (r'^(\d\d\d\d)/(\d\d)/$','mysite.blog.views.month_detail'), )
通过这两个URLconf,下面是一些处理请求的例子:
- /weblog/2007/:在第一个URLconf中,模式r'^weblog/'被匹配。因为它是一个include(),Django将截掉所有匹配的文本,在这里是'weblog/'。URL剩余的部分是2007/,将在mysite.blog.urls这个URLconf的第一行中被匹配到。URL仍存在的部分为2007/,与第一行的mysite.blog.urlsURL设置相匹配。
- /weblog//2007/(包含两个斜杠)在第一个URLconf中,r'^weblog/'匹配因为它有一个include(),django去掉了匹配的部,在这个例子中匹配的部分是'weblog/'剩下的部分是/2007/(最前面有一个斜杠),不匹配mysite.blog.urls中的任何一行.
- /about/:这个匹配第一个URLconf中的mysite.views.about视图。