1.URLconf技巧
1).流线型化函数导入
在 URLconf 中的每一个入口包括了它所联系的视图函数,直接传入了一个函数对象。 这就意味着需要在模块开始处导入视图函数。但随着 Django 应用变得复杂,它的 URLconf 也在增长,并且维护这些导入可能使得管理变麻烦。
为了避免这种麻烦,Django 提供了一种方法可以在 URLconf 中为某个特别的模式指定视图函数: 你可以传入一个包含模块名和函数名的字符串,而不是函数对象本身。例如:
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^hello/$', 'mysite.views.hello' ), (r'^time/$', 'mysite.views.current_datetime' ), (r'^time/plus/(d{1,2})/$', 'mysite.views.hours_ahead' ), )
(注意视图名前后的引号。 应该使用带引号的 'mysite.views.current_datetime' 而不是 mysite.views.current_datetime 。)
使用这个技术,就不必导入视图函数了;Django 会在第一次需要它时导入合适的视图函数,根据字符串所描述的视图函数的名字和路径。
当使用字符串技术时,你可以采用更简化的方式:提取出一个公共视图前缀。 在我们的 URLconf 例子中,每一个视图字符串都是以 'mysite.views' 开始的,造成过多的输入。
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' ), )
2).使用多个视图前缀
如果你使用字符串技术,特别是当你的 URLconf 中没有一个公共前缀时,你最终可能混合视图。 然而,你仍然可以利用视图前缀的简便方式来减少重复。 只要增加多个 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'), )
3).使用命名组
在 Python 正则表达式中,命名的正则表达式组的语法是 (?P<name>pattern) ,这里 name 是组的名字,而 pattern 是匹配的某个模式。
from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^articles/(?P<year>\d{4})/$', views.year_archive), (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive), )
使用命名组可以让你的URLconfs更加清晰,减少参数次序可能搞混的潜在BUG,还可以 让你在函数定义中对参数重新排序。 接着上面这个例子,如果我们想修改URL把月份放到年份的前面,而不使用命名组的话,我们就不得不去修改视图 month_archive 的参数次序。 如果我们使用命名组的话,修改URL里提取参数的次序对视图没有影响。
注:如果在URLconf中使用命名组,那么命名组和非命名组是不能同时存在于同一个URLconf的模式中的。
4).传递额外的参数到视图中
有时你会发现你写的视图函数是十分类似的,只有一点点的不同。 比如说,你有两个视图,它们的内容是一致的,除了它们所用的模板不太一样:
# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}), (r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {'m_list': m_list})
5).捕捉值和额外参数之间的优先级
当冲突出现的时候,额外URLconf参数优先于捕捉值。 也就是说,如果URLconf捕捉到的一个命名组变量和一个额外URLconf参数包含的变量同名时,额外URLconf参数的值会被使用。例如:
from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^mydata/(?P<id>\d+)/$', views.my_view, {'id': 3}), )
2.使用缺省视图参数
你可以给一个视图指定默认的参数。 这样,当没有给这个参数赋值的时候将会使用默认的值。
# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^blog/$', views.page), (r'^blog/page(?P<num>\d+)/$', views.page), ) # views.py def page(request, num='1'): # Output the appropriate page of blog entries, according to num. # ...
注:我们已经注意到设置默认参数值是字符串 ‘1’ ,不是整数 1 。为了保持一致,因为捕捉给 num 的值总是字符串。
3.包装视图函数
假设你发现自己在各个不同视图里重复了大量代码,就像 这个例子:
def my_view1(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') # ... return render_to_response('template1.html') def my_view2(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') # ... return render_to_response('template2.html') def my_view3(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') # ... return render_to_response('template3.html')
如果我们能够丛每个视图里移除那些 重复代,并且只在需要认证的时候指明它们,那就完美了。 我们能够通过使用一个视图包装达到目的。 花点时间来看看这个:
def requires_login(view): def new_view(request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') return view(request, *args, **kwargs) return new_view
4.包含其他URLconf
在任何时候,你的URLconf都可以包含其他URLconf模块。 对于根目录是基于一系列URL的站点来说,这是必要的。 例如下面的,URLconf包含了其他URLConf:
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^weblog/', include('mysite.blog.urls')), (r'^photos/', include('mysite.photos.urls')), (r'^about/$', 'mysite.views.about'), )
这里有个很重要的地方: 例子中的指向 include() 的正则表达式并 不 包含一个 $ (字符串结尾匹配符),但是包含了一个斜杆。 每当Django遇到 include() 时,它将截断匹配的URL,并把剩余的字符串发往包含的URLconf作进一步处理。
5.捕获的参数和额外的参数如何和include()协同工作
被捕获的参数和额外的参数 总是 传递到被包含的URLconf中的 每一 行,不管那些行对应的视图是否需要这些参数。例如,下面的两个URLconf在功能上是相等的。
# urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/', include('inner'), {'blogid': 3}), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^archive/$', 'mysite.views.archive'), (r'^about/$', 'mysite.views.about'), (r'^rss/$', 'mysite.views.rss'), )
# urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/', include('inner')), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), (r'^about/$', 'mysite.views.about', {'blogid': 3}), (r'^rss/$', 'mysite.views.rss', {'blogid': 3}), )