django-url调度器-高级篇

  咱们在中级篇中学会了如何进行反向解析,可是有这样一个问题,在为 url 命名的时候,名字不能重复,不然会致使各类各样的问题。在 url 还少的时候保证不重名仍是比较简单的,可是 url 多起来之后就比较难了。为了解决这样的问题,能够在 url 中加一个前缀。例如,我有一个 url 的名字叫作 'comment' ,此时,我能够为其加一个前缀,这个前缀一般是 app 名,例如:'myapp-comment'。html

  这也是django所推荐的命名方式,可是这样始终是治标不治本。此时,咱们就要学习 django 中 url 命名空间了。前端

URL 命名空间

  简介:python

  URL 命名空间容许你反查到惟一的命名 URL,即便在不一样的应用中使用相同的 URL 名称。(也就是能够在不一样的app中使用相同的名称,为有命名困难症的程序员带来了福音)nginx

  根据经验,第三方应用应该始终使用带命名空间的URL 相似地,它还容许你在一个应用有多个实例部署的状况下反查URL。换句话讲,由于一个应用的多个实例共享相同的命名URL,命名空间将提供一种区分这些命名 URL 的方法。程序员

  在一个站点上,正确使用 URL 命名空间的 Django 应用能够部署屡次。例如,django.contrib.admin 具备一个 AdminSite 类,它容许你很容易地部署多个管理站点的实例在下面的例子中,咱们将讨论在两个不一样的地方部署教程中的polls 应用,这样咱们能够为两种不一样的用户(做者和发布者)提供相同的功能。web

一个URL 命名空间有两个部分,它们都是字符串django

 应用命名空间
  它表示正在部署的应用的名称。一个应用的每一个实例具备相同的应用命名空间。例如,能够预见Django 的管理站点的应用命名空间是'admin'。
 实例命名空间
  它表示应用的一个特定的实例实例的命名空间在你的所有项目中应该是惟一的。可是,一个实例的命名空间能够和应用的命名空间相同。它用于表示一个应用的默认实例。例如,Django 管理站点实例具备一个默认的实例命名空间'admin'

  URL 的命名空间使用':' 操做符指定。例如,管理站点应用的主页使用'admin:index'它表示'admin' 的一个命名空间和'index' 的一个命名URL。并发

  命名空间也能够嵌套。命名URL'sports:polls:index' 将在命名空间'polls'中查找'index',而poll 定义在顶层的命名空间'sports' 中。app

 


 

反查带命名空间的URL

  咱们在中级篇中了解到了 url 反查带来的变量,而在中级篇中,都是使用 name 进行反查,这里来看看如何对带命名空间的 url 进行反查。函数

例子:

from django.conf.urls import include, url

urlpatterns = [
    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')),
]

 

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
    ...
]

 

 反查的方法和中级篇的同样,在模板中:

{% url 'polls:index' %}

 在基于类的视图的方法中:

reverse('polls:index', current_app=self.request.resolver_match.namespace)

  另外,注意,在模板中的反查须要添加 requestcurrent_app 属性,像这样:

def render_to_response(self, context, **response_kwargs):
    self.request.current_app = self.request.resolver_match.namespace
    return super(DetailView, self).render_to_response(context, **response_kwargs)

 

 这时,会有同窗有疑问了, polls 这个应用命名空间设置了两行呀,那 polls 下的 index 到底指的是哪一个?

 这个时候,就要看 django 的查找顺序了:

 1.若是当前有实例,也就是说咱们经过 url 访问到了某个处理函数,这个函数进行反向查询的时候,例如我访问的是:author-polls/ ,这个 url 对应的处理函数要进行反向解析,此时它要解析 'polls:detail'。那么将解析到 author-polls/(?P<pk>\d+)/$ 中,也就是有实例的优先在该实例空间中查询。

 2.若是没有实例,可是有默认的实例空间,例如 app_name='polls',namespace='polls' ,和应用空间同名,这样的就叫作默认实例空间。在没有访问实例的时候,就匹配到默认实例空间中。

 3.若是没有实例,也没有默认实例空间,那么谁是最后注册的就选谁,例子中的 namespace='publisher-polls' 就是最后一个注册的(也就是下面的)。

注意:

  由于实例空间要是惟一的,因此使用 namespace:name 的模式应该也是惟一匹配的,例如这里的'author-polls:index' 将永远解析到 'author-polls' 实例的主页('publisher-polls' 相似)

 

 


 

URL 命名空间和被包含的URLconf

  被包含的URLconf 的命名空间能够经过两种方式指定。

  首先,在你构造你的URL 模式时,你能够提供 应用实例的命名空间给 include() 做为参数。例如

