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}),
)