为了给一个应用设计 URL,你需要创建一个 Python 模块,通常被称为 URLconf (URL configuration)。这个模块是纯粹的 Python 代码,包含 URL 模式(url patterns,简单的正则表达式)到 Python 函数(你的视图)的简单映射。

求的URL被看做是一个普通的Python 字符串, URLconf在其上查找并匹配。进行匹配时将不包括GET或POST请求方式的参数以及域名。
例如, https://www.example.com/myapp/ 请求中,URLconf 将查找 myapp/
https://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找 myapp/ 。
URLconf 不检查使用了哪种请求方法。换句话讲,所有的请求方法 —— 即,对同一个URL的无论是 POST请求 、 GET请求 、或 HEAD 请求方法等等 —— 都将路由到相同的函数。

路径相同,则调用的视图函数便相同。

当接收到一个URL以后,例如http://www.example.com/foo/bar/apple/2021/?key=value
对于主路由模块来说待匹配的是foo/bar/apple/2021/,主路由可能如下所示

  1. path('foo/', include('foo.urls'))

对于二级子路由来说待匹配的是bar/apple/2021/,子路由可能如下所示

  1. path('bar/apple/2021/', views.product_apple_2021)

对于协议,主机,查询参数等全部装到了HttpRequest实例中传入了视图函数。

1)定位ROOT_URLCONF的位置
2)加载ROOT_URLCONF模块,定位urlpatterns
3)顺序遍历url pattern,直到与HttpRequest.path_info匹配
4)调用该url pattern对应的视图函数(或者一个基于类的视图),并传入一个HttpRequest类型的参数(默认)和其他捕获的参数(可选)
5)若没有匹配成功或者出现其他错误,则调用错误视图

URL模式

/articles/2003/可以匹配如下urlpattern,然后Django会调用视图函数views.special_2003(request)

  1. path('articles/2003/', views.special_2003)

还可以使用尖括号来从URL的Path部分取值。
/articles/2021/可以匹配如下urlpattern,然后Django会调用视图函数views.year_archive(request, year=2021)

  1. path('articles/<year>/', views.year_archive)

捕获的值可以选择性地包含转换器类型。比如,使用 来捕获字符串类型的参数。
/articles/2021/bingo/可以匹配如下urlpattern,然后Django会调用视图函数views.name_archive(request, year=2021, name=bingo)

  1. path('articles/<int:year>/<str:name>/', views.name_archive)

模式要求 URL 以一个斜线结尾

路径转换器

str,匹配除了 / 以外的任意非空字符串,默认使用。
int,匹配0或者任意整数,返回一个int类型。
slug,匹配任意字母、数字、下划线和连字符,例如building-your-1st-django-site。
uuid,匹配一个格式化的UUID,例如075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配非空字段,包含 /。

自定义路径转换器

https://docs.djangoproject.com/zh-hans/3.2/topics/http/urls/#registering-custom-path-converters

使用正则表达式

使用re_path来替换path方法。
url模式的语法是:(?Ppattern)

  1. re_path(r'^articles/(?P<year>[0-9]{4})/$', views.blog_articles)

也可以使用下面这种未命名的方式,不过不推荐

  1. re_path(r'^articles/(?P[0-9]{4})/$', views.blog_articles)

正则表达式还支持嵌套参数的形式
https://docs.djangoproject.com/zh-hans/3.2/topics/http/urls/#nested-arguments

  1. re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments)

包含其他的URLConf

用法一

  1. from django.urls import include, path
  2. urlpatterns = [
  3. # ... snip ...
  4. path('community/', include('aggregator.urls')),
  5. path('contact/', include('contact.urls')),
  6. # ... snip ...
  7. ]

http://www.example.com/contact/foo/的请求中,会进入到contact子路由模块中
用法二

  1. from django.urls import include, path
  2. from apps.main import views as main_views
  3. from credit import views as credit_views
  4. extra_patterns = [
  5. path('reports/', credit_views.report),
  6. path('reports/<int:id>/', credit_views.report),
  7. path('charge/', credit_views.charge),
  8. ]
  9. urlpatterns = [
  10. path('', main_views.homepage),
  11. path('help/', include('apps.help.urls')),
  12. path('credit/', include(extra_patterns)),
  13. ]

http://www.example.com/credit/reports/2/的请求中,会调用credit_views.report(request, 1)视图函数。

在父路由中捕获的参数,可以传递到子路由中

  1. # urls/main.py
  2. urlpatterns = [
  3. path('<str:user>/blog/', include('foo.urls.blog'))
  4. ]
  5. # foo/urls/blog.py
  6. urlpatterns = [
  7. path('hisotry', views.blog.history)
  8. ]

http://www.example.com/tom/blog/history/的请求中,会调用views.blog.history(request, user=’tom’)视图函数

URL的反向解析

https://docs.djangoproject.com/zh-hans/3.2/topics/http/urls/#reverse-resolution-of-urls

在URLConf中命名URL pattern

  1. from django.urls import path
  2. from . import views
  3. urlpatterns = [
  4. #...
  5. path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
  6. #...
  7. ]

在模板中反向解析

  1. <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
  2. {# Or with the year in a template context variable: #}
  3. <ul>
  4. {% for yearvar in year_list %}
  5. <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
  6. {% endfor %}
  7. </ul>

在Python代码中反向解析

  1. from django.http import HttpResponseRedirect
  2. from django.urls import reverse
  3. def redirect_to_year(request):
  4. # ...
  5. year = 2006
  6. # ...
  7. return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

URL命名空间

https://docs.djangoproject.com/zh-hans/3.2/topics/http/urls/#naming-url-patterns