url(r'^polls/', include('polls.urls', namespace='author-polls', app_name='polls')),

 

  这将包含 polls.urls 中定义的URL 到应用命名空间 'polls'中,其实例命名空间'author-polls'

  其次,你能够include 一个包含嵌套命名空间数据的对象。若是你include() 一个url() 实例的列表,那么该对象中包含的URL 将添加到全局命名空间。然而,你还能够include() 一个3个元素的元组:

 

(<list of url() instances>, <application namespace>, <instance namespace>)

 

  注意这里的应用命名空间和实例命名空间是相反的。

  实例:

from django.conf.urls import include, url

from . import views

polls_patterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
]

url(r'^polls/', include((polls_patterns, 'polls', 'author-polls'))),

 

  这样会包含命名的URL模式进入到给定的应用和实例命名空间中

 


 

与 url 相关的函数都在 django.conf.urls 中,下面看看里面都有哪些函数:

1. patterns(prefix, pattern_description, ...) 

  这是一个废弃了的方法,在 django1.8 以前,urlpatterns 变量是该函数的实例。

例如:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^articles/([0-9]{4})/$', 'news.views.year_archive'),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'news.views.month_archive'),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'news.views.article_detail'),
)

 

第一个参数是一个前缀,这里的全部表示处理函数的字符串都是以 'new.views' 开头的,全部能够改写成下面这种形式:

from django.conf.urls import patterns, url

urlpatterns = patterns('news.views',
    url(r'^articles/([0-9]{4})/$', 'year_archive'),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'month_archive'),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'article_detail'),
)

 

  由于 patterns 是python的一个方法,而 python 中,一个方法最多接受 255 个参数,也就是说最多能够在一个 patterns 中写 255-1 个 url,虽然这通常不会有什么影响,由于咱们能够经过 include 方法来分离 url,并且这个方法返回的是一个列表,因此能够经过列表拼接的方式,来扩展,例如:

urlpatterns = patterns('',
    ...
    )
urlpatterns += patterns('',
    ...
    )

 

  因此也只是如今最多一次性建立多少个 url 而已。

  可是这个方法仍是在 1.8 中废弃了(固然你还可强行用,到 1.9.4 为止代码并无被移除,之后的版本另算),之后直接使用 python 列表,列表中的元素是 url() 函数的实例就好了。而 python 的列表不限制长度,只看电脑的内存有没有足够的空间,因此也算是改进了。

 

2. static.static(prefix, view=django.views.static.serve, **kwargs) 

  若是你经过django的后台上传了一张图片,而你又想在前端显示它。通常而言 django 只提供了静态文件的支持(默认是 /static/ 开头的url请求都视为静态文件请求),而图片上传是经过 MEDIA_URL 来做为

请求的开头的,可是若是不作特殊设置,是没法显示的,此时,能够经过如下的方式:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

 

  这是老版本的写法,新版本中直接把函数放进列表中,做为列表中的一个元素就行

  注意:这里咱们并无为 view 传参,直接用默认的就行。

  固然,这也只是在开发环境中使用,若是到了正式生产环境,这些东西仍是老老实实用 web server ,例如Apache或者nginx之类的做为前方代理,django自带的 web 服务估计并发量在20左右就会挂掉,并且还不是守护进程,也就是说挂掉了不会重启,要多蛋疼有多蛋疼。

 

3. include(arg, namespace=None, app_name=None) 

  arg:能够接受一个字符串,表示被包含的模块在哪里;也能够接受一个列表,这个列表是被包含的 url() 的实例;还能够接受一个元祖,元祖的第一个元素是一个被包含的列表,第二个元素是该列表的应用空间名,第三个元素是实例空间名。

  namespace : 实例命名空间

  app_name : 应用命名空间

4. url(regex, view, kwargs=None, name=None, prefix='') 

   regex:要匹配的 url。

   view:该 url 的处理函数,能够是一个表示函数位置的字符串, 也能够是一个函数的实例。

   kwargs: 一个字典,表示传递多余的参数。

   name : 为 url 进行命名。

   prefix : if prefix: view = prefix + '.' + view  表示在 view 前加上前缀。

 

5.各类 handler:

  django 自带错误处理视图:

        handler400 = 'django.views.defaults.bad_request'
        handler403 = 'django.views.defaults.permission_denied'
        handler404 = 'django.views.defaults.page_not_found'
        handler500 = 'django.views.defaults.server_error'

  在触发相应的错误的时候,都会转向默认的处理函数,固然咱们也能够重写它们,只有在 urls.py 中导入它们,并改写成咱们本身的处理函数的字符串表示就能够了。

相关文章
相关标签/搜索