zoukankan      html  css  js  c++  java
  • Django中URL的解析和反查

    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

  • 相关阅读:
    AC自动机
    KMP、扩展KMP、MANACHER
    Docker用户身份登录和管理员权限
    Response.Redirect和Server.Transfer比较--(转)
    SQLServer中char、varchar、nchar、nvarchar的区别--(转)
    MsSQL的字段类型--(转)
    读取UEditor编辑框内容到数据库和上传图片的配置
    以做产品的思想分析男女相处之道
    springBoot创建定时任务
    Runnable和Thread的区别
  • 原文地址:https://www.cnblogs.com/ajianbeyourself/p/5038233.html
Copyright © 2011-2022 走看看