一、使用命名组
使用命名组,能够使代码更加清晰,在做一些复杂模块的时候,只需看一下URLconf就大概知道怎么回事了。
命名组规则:
在 Python 正则表达式中,命名的正则表达式组的语法是 (?Ppattern) ,这里 name 是组的名字,而pattern 是匹配的某个模式。
例子:
urlpatterns = patterns('',
(r'^showdate/(?P/d{4})/(?P/d{2})/(?P/d{2})/$',Show_date),
)
这里定义了三个命名组分别是年月日。在模板里根据名称就能很好的组织并处理数据
def Show_date(request,mon,year,day):
html = 'ShowTime: '+year+'year'+' '+month+'Mon'+' '+day+'day'
html = '%s' % html
return HttpResponse(html)
二、理解匹配/分组算法
需要注意的是如果在URLconf中使用命名组,那么命名组和非命名组是不能同时存在于同一个 URLconf的模式中的。如果你这样做,Django不会抛出任何错误,但你可能会发现你的URL并没有像你预想的那样匹配正确。具体地,以下是 URLconf解释器有关正则表达式中命名组和非命名组所遵循的算法。
在以上的两种情况,Django同时会以关键字参数的方式传递一些额外参数。
传递额外的参数到视图函数中
有时你会发现你写的视图函数是十分类似的,只有一点点的不同。比如说,你有两个视图,它们的内容是一致的,除了它们所用的模板不太一样:
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^foo/$', views.foo_view),
(r'^bar/$', views.bar_view),
)
# views.py
from django.shortcuts import render_to_response
from mysite.models import MyModel
def foo_view(request):
m_list = MyModel.objects.filter(is_new=True)
return render_to_response('template1.html', {'m_list': m_list})
def bar_view(request):
m_list = MyModel.objects.filter(is_new=True)
return render_to_response('template2.html', {'m_list': m_list})
我们在这代码里面做了重复的工作,不够简练。起初你可能会想,通过对两个URL都试用同样的视图,在URL中使用括号捕捉请求,然后在视图中检查并决定使用哪个模板来去除代码的冗余,就像这样:
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^(foo)/$', views.foobar_view),
(r'^(bar)/$', views.foobar_view),
)
# views.py
from django.shortcuts import render_to_response
from mysite.models import MyModel
def foobar_view(request, url):
m_list = MyModel.objects.filter(is_new=True)
if url == 'foo':
template_name = 'template1.html'
elif url == 'bar':
template_name = 'template2.html'
return render_to_response(template_name, {'m_list': m_list})
这种解决方案的问题还是老缺点,就是把你的URL耦合进你的代码里面了。如果你打算把 /foo/ 改成 /fooey/ 的话,那么你就得记住要去改变视图里面的代码。
优雅的解决方法:使用一个额外的URLconf参数。一个URLconf里面的每一个模式可以包含第三个数据:一个传到视图函数中的关键字参数的字典。
有了这个概念以后,我们就可以把我们现在的例子改写成这样:
# 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})
如你所见,这个例子中,URLconf指定了 template_name 。而视图函数则会把它处理成另一个参数而已。
这额外的URLconf参数的技术以最少的麻烦给你提供了向视图函数传递额外信息的一个好方法。
1、伪造捕捉到的URLConf
如果有匹配某个模式的一推试图,以及一个并不匹配这个模式的但它的试图逻辑是一样的URL。这种情况下,可以伪造URL值的捕捉,
这主要通过使用额外URLConf参数,使得这个多出来的URL一样使用试图。
例如,你有可能有一个显示某一个特定日子的某些数据的应用,URL类似这样:
/mydata/jan/01/
/mydata/jan/02/
/mydata/jan/03/
# ...
/mydata/dec/30/
/mydata/dec/31/
太简单了,你可以再URLconf中捕捉这些值,使用组命名
urlpatterns = patterns('',
(r'^mydata/(?Pd{2})/(?Pd{2})/$',views.my_view),
)
然后试图看起来可能是这样
def my_view(request,month,day):
#...
这种简单方法很直接,没什么特别技术,问题如果你想添加一个使用my_view试图的URL但
它每包含一个Month和/或者Day。
比如你可能响增加一个这样的URL /mydata/birthday/. 这个URL等价于/mydata/jan/06,
这时候你可以使用额外参数来达到
urlpatterns = patterns('',
(r'^mydata/birthday/$',views.my_view,{'Month':'jan','Day':'06'}),
(r'^mydata/(?Pd{2})/(?Pd{2})/$',views.my_view),
)
在这里最帅的地方莫过于你根本不用改变你的视图函数。视图函数只会关心它 获得 了 month 和 day 参数,
它不会去管这些参数到底是捕捉回来的还是被额外提供的。
2.了解捕捉值和额外参数之间的优先级
额外参数优先级高于捕捉值参数
例如
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^mydata/(?P/d+)/$', views.my_view, {'id': 3}),
)
这里无论正则表达式匹配的Id值是多少,都会当做Id=3处理。
所以在开发过程中,一定注意避免出现上诉情况
3、短路逻辑
URLConf采用自上而下的匹配方式。
例如一个视图
urlpatterns = patterns('',
# ...
('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),
# ...
)
它将匹配像 /myblog/entries/add/ 和 /auth/groups/add/ 这样的URL,然而,对于用户对象的添加页面( /auth/user/add/ )是个特殊情况
我们可以在视图里判断一下而处理
视图:
def add_stage(request,app_moudle,moudle_name):
if app_moudle=='auth' and moudle_name=='user':
# 处理
else:
#处理
这种方法固然实现了我们的目的,但是他看上去很不优雅,我们应该将判断逻辑放到URLconf中,而不是视图中。
这里我们利用“短路逻辑”处理
urlpatterns = patterns('',
# ...
('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'),
('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),
# ...
)
4、包含其他URLconf
如果你试图让你的代码用在多个基于Django的站点上,你应该考虑将你的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作进一步处理。
继续看这个例子,这里就是被包含的URLconf mysite.blog.urls :
from django.conf.urls.defaults import *
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的第一行中被匹配到。
*
/weblog//2007/ :在第一个URLconf中,模式 r'^weblog/' 被匹配。因为它是一个 include() ,Django将截掉所有匹配的文本,在这里是 'weblog/' 。URL剩余的部分是 /2007/ (开头有一个斜杠),将不会匹配 mysite.blog.urls 中的任何URLconf。
*
/about/ : 这个匹配第一个URLconf中的 mysite.views.about 视图。只是为了示范你可以混合 include() patterns和 non-include() patterns在一起使用。
阅读(5655) | 评论(0) | 转发(0) |