在初级篇中,我们接触了:

  1.url 的简单编写

  2.两种传参的方式

  3.捕获的参数总是字符串

  4.为视图设置默认参数

  ……

  在中级篇中将更进一步。

包含其它的URLconfs

  当网站非常大的时候,将所有的url都写在一个url模块中会非常的臃肿,且后期不便于维护。此时,就可以使用包含的方式将部分的url放在另一个url模块中。最常见的就是每个app的url都进行分离。

官方代码示例:

from django.conf.urls import include, url
urlpatterns = [
# ... snip ...
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
# ... snip ...]

  注意,这个例子中的正则表达式没有包含$(字符串结束匹配符),但是包含一个末尾的斜杠。每当 Django 遇到 include()(django.conf.urls.include())时,它会去掉 URL 中匹配的部分并将剩下的字符串发送给包含的 URLconf 做进一步处理

  另外一种包含其它URL 模式的方式是使用一个url() 实例的列表。例如,请看下面的URLconf:

from django.conf.urls import include, url
from apps.main import views as main_viewsfrom credit import views as credit_views
extra_patterns = [
url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', credit_views.charge),
]
urlpatterns = [
url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')),
url(r'^credit/', include(extra_patterns)),
]

  在这个例子中,/credit/reports/ URL 将被 credit.views.report() 这个Django 视图处理。

  这种方法可以用来去除 URLconf 中的冗余,其中某个模式前缀被重复使用。例如,考虑这个 URLconf:

from django.conf.urls import urlfrom . import views
urlpatterns = [
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions),
]

  我们可以改进它,通过只声明共同的路径前缀一次并将后面的部分分组:

from django.conf.urls import include, urlfrom . import views
urlpatterns = [
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
url(r'^history/$', views.history),
url(r'^edit/$', views.edit),
url(r'^discuss/$', views.discuss),
url(r'^permissions/$', views.permissions),
])),
]

  下面,我们总结一下使用 include 能达到什么效果:

  1.分离 url ,例如将 app 相关的 url 都移到对应的 app 目录下,这样逻辑更清晰,也更易维护。

  2.去除 url 中的冗余。

  当然,还有更高级的用法,例如:命名空间,反向解析等。这些等到高级篇再进行讨论。


包含之后的参数传递

  包含的 URLconf 会收到来自父URLconf 捕获的任何参数(也就是说捕获到的参数是向下传递的),所以下面的例子是合法的:

# In settings/urls/main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
] # In foo/urls/blog.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.blog.index),
url(r'^archive/$', views.blog.archive),
]

  在上面的例子中,捕获的 "username" 变量将被如期传递给 include() 指向的 URLconf。


嵌套的参数

  正则表达式允许嵌套参数,Django 将解析它们并传递给视图。当反查时,Django 将尝试填满所有外围捕获的参数,并忽略嵌套捕获的参数。

  例如下面的 URL 模式,它带有一个可选的 page 参数:

