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>

  在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 中的内容。

时间: 2024-10-18 08:21:06

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

django-url调度器-高级篇

我们在中级篇中学会了如何进行反向解析,但是有这样一个问题,在为 url 命名的时候,名字不能重复,否则会导致各种各样的问题.在 url 还少的时候保证不重名还是比较简单的,但是 url 多起来以后就比较难了.为了解决这样的问题,可以在 url 中加一个前缀.例如,我有一个 url 的名字叫做 'comment' ,此时,我可以为其加一个前缀,这个前缀通常是 app 名,例如:'myapp-comment'. 这也是django所推荐的命名方式,但是这样始终是治标不治本.此时,我们就要学习 dja

django-url调度器-初级篇

Django 遵从 MVC 模型,并将其特色化为 MTV 模型.模型的核心是通过用户访问的 url 来指向处理的函数,而函数处理后返回相应的结果.所以url决定了用户访问的入口,另外表单处理的提交地址也需要指定的url.url是所有功能的入口,所以url的编写就变得非常重要. Django 的 url 编写涉及了 python 的 re 模块,也就是正则表达式,这部分内容需要提前掌握. 本篇的内容将结合官方的1.8.2的文档进行说明,如果有说明不清的地方可以相应参照官方的文档,我这里提供一个进行

django url调度

Django的url配置同样遵循着DRY(dont repeat yourself)的规则.以下都是官方文档的例子: 首先介绍的是Django如何处理http的请求: 1.在setting里定义ROOT_URLCONF ,这个值就是url的根配置,但若被request processing中间件定义了HttpRequest的urlconf属性,会替换掉ROOT_URLCONF 2.Django 加载模块,寻找 urlpatterns,它是pattern函数的返回值,是url的list 3.寻找每

白话Spring(中级篇)---拦截器(下)

[一知半解,就是给自己挖坑] 上文我们介绍了Spring中过滤器的基本用法,本文我们来介绍多个拦截器的执行情况,另外一种拦截器的实现方式,以及拦截器与java过滤器的区别.特别的,在本文中,我们将不在演示具体的拦截的实例,请读者们参照上文的实现以及配置方式自行实现. --------------------------------------------------------------------------------------------------------------------

FreeRTOS高级篇3---启动调度器

使用FreeRTOS,一个最基本的程序架构如下所示: int main(void) { 必要的初始化工作; 创建任务1; 创建任务2; ... vTaskStartScheduler(); /*启动调度器*/ while(1); } 任务创建完成后,静态变量指针pxCurrentTCB(见<FreeRTOS高级篇2---FreeRTOS任务创建分析>第7节内容)指向优先级最高的就绪任务.但此时任务并不能运行,因为接下来还有关键的一步:启动FreeRTOS调度器. 调度器是FreeRTOS操作系

Django Rest Framework url注册器组件 | 响应器组件 | 分页器组件

文章参考博主:https://www.cnblogs.com/li-li/p/10103918.html 1.url注册器组件 : 通过DRF的视图组件,数据接口逻辑被我们优化到最后剩下一个类,接下来,我们使用DRF的url控制器来帮助我们自动生成url '''3.使用url注册器组件的url''' #导入模块 from rest_framework import routers router = routers.DefaultRouter() # 3.将需要自动生成url的接口注册到route

零基础学习openstack【完整中级篇】及openstack资源汇总

1.你是如何学习openstack的?2.你对openstack的组件了解多少?3.你认为openstack该如何学习? 一直想写关于openstack的方面的内容,今天终于整理完成.算是完成一桩心事,内容整合来自: 零基础学习openstack(上)[中级篇] 零基础学习openstack(下)[中级篇] 是在 零基础学习openstack[初级篇]基础上的一个继续: 初级篇,我们主要是有这么一个概念,openstack的组成openstack由哪些部分来组成: Identity(代号为“Ke

Farseer.net轻量级开源框架 中级篇:Cookies、Session、Request

导航 目   录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 中级篇: 探究ORM(Mapping) 下一篇:Farseer.net轻量级开源框架 中级篇: UrlRewriter 地址重写 Cookies.Session.Request是专门针对WEB项目的额外支持. 顺便说下,今天有园友在群里问到ORM对MVC的支持.或者对WinForm支持吗?对于ORM来说,本身是对表现层没有任何的联系.它仅仅是让你在开发的时候,能以面向对象的思想(语法)去做

Django学习【第1篇】:Django之MTV模型

Django框架第一篇基础 一个小问题: 什么是根目录:就是没有路径,只有域名..url(r'^$') 补充一张关于wsgiref模块的图片 一.MTV模型 Django的MTV分别代表: Model(模型):和数据库相关的,负责业务对象与数据库的对象(ORM) Template(模板):放所有的html文件 模板语法:目的是将白变量(数据库的内容)如何巧妙的嵌入到html页面中 View(视图):负责业务逻辑,并在适当的时候调用Model和Template 此外,Django还有一个URL分发