add by zhj:
如果想用reverse(namespace1:namespace2:...:namespaceN:name)反查url(注意:用reverse('polls:index')方法和{% url 'polls:index' %}获取到的是url中的path部分,要自己加上domain才是完整的url),那要做下面两点。
1. 该url路径上用到的所有url()方法中必须加name参数,如果url()方法中有include(),那不用加name参数。
name相当于文件,同一目录下的文件不能重名,即任何一个patterns(),它里面的各个url()的name参数不能相同。
2. 该url路径上用到的所有include()方法中必须namespace参数。
include相当于目录,同一父目录下的目录不能重名,即任何一个patterns(),它里面的各个url()中的include()的namespace不能重名
下面是正文
1. URL的解析
该部分来自http://blog.csdn.net/hackerain/article/details/40701099
from django.conf.urls import patterns, url, include urlpatterns = patterns('', url(r'^articles/2003/$', 'news.views.special_case_2003'), url(r'^articles/(d{4})/$', 'news.views.year_archive'), ) urlpatterns += patterns('', url(r'^articles/(?P<year>d{4})/(?P<month>d{2})/$', 'news.views.month_archive'), url(r'model/', include('model_test.urls')), )
这段代码就是一个URL Dispatcher的例子,它定义了URL和View之间的映射。在Django中的主配置文件中,用ROOT_URLCONF配置项来指定根URLconf,从根URLconf开始,逐条进行匹配,直到找到匹配项为止。
在上面例子中,我们可以看到有3个方法:patterns, url, include。url方法构建了一个URL到View方法的映射关系对象,patterns将这些映射关系对象组织成为一个python的列表,那include是做什么的呢?它就是我们上面说到的“树”结构关系的联系者,include会关联其他的URLconf到本URLconf,也就是说include关联的是孩子节点。整个URL dispatcher体系,就是由这三个方法构建起来的,下面我们重点来介绍这三个方法,了解了这三个方法,整个URL映射机制就会非常清楚了。
def url(regex, view, kwargs=None, name=None, prefix=''): pass def patterns(prefix, *args): pass def include(arg, namespace=None, app_name=None): pass
url()
先来看下最重要的url()方法。第一个参数regex是代表URL的正则表达式,第二个参数指定了和该正则表达式映射的View,此外,还可以通过kwargs参数,给view方法指定默认的kwargs参数,还有name参数,用来命名该URL,主要用在URL反解中,至于prefix用处不大,不解释。
url()方法最终构造了一个对象,我们姑且叫它URL映射对象,当第一次访问这个对象去匹配URL时,它会把这个对象中的正则表达式编译一次,然后保存在该对象中,所以以后再次匹配时,就会很快,不会重复编译该正则表达式了。在这里正则匹配其实就是用就是python的re模块,使用过程大致如下:
# 第一次访问时,编译,然后保存在url对象中 regex = re.compile(regex_str, re.UNICODE) # 每次URL访问时,进行正则匹配 match = regex.search(path) kwargs = match.groupdict() args = match.groups()
从URL中获取参数,其实是通过re模块中named groups和non-named groups的概念来获取的,通过match.groupdict()得到的是named groups,其实就是一个字典,字典的key是在URL中指定的,该字典会作为kwargs参数传递给view,而通过match.groups()得到的是non-named groups,是一个元组,即tuple,该元组会作为args参数传递给view。不过,这里的args和kwargs是不能够同时存在的,当有kwargs不为空时,args就会被置空,当kwargs为空时,args才会被用到,而传递给view的kwargs就只有url()方法中指定的默认kwargs。也就是说,如果你在URL中使用了named groups,那么non-named groups就会被忽略,如果只使用了non-named groups,它才会被作为args参数,传递给view方法。
解析一下我们上面提到的例子,假如我们有url和view:
urls:
url(r'^articles/(d{4})/$', 'news.views.year_archive') url(r'^articles/(?P<year>d{4})/(?P<month>d{2})/$', 'news.views.month_archive')
views:
def year_archive(request, *args, **kwargs): pass def month_archive(request, *args, **kwargs): pass
当我们访问”articles/2014/”这个路径的时候,解析的过程如下:
>>> import re >>> regex = re.compile(r'^articles/(d{4})/$', re.UNICODE) >>> match = regex.search("articles/2014/") >>> match.groupdict() {} >>> match.groups() ('2014',)
当我们访问”articles/2014/11”这个路径时,解析的过程如下:
>>> import re >>> regex = re.compile(r'^articles/(?P<year>d{4})/(?P<month>d{2})/$', re.UNICODE) >>> match = regex.search("articles/2014/11/") >>> match.groupdict() {'year': '2014', 'month': '11'} >>> match.groups() ('2014', '11')
所以最终传递给month_archive()方法中的参数应该是这样的:args=(),
kwargs =
{'month': u'11', 'year': u'2014'}
再罗嗦一句,因为url()可以指定一个kwargs参数,它是该url关联的view()方法的默认kwargs参数,也就是说如果在url()方法中指定了kwargs,那么会将这个参数的内容,也传递到view方法中的kwargs参数中。
好,至此,url()方法基本上就清楚了,第二个问题也解决了,至于name参数,到下面讲到URL反解的时候再详细解释。
patterns()
接下来,我们来看patterns()方法,这个其实比较简单,它就是返回一个由url()方法构造的URL映射对象组成的列表。它有一个必填参数是prefix,这个prefix是它所包含的view的公共前缀,这么做是为了避免代码重复,比如:
urlpatterns = patterns('', url(r'^articles/(d{4})/$', 'news.views.year_archive'), url(r'^articles/(d{4})/(d{2})/$', 'news.views.month_archive'), url(r'^articles/(d{4})/(d{2})/(d+)/$', 'news.views.article_detail'), )
可以写成:
urlpatterns = patterns('news.views', url(r'^articles/(d{4})/$', 'year_archive'), url(r'^articles/(d{4})/(d{2})/$', 'month_archive'), url(r'^articles/(d{4})/(d{2})/(d+)/$', 'article_detail'), )
注意,由patterns()生成的列表,被赋值给urlpatterns这个变量,这个变量是不能随便定义的,必须是约定好的,默认django会去URLconf中查找这个变量,也许你可以在某个地方设定一个参数,来换个约定,改变一下这个变量名。
include()
看上面的例子就可以了。
2. URL的反查
如果没有下面这种情况,即同一个urls.py模块被多个域名使用。那在写url时,只要注意两点就可以实现反查。
urlpatterns = patterns('', url(r'^author-polls/', include('polls.urls', namespace='author-polls', app_name='polls')), url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls', app_name='polls')), )
ok,那我们先不考虑上面这种情况,因为出现的概率很小,而且出现了再修改原有的url也可以,影响不大。
如果想对某个url进行反查,那要做两点(其实不是必须,但最好这样做,这样也便于对其它url进行反查,名称空间),
我们把include和name跟文件系统中的目录和文件做比较
1. 该url路径上用到的所有url()方法中必须加name参数,如果url()方法中有include(),那不用加name参数。
name相当于文件,同一目录下的文件不能重名,即任何一个patterns(),它里面的各个url()的name参数不能相同。
2. 该url路径上用到的所有include()方法中必须namespace参数。
include相当于目录,同一父目录下的目录不能重名,即任何一个patterns(),它里面的各个url()中的include()的namespace不能重名
当每个url都这样做时,就可以保证每个url在命名空间中可以唯一定位到。见下面例子
urls.py
from django.conf.urls import include, url, patterns urlpatterns = patterns('', url(r'^polls/', include('polls.urls', namespace='polls')), )
polls/urls.py
from django.conf.urls import url, patterns from . import views urlpatterns = patterns( url(r'^$', views.IndexView.as_view(), name='index')/, url(r'^(?P<pk>d+)/$', views.DetailView.as_view(), name='detail'), ... )
在python代码中,用下面的代码就能得到该url的path='/polls/index/',即相对于域名的路径。
include()方法是可以嵌套的,用类似reverse('polls:author_polls:index')可以得到路径
reverse('polls:index')
在模板中,用下面的代码获取
{% url 'polls:index' %}
参考:
http://blog.csdn.net/hackerain/article/details/40701099
http://python.usyiyi.cn/django/topics/http/urls.html