Django-路由

Django2.0版本

这是一个示例URLconf:

from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

笔记:

  • 要从URL捕获值,请使用尖括号。
  • 捕获的值可以选择包括转换器类型。例如,用于 <int:name>捕获整数参数。如果未包含转换器/,则匹配字符之外的任何字符串
  • 没有必要添加前导斜杠,因为每个URL都有。例如,它articles不是/articles

示例请求:

  • 请求/articles/2005/03/与列表中的第三个条目匹配。Django会调用该函数 views.month_archive(request,year=2005, month=3)
  • /articles/2003/将匹配列表中的第一个模式,而不是第二个模式,因为模式是按顺序测试的,第一个是第一个要通过的测试。随意利用订单插入这样的特殊情况。在这里,Django会调用该函数 views.special_case_2003(request)
  • /articles/2003 不匹配任何这些模式,因为每个模式都要求URL以斜杠结尾。
  • /articles/2003/03/building-a-django-site/将匹配最终模式。Django会调用该函数 views.article_detail(request, year=2003, month=3, slug="building-a-django-site")

使用正则表达式

如果路径和转换器语法不足以定义URL模式,则还可以使用正则表达式。为此,请使用 re_path()而不是path()

在Python正则表达式中,命名正则表达式组的语法是(?P<name>pattern)name的名称,并且 pattern是要匹配的模式。

这是前面的示例URLconf,使用正则表达式重写:

from django.urls import path, re_path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[w-]+)/$', views.article_detail),
]

这完成了与前一个示例大致相同的事情,除了:

  • 匹配的确切网址稍微受限制。例如,年份10000将不再匹配,因为年份整数被限制为恰好四位数。
  • 无论正则表达式的匹配类型如何,每个捕获的参数都将作为字符串发送到视图。

从使用切换path()到 re_path()反之亦然,特别重要的是要注意视图参数的类型可能会发生变化,因此您可能需要调整视图。

使用未命名的正则表达式组

除了命名组语法之外,例如(?P<year>[0-9]{4}),您还可以使用较短的未命名组,例如([0-9]{4})

不特别推荐这种用法,因为它更容易在匹配的预期含义和视图的参数之间意外引入错误。

在任何一种情况下,建议在给定的正则表达式中仅使用一种样式。当两种样式混合使用时,将忽略任何未命名的组,并且只将命名组传递给视图函数。

反向解析

在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。

在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url 模板标签。
  • 在Python 代码中:使用from django.urls import reverse()函数
     

urls.py:

 
from django.conf.urls import url

from . import views

urlpatterns = [
    #...
    re_path(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]
 

在模板中:

 
<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中:

 
from django.urls import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))   # 同redirect("/path/")
 

当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment

名称空间

命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回
我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。

project的urls.py:

urlpatterns = [
    re_path(r'^admin/', admin.site.urls),
    re_path(r'^app01/', include("app01.urls",namespace="app01")),
    re_path(r'^app02/', include("app02.urls",namespace="app02")),
]

app01.urls:

urlpatterns = [
    re_path(r'^index/', index,name="index"),
]

app02.urls:

urlpatterns = [
    re_path(r'^index/', index,name="index"),
]

app01.views 

from django.core.urlresolvers import reverse

def index(request):

    return  HttpResponse(reverse("app01:index"))

app02.views

from django.core.urlresolvers import reverse

def index(request):

    return  HttpResponse(reverse("app02:index"))