django-url调度器-中级篇
在初级篇中,我们接触了:
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调度器-中级篇的更多相关文章
- Django URL调度器
Django处理请求的流程 Django确定要使用的根URLconf模块.通常,这是ROOT_URLCONF设置的值,但如果传入 HttpRequest对象具有urlconf 属性(由中间件设置),则 ...
- Django 源码小剖: 更高效的 URL 调度器(URL dispatcher)
效率问题 django 内部的 url 调度机制说白了就是给一张有关匹配信息的表, 这张表中有着 url -> action 的映射, 当请求到来的时候, 一个一个(遍历)去匹配. 中, 则调用 ...
- Django 源码小剖: URL 调度器(URL dispatcher)
在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 URL. 这是 django url 匹配处理机制的 ...
- URL 调度器(URL dispatcher)
URL 调度器(URL dispatcher) 在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 UR ...
- django-url调度器-高级篇
我们在中级篇中学会了如何进行反向解析,但是有这样一个问题,在为 url 命名的时候,名字不能重复,否则会导致各种各样的问题.在 url 还少的时候保证不重名还是比较简单的,但是 url 多起来以后就比 ...
- django url注册器组件, 响应器组件, 分页器组件
一.url注册器的使用 1.1导入模块 from django.urls import re_path, include from .serializer import views from rest ...
- django-url调度器-初级篇
Django 遵从 MVC 模型,并将其特色化为 MTV 模型.模型的核心是通过用户访问的 url 来指向处理的函数,而函数处理后返回相应的结果.所以url决定了用户访问的入口,另外表单处理的提交地址 ...
- Django url分发器
视图: 视图一般都写在app的views.py中.并且视图的第一个参数永远都是request(一个HttpRequest)对象.这个对象存储了请求过来的所有信息,包括携带的参数以及一些头部信息等.在视 ...
- django url调度
Django的url配置相同遵循着DRY(dont repeat yourself)的规则.下面都是官方文档的样例: 首先介绍的是Django怎样处理http的请求: 1.在setting里定义ROO ...
随机推荐
- git小操作之checkout、stash
git checkout会带上当前changed但没有commit的内容到目标分支 git stash用来暂存当前改动,并且会退代码到上一个commit:git stash pop则取出所stash的 ...
- MySQL数据库优化技术之数据库表的设计
三范式介绍表的范式:只有符合的第一范式,才能满足第二范式,进一步才能满足第三范式. 1. 第一范式:表的列具有原子性,不可再分解.只要是关系型数据库都自动满足第一范式.数据库的分类:关系型数据库:My ...
- HDU 4786 Fibonacci Tree
Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) P ...
- cocos2d 3.0自定义事件答疑解惑
疑惑一:在事件分发中修改订阅者 ,对于这个的理解. 事件的分发是可以嵌套的,cocos2dx使用_inDispatch来保存当前嵌套的深度,当调用第一个dispatchEvent的时候,_inDisp ...
- 一步一步学习Unity3d学习笔记系1.1
最近开始在学习Unity3D,在网上找到了一些教程利用晚上回家休息的时间自学了一下,我就是一个小白,对Unity3D什么都不懂,可能需要一些美工的功底.刚好有点,需要点编程的基础,也好我也有点,对C# ...
- 翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述
本文系对「C++ Rvalue References Explained」 该文的翻译,原文作者:Thomas Becker. 该文较详细的解释了C++11右值引用的作用和出现的意义,也同时被Scot ...
- sqlserver 常用sql语句
SELECT COUNT(*) FROM WeixinUser SELECT COUNT(*) FROM WeixinUser WHERE datediff(day, CreateTime,getda ...
- memcached搭建缓存系统
Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能. 二.适用场合 1.分布式应用.由于memca ...
- Linux操作系统下三种配置环境变量的方法——转载
来源:赛迪网 作者:millio 现在使用linux的朋友越来越多了,在linux下做开发首先就是需要配置环境变量,下面以配置java环境变量为例介绍三种配置环境变量的方法. 1.修改/e ...
- size_t 与 int 区别
size_t是无符号的,并且是平台无关的,表示0-MAXINT的范围, 但是如果传入的是负数,会被编译成他的补码. size_t是标准规定的一个同义词,它的原始定义放在stddef.h里面,不同的环境 ...