Django之路由系统

        Django之路由系统         

Django2.2版本 URLConf官方文档

 

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。也就是以这种方式告诉Django,对于指定的URL调用指定的代码函数。

      URLConf配置      

Django如何处理一个请求?

当用户从你的django驱动的站点请求一个页面时,系统按照以下算法来确定需要执行的Python代码函数:

  1. Django确定要使用的根URLconf模块。通常,这是ROOT_URLCONF设置的值,但是如果传入的HttpRequest对象具有urlconf属性(由中间件设置),则将使用它的值来代替ROOT_URLCONF设置。
  2. Django加载Python模块并查找变量urlpatterns。这是一个django.url .path()和/或django.url .re_path()实例的序列。
  3. Django按顺序遍历每个URL模式,并在第一个匹配请求的URL的模式处停止。
  4. 一旦其中一个URL模式匹配,Django就会导入并调用给定的视图,该视图是一个简单的Python函数(或基于类的视图)。视图通过以下参数传递:
  • HttpRequest的一个实例。
  • 如果匹配的URL模式没有返回指定的组,那么正则表达式中的匹配将作为位置参数提供。
  • 关键字参数由路径表达式匹配的任何命名部分组成,由可选的kwargs参数(django.url .path()或django.url .re_path()中指定的任何参数覆盖。

5. 如果没有匹配的URL模式,或者在此过程的任何时间点引发异常,Django将调用适当的错误处理视图。参见下面的错误处理。

一个简单的例子:

 

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),
]

 

注意:1.匹配除/字符之外的任何字符串。2.不需要添加前导斜杠,因为每个URL都有。例如,它是articles,而不是/articles。

下列路径转换器在预设情况下是可用的:               

str—匹配任何非空字符串,不包括路径分隔符'/'。如果表达式中没有包含转换器,这是默认的。
int—匹配0或任何正整数。返回一个int。
slug-匹配任何由ASCII字符或数字,加上连字符和下划线字符组成的slug字符串。例如,building-your-1st-django-site。
uuid -匹配格式化的uuid。为了防止多个url映射到同一个页面,必须包含破折号和小写字母。例如,075194 d3 - 6885 - 417 - e - a8a8 c931e272f00——6。返回一个UUID实例。
path—匹配任何非空字符串,包括路径分隔符'/'。这允许您匹配一个完整的URL路径,而不是像str那样只匹配URL路径的一部分。
可用的路径转换器

       使用正则表达式     

   如果路径和转换器语法不足以定义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),
]
正则重写URLConf

这实现了与前一个例子大致相同的事情,除了:

  • 将匹配的确切url稍微受到一些限制。例如,10000年将不再匹配,因为年份整数被限制为正好四位数字长。
  • 每个捕获的参数都以字符串的形式发送到视图,而不管正则表达式匹配什么类型

在从使用path()切换到re_path()或从使用re_path()切换到使用path()时,注意视图参数的类型可能会改变,因此可能需要调整视图。

当命名正则和非命名正则两种样式混合时,任何未命名的组都被忽略,只有命名的组被传递给视图函数

注意:

# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True

Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。

      其他URLconfs      

在任何时候,您的urlpatterns都可以“包括”其他URLconf模块。这本质上是一组位于其他url之下的“根”。例如,下面是Django网站本身的URLconf的摘录。它包括一些其他的URLconfs:

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path('community/', include('aggregator.urls')),
    path('contact/', include('contact.urls')),
    # ... snip ...
]

通过使用path()实例列表来包含额外的URL模式。例如,考虑这个URLconf:

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path('reports/', credit_views.report),
    path('reports/<int:id>/', credit_views.report),
    path('charge/', credit_views.charge),
]

urlpatterns = [
    path('', main_views.homepage),
    path('help/', include('apps.help.urls')),
    path('credit/', include(extra_patterns)),
]

在本例中,/credit/reports/ URL将由credit_views.report()  Django视图处理。这可以用于从重复使用单个模式前缀的URLconfs中删除冗余。例如,考虑这个URLconf:

from django.urls import path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/history/', views.history),
    path('<page_slug>-<page_id>/edit/', views.edit),
    path('<page_slug>-<page_id>/discuss/', views.discuss),
    path('<page_slug>-<page_id>/permissions/', views.permissions),
]

 可以通过只声明一次公共路径前缀并对不同的后缀进行分组来改进:

from django.urls import include, path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/', include([
        path('history/', views.history),
        path('edit/', views.edit),
        path('discuss/', views.discuss),
        path('permissions/', views.permissions),
    ])),
]
公共路径前缀+不同后缀进行分组

包含的URLconf从父URLconfs接收任何捕获的参数:

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path('<username>/blog/', include('foo.urls.blog')),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog.index),
    path('archive/', views.blog.archive),
]
父URLConfs接受不同的参数

在上面的例子中,捕获的“username”变量按照预期传递到包含的URLconf。

   命名URL和URL反向解析   

Django提供了执行URL反转的工具,以匹配需要URL的不同层:

  1. 在模板中:使用url模板标记。
  2. 在Python代码中:使用reverse()函数。
  3. 在与处理Django模型实例的url相关的高级代码中:get_absolute_url()方法。

再次考虑URLconf条目:

from django.urls import path

from . import views

urlpatterns = [
    #...
    path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
    #...
]
urls.py中命名,以便后续进行反向解析

与年份nnnn对应的归档URL为/articles//。你可以在模板代码中使用:

<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>
HTML中的引入形式

或者在python中的代码:

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

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

注意:在一些视图具有一般性质的场景中,url和视图之间可能存在多对一关系。在这些情况下,视图名在反转url时不是一个足够好的标识符。

    命名的URL模式    

为了执行URL反转,需要使用上面示例中所使用的命名URL模式。用于URL名称的字符串可以包含自己喜欢的任何字符。不受限于有效的Python名称。在命名URL模式时,选择不太可能与其他应用程序的名称选择冲突的名称。如果你调用你的URL模式注释,而另一个应用程序执行相同的操作,那么reverse()找到的URL取决于您的项目的urlpatterns列表中的最后一个模式。在URL名称上加上前缀(可能来自应用程序名称(比如myapp-comment而不是comment))可以减少冲突的几率。如果要覆盖视图,可以故意选择与另一个应用程序相同的URL名称。例如,一个常见的用例是覆盖LoginView。Django的某些部分和大多数第三方应用程序都假设这个视图有一个名为login的URL模式。如果您有一个自定义登录视图,并将其URL命名为login, reverse()将找到您的自定义视图,只要它是在django.contrib.auth之后的urlpatterns中。包括url(如果有的话)。如果多个URL模式的参数不同,也可以使用相同的名称。除了URL名称之外,reverse()还匹配参数的数量和关键字参数的名称

URL命名空间

URL名称空间允许您唯一地反向命名URL模式,即使不同的应用程序使用相同的URL名称。

举个例子:

project中的urls.py

from django.conf.urls import url, include
 
urlpatterns = [
    path('app01/', include('app01.urls', namespace='app01')),
    path('app02/', include('app02.urls', namespace='app02')),
]
Project中的urls.py
from django.conf.urls import url
from app01 import views
 
app_name = 'app01'
urlpatterns = [
    path('(?P<pk>\d+)/$', views.detail, name='detail')
]
app01中的urls.py
from django.conf.urls import url
from app02 import views
 
app_name = 'app02'
urlpatterns = [
    path('^(?P<pk>\d+)/$', views.detail, name='detail')
]
app02中的urls.py

现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

语法:

'命名空间名称:URL名称'

模板中使用:

{% url 'app01:detail' pk=12 pp=99 %}

views中的函数中使用

v = reverse('app01:detail', kwargs={'pk':11})

 这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

 

posted on 2020-03-22 13:32  眨眼星舟_Eric  阅读(122)  评论(0编辑  收藏  举报

导航