from django.conf.urls import url
urlpatterns = [
url(r'blog/(page-(\d+)/)?$', blog_articles), # bad
url(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
]

  两个模式都使用嵌套的参数,其解析方式是:例如 blog/page-2/ 将匹配 blog_articles 并带有两个位置参数 page-2/ 和 2。(也就是凡是分组都会传递参数,顺序由内层到外层)

  而在正在表达式中 (?:....)虽然类似一个分组,但并不是分组。

  所以,第二个 comments 的模式将匹配 comments/page-2/ 并带有一个值为 2 的关键字参数 page_number。这个例子中外围参数是一个不捕获的参数(?:...)。

  blog_articles 视图需要最外层捕获的参数来反查,在这个例子中是 page-2/ 或者没有参数,而 comments 可以不带参数或者用一个 page_number 值来反查。

  嵌套捕获的参数使得视图参数和URL 之间存在强耦合,正如 blog_articles 所示:视图接收URL(page-2/)的一部分,而不只是视图所要的值(通常我只需要知道一个页码,也就是这里的 2 就行了)。这种耦合在反查时更加显著,因为反查视图时我们需要传递 URL 的一个片段而不只是 page 的值。

  总结:尽量不要捕获不需要的参数,因为这样不仅在函数中需要额外的处理,而且在进行各种反向查询的时候也会困难些。


传递额外的选项给视图函数

  URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。

  django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

例如:

from django.conf.urls import urlfrom . import views
urlpatterns = [
  url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

  在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。

  但是这样会出现一定的冲突,当 URL 模式捕获的命名关键字参数和在字典中传递的额外参数具有相同的名称时,将使用字典中的参数而不是URL 中捕获的参数。(也就是说字典中的参数优先级更高。


传递额外的选项给include

  类似地,你可以传递额外的选项给include()。当你传递额外的选项给include() 时,被包含的URLconf 的每一行将被传递这些额外的选项。

  也就是说在 include 中传递的额外参数将传给所有被包含的 url

设置一:
# main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^blog/', include('inner'), {'blogid': 3}),
]
# inner.pyfrom django.conf.urls import urlfrom mysite import views
urlpatterns = [
url(r'^archive/$', views.archive),
url(r'^about/$', views.about),
] 设置二:
# main.py
from django.conf.urls import include, urlfrom mysite import views
urlpatterns = [
url(r'^blog/', include('inner')),
]
# inner.pyfrom django.conf.urls import url
urlpatterns = [
url(r'^archive/$', views.archive, {'blogid': 3}),
url(r'^about/$', views.about, {'blogid': 3})
,]

  但是,如果你不确定你的所有的相关视图函数都需要这个额外的参数的话,将会导致参数传递错误,例如多传了参数。而发生这种情况时,毫无疑问会发生报错。所以在使用这个功能的时候要足够的谨慎。你要知道你做了什么。


URL 的反向解析

  反向解析是做什么的?反向解析,就是在模板中,或 views 函数中进行 url 的获取或者重定向到指定页面的时候,可以更加灵活的写入目标 url 而不用硬编码。

  例如,在没有使用反向解析之前:

<a href="/xxx/xxx/">测试</a>        #模板中

def xxx(request):        #视图函数需要重定向时
.....
return HttpResponseRedirect('/xxx/xxx/')

  如果此时处于业务需要,想要改动 url 时,那么代码中所以用到的地方就都需要改。如果此时用的这个 url 的地方有 N 个,就意味着要改动 N 次。此时,你可能想死的心都有了。为了延长程序员的寿命,反向解析就显得非常重要了。

  Django 通过为指定的url命名的方式,来代替硬编码,而为了解决命名重复的问题,又引入了命名空间,下面逐一介绍。

例子:  

from django.conf.urls import url
from . import views
urlpatterns = [
#...
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
#...]

  在这里,添加了 name 这个属性,并将其赋值为'news-year-archive'。这就是为这个 url 进行了命名。

  在进行命名了以后,就可以这样写:

<a href="{% url ‘new-year-archive’}>测试</a>        #模板中

from django.core.urlresolvers import reverse
def xxx(request): #视图函数
......
return HttpResponseRedirect(reverse('news-year-archive',))

  这里的reverse()函数的作用是进行反向解析,以直接访问其他视图函数。

  下面来分析一下这个函数要怎么用:

reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)

  这里接收 5 个参数,下面来看看这些参数都是做什么的:

  viewname:是一个字符串,可以是一个Python路径视图对象(废弃),一个URL模式名称( reverse('news_archive') ),或可调用视图对象( from news import views /reverse(views.archive) )。

  urlconf : reverse 在其内部是这样处理的: if urlconf is None: urlconf = get_urlconf() ,那我们去看看get_urlconf()是做什么的。这时,我们看到这样的一句说明:

def get_urlconf(default=None):
"""
Returns the root URLconf to use for the current thread if it has been
changed from the default one.
"""
return getattr(_urlconfs, "value", default)

  返回根 url 模块的。

  也就是说这个属性决定此次反向解析使用哪个 url 模块。默认是当前的根 url 模块

  args : 用于传参,也就是说方向解析到指定的 view 函数后,并传递了参数,可以是元组或列表,表示按照顺序进行位置传参。

  kwargs:也是用于传参的,不同的是,这里是一个字典,传参时使用关键字传参的方式。

  current_app :参数允许您提供一个提示解析器指示应用程序当前执行的视图所属(所在app)。这个current_app参数作为一个提示,根据名称空间URL解决策略,来解决应用程序名称空间URL在特定的应用程序实例。

  注意:

    若没有找到匹配的对象,则抛出 NoReverseMatch 异常。

    一般而言几乎所有的正则都能逆向解析,但是目前并不能匹配含有选择符(|)的正则。除此之外几乎可以很轻松得逆向解析,但这种逆向解析是不可逆的。

    反向解析Python路径的能力,如反向(“news.views.archive”),已被弃用。(在1.8中)

官方手册例子:

from django.conf.urls import url
from . import views urlpatterns = [
#...
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
#...
]

  根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/

  你可以在模板的代码中使用下面的方法获得它们:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

   传递多个参数时用空格隔开: 

{% url 'add' 123 321  %}
{% url 'add' num1=123 num2=321 %}

  在Python 代码中,这样使用:

rom django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect def redirect_to_year(request):
# ...
year = 2006
# ...
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

  如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

django-url调度器-中级篇的更多相关文章

  1. Django URL调度器

    Django处理请求的流程 Django确定要使用的根URLconf模块.通常,这是ROOT_URLCONF设置的值,但如果传入 HttpRequest对象具有urlconf 属性(由中间件设置),则 ...

  2. Django 源码小剖: 更高效的 URL 调度器(URL dispatcher)

    效率问题 django 内部的 url 调度机制说白了就是给一张有关匹配信息的表, 这张表中有着 url -> action 的映射, 当请求到来的时候, 一个一个(遍历)去匹配. 中, 则调用 ...

  3. Django 源码小剖: URL 调度器(URL dispatcher)

    在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 URL. 这是 django url 匹配处理机制的 ...

  4. URL 调度器(URL dispatcher)

    URL 调度器(URL dispatcher) 在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 UR ...

  5. django-url调度器-高级篇

    我们在中级篇中学会了如何进行反向解析,但是有这样一个问题,在为 url 命名的时候,名字不能重复,否则会导致各种各样的问题.在 url 还少的时候保证不重名还是比较简单的,但是 url 多起来以后就比 ...

  6. django url注册器组件, 响应器组件, 分页器组件

    一.url注册器的使用 1.1导入模块 from django.urls import re_path, include from .serializer import views from rest ...

  7. django-url调度器-初级篇

    Django 遵从 MVC 模型,并将其特色化为 MTV 模型.模型的核心是通过用户访问的 url 来指向处理的函数,而函数处理后返回相应的结果.所以url决定了用户访问的入口,另外表单处理的提交地址 ...

  8. Django url分发器

    视图: 视图一般都写在app的views.py中.并且视图的第一个参数永远都是request(一个HttpRequest)对象.这个对象存储了请求过来的所有信息,包括携带的参数以及一些头部信息等.在视 ...

  9. django url调度

    Django的url配置相同遵循着DRY(dont repeat yourself)的规则.下面都是官方文档的样例: 首先介绍的是Django怎样处理http的请求: 1.在setting里定义ROO ...

随机推荐

  1. [转]iOS技巧之获取本机通讯录中的内容,解析通讯录源代码

    一.在工程中添加AddressBook.framework和AddressBookUI.framework 二.获取通讯录 1.在infterface中定义数组并在init方法中初始化 ? 1 2 3 ...

  2. css3实现小米商城鼠标移动图片上浮阴影效果

    今天在编程爱好者编码库看见一个好玩的程序,代码如下. <!DOCTYPE html> <html> <head>     <meta charset=&quo ...

  3. Python安装Selenium3

    概述 2016.10.13,Selenium3.0正式发布,官方说明如下: The major change in Selenium 3.0 is we're removing the origina ...

  4. socket学习笔记——select与epoll函数的使用(linux)

    select.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <u ...

  5. SQL where 1=1的作用

    浅谈where 1=1 1.简单理解的话where 1=1 永真, where 1<>1 永假 2.1<>1 的用处:     用于只取结构不取数据的场合     例如:    ...

  6. Visual Studio 2010 C++ 工程文件解读

    在 VS2010 中,C++ 的工程文件已经和 2005 / 2008 有了很大的不同,而是完全采用 MSBUILD 的属性方式进行表达,并且可以让用户通过一次性的配置而对所有的属性进行自定义: 根据 ...

  7. centos系统自动化安装研究

    https://rhinstaller.github.io/anaconda/intro.html https://github.com/rhinstaller/pykickstart/blob/ma ...

  8. centreon 降低rrd磁盘读写

    参考 https://documentation.centreon.com/docs/centreon/en/2.7.x/faq/performance.html 修改rrdcached配置 vim ...

  9. JSON时间转换格式化

    通常JSON时间一般是这样的格式. 1 /Date(1436595149269)/ 通常我们用AJAX获取下来的JSON数据,如果有时间,都是这种格式的.其中,中间的一段数字"1436595 ...

  10. css透明属性

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...